view release on metacpan or search on metacpan
Preamble
The license agreements of most software companies try to keep users
at the mercy of those companies. By contrast, our General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. The
General Public License applies to the Free Software Foundation's
software and to any other program whose authors commit to using it.
You can use it for your programs, too.
When we speak of free software, we are referring to freedom, not
price. Specifically, the General Public License is designed to make
sure that you have the freedom to give away or sell copies of free
software, that you receive source code or can get it if you want it,
that you can change the software or use pieces of it in new free
programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
Program or a portion of it, either verbatim or with modifications. Each
licensee is addressed as "you".
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this
General Public License and to the absence of any warranty; and give any
other recipients of the Program a copy of this General Public License
along with the Program. You may charge a fee for the physical act of
transferring a copy.
2. You may modify your copy or copies of the Program or any portion of
it, and copy and distribute such modifications under the terms of Paragraph
1 above, provided that you also do the following:
a) cause the modified files to carry prominent notices stating that
you changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish, that
in whole or in part contains the Program or any part thereof, either
c) If the modified program normally reads commands interactively when
run, you must cause it, when started running for such interactive use
in the simplest and most usual way, to print or display an
announcement including an appropriate copyright notice and a notice
that there is no warranty (or else, saying that you provide a
warranty) and that users may redistribute the program under these
conditions, and telling the user how to view a copy of this General
Public License.
d) You may charge a fee for the physical act of transferring a
copy, and you may at your option offer warranty protection in
exchange for a fee.
Mere aggregation of another independent work with the Program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other work under the scope of these terms.
3. You may copy and distribute the Program (or a portion or derivative of
it, under Paragraph 2) in object code or executable form under the terms of
Paragraphs 1 and 2 above provided that you also do one of the following:
years, to give any third party free (except for a nominal charge
for the cost of distribution) a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of
Paragraphs 1 and 2 above; or,
c) accompany it with the information you received as to where the
corresponding source code may be obtained. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form alone.)
Source code for a work means the preferred form of the work for making
modifications to it. For an executable file, complete source code means
all the source code for all modules it contains; but, as a special
exception, it need not include source code for modules which are standard
libraries that accompany the operating system on which the executable
file runs, or for standard header files or definitions files that
accompany that operating system.
4. You may not copy, modify, sublicense, distribute or transfer the
Program except as expressly provided under this General Public License.
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_ view on Meta::CPAN
<p>What if I have a hook to log exceptions to a special log file, like so:</p>
<pre><code>#!/usr/bin/env perl
use Mojolicious::Lite;
# Log exceptions to a separate log file
hook after_dispatch => sub {
my ( $c ) = @_;
return unless my $e = $c->stash( 'exception' );
state $path = $c->app->home->child("exception.log");
state $log = Mojo::Log->new( path => $path );
$log->error( $e );
};
app->start;
</code></pre>
<p>To test this, once I've loaded my app and created a Test::Mojo object,
I'm free to add more configuration to my app, including new routes!
These routes can set up exactly the right conditions for my test.</p>
<pre><code># test.pl
use Test::More;
devdata/https_mojolicious.io_blog_2018_12_04_testing-hooks-and-helpers_ view on Meta::CPAN
return undef unless $auth;
my ( $token ) = $auth =~ /^Token\ (\S+)$/;
return undef unless $token;
return $c->app->config->{tokens}{ $token };
};
</code></pre>
<p>Then, rather than generating web requests to check all our
authentication edge cases, I can build a controller and set the right
headers to run my tests (using <a href="https://mojolicious.org/perldoc/Test/Mojo#new">Test::Mojo configuration
overrides</a> to add a test
token):</p>
<pre><code># test.pl
use Test::More;
use Test::Mojo;
use Mojo::File qw( path );
my $token = 'mytoken';
my $t = Test::Mojo->new( path('myapp.pl'), {
# Add a token as a configuration override
tokens => { $token => 'preaction' },
} );
my $c = $t->app->build_controller;
is $c->current_user, undef, 'current_user not set';
$c->req->headers->authorization( 'NOTATOKEN' );
is $c->current_user, undef, 'current_user without "Token"';
$c->req->headers->authorization( 'Token NOTFOUND' );
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_ view on Meta::CPAN
use warnings;
use open qw(:std :utf8);
use charnames qw();
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
my $url = 'https://blog.emojipedia.org/new-unicode-9-emojis/';
my $tx = $ua->get( $url );
die "That didn't work!\n" if $tx->error;
say $tx->result
->dom
->find( 'ul:not( [class] ) li a' )
->map( 'text' )
->map( sub {
my $c = substr $_, 0, 1;
[ $c, ord($c), charnames::viacode( ord($c) ) ]
})
->sort( sub { $a->[1] <=> $b->[1] } )
devdata/https_mojolicious.io_blog_2018_12_05_compound-selectors_ view on Meta::CPAN
<p><em style="font-size: 10px">
Editor's note: Unfortunately this example breaks our syntax highlighter. This is the site's fault not the author. We're trying to find a better way to render it short of rewriting the rendering engine.
</em></p>
<h2>Conclusion</h2>
<p>Even for an old programmer like me, dealing with HTML through CSS Selectors applied by Mojolicious is much easier than what I was doing before (which was dirty and much easier than doing it correctly). With a little skill creating compound selecto...
</section>
<small><p><a class="external text" href="https://www.flickr.com/photos/feuilllu/101083313/in/photolist-9W5xK-SWEcv6-qmMqBb-9W66e-umaBj-7Gkg2a-bnmWDf-jZPHK7-bAgNFi-bnmW3J-Hd8y3-dYNuYc-Hd9o9-22MW7qW-6qZWkL-7yzScF-24W5o6o-bBNUMi-5QPxcD-boz...
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/promises/">promises</a>,
<a href="/blog/tag/advent/">advent</a>
</p>
<div class="bio cf">
devdata/https_mojolicious.io_blog_2018_12_07_openapi_ view on Meta::CPAN
- name: collapsed
in: query
description: |
Force a collapsed even when searching for a particular
distribution or module name.
type: boolean
</code></pre>
<h4>Defining the Response</h4>
<p>The OpenAPI specification allows you to define each response to a method call, this includes both specific and generic error handling. Definitions are defined per HTTP status code.</p>
<pre><code>responses:
# HTTP 200 response
200:
description: Search response
# The schema defines what the result will look like
schema:
type: object
properties:
total:
devdata/https_mojolicious.io_blog_2018_12_10_minion-stands-alone_ view on Meta::CPAN
};
app->minion->add_task(
check_url => sub( $job, $url ) {
my $start = time;
my $tx = $job->app->ua->head( $url );
my $elapsed = time - $start;
$job->app->log->info(
sprintf 'Fetching %s took %.3f seconds', $url, $elapsed
);
# If there's an error loading the web page, fail the job
if ( $tx->error ) {
$job->app->log->error(
sprintf 'Error loading URL (%s): %s (%s)',
$url, @{ $tx->error }{qw( code message )},
);
return $job->fail(
sprintf '%s: %s', @{ $tx->error }{qw( code message )}
);
}
$job->finish( $elapsed );
},
);
app->start;
</code></pre>
<h2>Enqueuing Jobs</h2>
devdata/https_mojolicious.io_blog_2018_12_11_who-watches-the-minions_ view on Meta::CPAN
<!-- theme suggests 1300x500 -->
<img alt="Minion logo in the middle of binocular circles, original artwork by Doug Bell" src="/blog/2018/12/11/who-watches-the-minions/banner.jpg">
</div>
<div class="post-content">
<section id="section-1">
<p>Now that I have a <a href="https://mojolicious.org/perldoc/Minion">Minion job
queue</a>, I need to take care of
it properly. Are the workers working (have they seized the means of
production)? Are jobs completing successfully? Are there any errors?
What are they?</p>
</section>
<section id="section-2">
<h2>Minion Jobs Command</h2>
<p>Minion comes with a <a href="https://mojolicious.org/perldoc/Minion/Command/minion/job"><code>job</code>
command</a> that
lists the jobs and their statuses.</p>
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
}
sub get_invalid_queues( $self, @queues ) {
my %queue_map;
@queue_map{ @QUEUE_TYPES } = ();
my @invalid_queues = grep !exists $queue_map{ $_ }, @queues;
return @invalid_queues;
}
</code></pre>
<p>With that in place, it was easy for our <code>queue_job()</code> method to throw an error if the developer tried to add a job to an invalid queue:</p>
<pre><code>sub queue_job( $self, $args ) {
my $job_name = $args->{ name } or die "queue_job(): must define job name!";
my $guid = $args->{ guid } or die "queue_job(): must have GUID to process!";
my $title = $args->{ title } // $job_name;
my $queue = $args->{ queue } // 'default';
my $job_args = $args->{ job_args };
die "queue_job(): Invalid job queue '$queue' specified" if $self->has_invalid_queues( $queue );
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
is => 'ro',
isa => 'MyJob::JobQueue',
lazy => 1,
default => sub( $self ) { return MyJob::JobQueue->new->runner; },
);
</code></pre>
<p>And in the models themselves, creating a new queueable task was as easy as:</p>
<pre><code>$self->runner->add_task( InstantXML =>
sub( $job, $request_path, $guid, $company_db, $force, $die_on_error = 0 ) {
$job->note(
request_path => $request_path,
feed_id => 2098,
group => $company_db,
);
MyJob::Models::FooBar->new( request_path => $request_path )->generate_xml({
pdf_guid => $guid,
group => $company_db,
force => $force,
die_on_error => $die_on_error,
});
});
</code></pre>
<h2>Running Jobs</h2>
<p>Starting a job from Dancer was super easy:</p>
<pre><code>use Dancer2;
use MyJob::JobQueue;
devdata/https_mojolicious.io_blog_2018_12_12_dancer-and-minion_ view on Meta::CPAN
my $id = $job->id;
my $notes = $job->info->{ notes };
my $title = $notes->{ title };
my $guid = $notes->{ guid };
$job->on( spawn => sub( $job, $pid ) {
$0 = "$title $guid";
$logger->info( "$title: Created child process $pid for job $id by parent $$ - $guid");
});
$job->on( failed => sub( $job, $error ) {
chomp $error;
$logger->error( $error );
});
});
</code></pre>
<p>To help us for future capacity planning, we want our workers to tell us if they are running at peak capacity, so log when this event occurs:</p>
<pre><code>$worker->on( busy => sub( $worker ) {
my $max = $worker->status->{ jobs };
$logger->log( "$0: Running at capacity (performing $max jobs)." );
});
devdata/https_mojolicious.io_blog_2018_12_23_mojolicious-and-angular_ view on Meta::CPAN
title => 'Higher Order Promises',
day => 3,
author => 'brain d foy',
},
],
status => 200,
);
});
</code></pre>
<p>As a sidenote, you may have to allow <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">Cross Origin Resource Sharing (CORS)</a> if the Angular app throws an error while accessing the mojo API endpoint.
In that case you may want to make use of the <a href="https://mojolicious.org/perldoc/Mojolicious/#before_dispatch"><code>before_dispatch</code></a> app hook:</p>
<pre><code>$self->hook(before_dispatch => sub {
my $c = shift;
$c->res->headers->header('Access-Control-Allow-Origin' => '*');
});
</code></pre>
<p>But please note, in a real-world application <code>*</code> is defeating the security feature.</p>
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
Mojo::IOLoop->start;
</code></pre>
<p>but that isn't always the case.
What if you wanted to return the title rather than print it?
What if wanted to fetch two resources rather than one, whether sequentially or in parallel?</p>
<h2>An Important First Step</h2>
<p>Several attempts have been made to organize and improve this situation.
The pattern that seems to have emerged as the preferred choice is <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises">Promises</a>.</p>
<p>Promises have a nice property that gets them closer to linear code.
You create and return a promise object that represents the eventual result of the task, though the task itself may not have even started yet.
In our example before we could say</p>
<pre><code>use Mojo::Promise;
my $promise = Mojo::Promise->new;
$ua->get($url, sub ($ua, $tx) {
my $title = trim $tx->res->dom->at('title')->text;
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
$promise->then(sub ($title) {
say $title;
})->wait;
</code></pre>
<p>At first glance this isn't too much better than the callback.
However, a few nice features emerge.
The most important of which is that the promise object can be returned to the caller and the caller can choose what to do with it.</p>
<p>In useful code you would also want to attach error handling, though I've omitted it here for bevity.
Mojolicious' promise implementation also gives us the <code>wait</code> method to start the ioloop if necessary.</p>
<p>Although it is interesting to see how a user can create a promise object to convert a callback api to promises, many libraries, including Mojolicious, now have promise variants built-in.
Rather than depending on the user to create a promise to resolve in the callback, these libraries will just return a promise of their own.
In the Mojolicious project, by convention methods that return promises end in <code>_p</code>.</p>
<p>With that we can write similar code to the one above</p>
<pre><code>my $promise = $ua->get_p($url);
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
}
get_title_p($url)->then(sub ($title) {
say $title;
})->wait;
</code></pre>
<p>All told, this is a step in the right direction, but it still involves a mental shift in style.
Even if this is easier than using pure callbacks, you still have to keep track of promises, consider the implications of chaining.
You still have to attach callbacks using <code>then</code>.
And don't forget error handling callbacks too!</p>
<p><em>Editor's note: to this point in the article, it is similar to the Perl Advent Calendar entry <a href="http://www.perladvent.org/2018/2018-12-19.html">posted just a few days before this one on 2018-12-19</a>, humorously presented by Mark Fo...
If you'd like to see another take on promises and Mojo::Promise specifically, give it a read.
Everything in it is applicable even as this article takes it one step further below ...</em></p>
<h2>Async/Await</h2>
<p>What we really wish we could tell the Perl interpreter to do is</p>
<ul>
devdata/https_mojolicious.io_blog_2018_12_24_async-await-the-mojo-way_ view on Meta::CPAN
<p>Where the example above would be at</p>
<pre><code>localhost:3000?url=https%3A%2F%2Fmojolicious.org&url=https%3A%2F%2Fmojolicious.io&url=https%3A%2F%2Fmetacpan.org
</code></pre>
<p>That code is almost exactly what you'd write for a blocking implementation except that it would block the server and it have to fetch the urls sequentially.
Instead, since it is written nonblocking, the requests are all made concurrently and the server is still free to respond to new clients.
And yet the code is still very easy to follow.</p>
<p>Note: the <a href="https://metacpan.org/pod/Mojolicious::Plugin::PromiseActions">PromiseActions</a> plugin automatically attaches error handlers to the controller action when it returns a promise; it is highly recommended when using async actions....
<h2>A Word on Implementation</h2>
<p>As stated before Mojo::AsyncAwait requires some mechanism to suspend the interpreter and resume it at that point later on.
Currently, the module uses the somewhat controversial module <a href="https://metacpan.org/pod/Coro">Coro</a> to do it.
As a bulwark against future implimentation changes, it comes with a pluggable backend system, not unlike how Mojo::IOLoop's pluggable reactor system works.
The default implementation may change and users may choose to use any available backend if they have a preference (once new ones come along, and others <strong>are</strong> in the works).</p>
<h2>Conclusion</h2>
devdata/https_mojolicious.io_blog_2018_12_25_special-thanks_ view on Meta::CPAN
We'll get those and other articles out to you in the coming months!</p>
<p>I want to thank Doug again for creating and maintaining <a href="http://preaction.me/statocles/">Statocles</a>, the static blog engine that powers this site.
I want to thank my employer <a href="https://www.servercentral.com/">ServerCentral</a> who not only are great to work for and support open source, but who gave me lots of time to get settled in with the newest member of my family (and a few cute gift...
I want to thank Sebastian Riedel for writing Mojolicious and for the outfit you see on Jude in the picture above (as far as I know, it is a unique piece), and the entire Mojolicious Core Team and community.</p>
<p>I want to thank Jude for being a reasonably happy newborn and sleeping for longer-than-average stretches at night.</p>
<p>Finally, I extend my warmest thanks to the doctors, nurses and staff of Northwest Community Hospital in Arlington Heights, Illinois and especially the NICU nurses who are beyond amazing.</p>
<p>Merry Christmas, Happy Holidays, Happy New Year, and Happy Perling!</p>
</section>
<small><p>Image: "Jude Carl Berger", original work by Joel Berger, licensed <a href="https://creativecommons.org/licenses/by-nc-nd/4.0/">CC BY-NC-ND 4.0</a>.</p>
</small>
<p class="tags">
<span>Tagged in </span>:
<a href="/blog/tag/advent/">advent</a>
</p>
t/00-compile.t view on Meta::CPAN
use File::Spec;
use IPC::Open3;
use IO::Handle;
open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
my @warnings;
for my $lib (@module_files)
{
# see L<perlfaq8/How can I capture STDERR from an external command?>
my $stderr = IO::Handle->new;
diag('Running: ', join(', ', map { my $str = $_; $str =~ s/'/\\'/g; q{'} . $str . q{'} }
$^X, @switches, '-e', "require q[$lib]"))
if $ENV{PERL_COMPILE_TEST_DEBUG};
my $pid = open3($stdin, '>&STDERR', $stderr, $^X, @switches, '-e', "require q[$lib]");
binmode $stderr, ':crlf' if $^O eq 'MSWin32';
my @_warnings = <$stderr>;
waitpid($pid, 0);
is($?, 0, "$lib loaded ok");
shift @_warnings if @_warnings and $_warnings[0] =~ /^Using .*\bblib/
and not eval { +require blib; blib->VERSION('1.01') };
if (@_warnings)
{
warn @_warnings;
push @warnings, @_warnings;