curl -L https://cpanmin.us | perl - -M https://cpan.metacpan.org -n Mojolicious
use Mojolicious::Lite -signatures;
any '/' => sub ($c) { $c->render( text => 'Hello World' ) };
app->start;
$ ./script daemon
$ morbo script
$ hypnotoad script
$ plackup script
or $ starman script
/
/Joel
becomes 'Hello Joel'/
is special cased to /World
use Mojolicious::Lite -signatures;
any '/:name' => { name => 'World' } => sub ($c) {
$c->stash( time => scalar localtime );
$c->render( 'hello' );
};
app->start;
__DATA__
@@ layouts/basic.html.ep
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
%= content
</body>
<html>
@@ hello.html.ep
% layout 'basic';
% title "Hello $name";
<p>Hello <%= $name %></p>
%= tag p => begin
The time is now <%= $time %>
% end
ex/hello.pl
use Mojo::Base -strict;
use Test::More;
use Test::Mojo;
use FindBin '$Bin';
require "$Bin/hello.pl";
my $t = Test::Mojo->new;
$t->get_ok('/')
->status_is(200)
->content_like(qr/Hello World/)
->content_like(qr/\d{2}:\d{2}/);
$t->get_ok('/Joel')
->status_is(200)
->content_like(qr/Hello Joel/)
->content_like(qr/\d{2}:\d{2}/);
done_testing;
ex/hello1.t
Test::Mojo->new
$dom->at($selector)
returns a Mojo::DOM$dom->find($selector)
returns a Mojo::Collection
use Mojo::Base -strict;
use Mojo::DOM;
my $html = <<'END';
<div class="something">
<h2>Heading</h2>
Bare text
<p>Important</p>
</div>
<div class="else">Ignore</div>
END
my $dom = Mojo::DOM->new($html);
say $dom->at('.something p')->text;
ex/dom_example.pl
use Mojo::Base -strict;
use Test::More;
use Test::Mojo;
use FindBin '$Bin';
require "$Bin/hello.pl";
my $t = Test::Mojo->new;
$t->get_ok('/')
->status_is(200)
->text_is( p => 'Hello World' )
->text_like( 'p:nth-of-type(2)' => qr/\d{2}:\d{2}/ );
$t->get_ok('/Joel')
->status_is(200)
->text_is( p => 'Hello Joel' )
->text_like( 'p:nth-of-type(2)' => qr/\d{2}:\d{2}/ );
done_testing;
ex/hello2.t
Session info is signed and stored in a cookie
use Mojolicious::Lite -signatures;
helper validate => sub ($c, $user, $pass) {
state $users = {
joel => 'mypass',
};
return unless $users->{$user} eq $pass;
$c->session( user => $user );
};
any '/' => sub ($c) {
my ($user, $pass) = map {$c->param($_)} qw/user pass/;
$c->validate($user, $pass) if $user;
$c->render('index');
};
any '/logout' => sub ($c) {
$c->session( expires => 1 );
$c->redirect_to('/');
};
app->start;
__DATA__
@@ index.html.ep
% my $user = session 'user';
% title $user ? "Welcome back \u$user" : "Not logged in";
% layout 'basic';
<h1><%= title %></h1>
% unless ($user) {
%= form_for '/' => method => 'POST' => begin
Username: <%= input_tag 'user' %> <br>
Password <%= password_field 'pass' %> <br>
%= submit_button
% end
% }
ex/login.pl
use Mojo::Base -strict;
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new(max_redirects => 10);
say $ua->get('api.metacpan.org/v0/release/Mojolicious')
->res->json->{version};
use Mojo::URL;
my $url = Mojo::URL->new('http://openlibrary.org/subjects/')
->path('perl.json')
->query( details => 'true' );
say $url;
say $ua->get($url)->res->json('/works/0/title');
ex/ua_example.pl
use Mojo::Base -strict;
use Test::More;
use Test::Mojo;
use FindBin '$Bin';
require "$Bin/login.pl";
my $t = Test::Mojo->new;
$t->ua->max_redirects( 2 );
$t->get_ok('/')
->status_is(200)
->text_is( h1 => 'Not logged in' )
->element_exists( 'form' );
my $login = { user => 'joel', pass => 'mypass' };
$t->post_ok( '/' => form => $login )
->status_is(200)
->text_like( h1 => qr/joel/i )
->element_exists_not( 'form' );
$t->get_ok('/logout')
->status_is(200)
->element_exists('form');
done_testing;
ex/login.t
reply->not_found
renders a 404 pagereply->exception
renders a 500 page
use Mojolicious::Lite -signatures;
my %data = (
1 => { foo => 'bar' },
2 => { baz => 'bat' },
);
any '/:id' => sub ($c) {
return $c->reply->not_found
unless my $item = $data{$c->stash('id')};
$c->respond_to(
txt => { text => join(', ', %$item) },
json => { json => $item },
any => {
format => 'html',
template => 'page',
foo => $item,
},
);
};
app->start;
__DATA__
@@ page.html.ep
% my $key = (keys %$foo)[0];
% title "You wanted $key";
% layout 'basic';
<p>
All your <%= $key %>
are belong to <%= $foo->{$key} %>
</p>
ex/content.pl
use Mojo::Base -strict;
use Test::More;
use Test::Mojo;
use FindBin '$Bin';
require "$Bin/content.pl";
my $t = Test::Mojo->new;
$t->get_ok('/0')
->status_is(404);
$t->get_ok('/1')
->status_is(200)
->text_like( p => qr/foo.*?bar/ms );
$t->get_ok('/2?format=txt')
->status_is(200)
->content_is('baz, bat');
$t->get_ok('/1.json')
->status_is(200)
->json_is({foo => 'bar'});
$t->get_ok('/2', { Accept => 'application/json' })
->status_is(200)
->json_is('/baz' => 'bat');
done_testing;
ex/content.t
use Mojolicious::Lite -signatures;
use Mojo::UserAgent;
use Mojo::URL;
my $ua = Mojo::UserAgent->new;
my $url = Mojo::URL->new('http://api.metacpan.org/pod/')
->query( 'content-type' => 'text/html' );
any '/:module' => { module => 'Mojolicious' } => sub ($c) {
$c->render_later;
my $module = $c->stash('module');
my $target = $url->clone;
$target->path($module);
$ua->get( $target => sub {
my ($ua, $tx) = @_;
$c->render( 'docs', pod => $tx->res->body );
});
};
app->start;
__DATA__
@@ docs.html.ep
% layout 'basic';
% title $module;
<h1><%= $module %></h1>
%== $pod
ex/nb_doc_server.pl
use Mojolicious::Lite -signatures;
any '/' => 'index';
websocket '/data' => sub ($c) {
my $timer = Mojo::IOLoop->recurring( 1 => sub {
state $i = 0;
$c->send({ json => gen_data($i++) });
});
$c->on( finish => sub {
Mojo::IOLoop->remove($timer);
});
};
sub gen_data ($x) {
return [ $x, sin( $x + 2*rand() - 2*rand() ) ]
}
app->start;
__DATA__
@@ index.html.ep
% layout 'basic';
%= javascript '/jquery-1.9.1.min.js'
%= javascript '/jquery.flot.js'
<div id="plot" style="width:600px;height:300px">
</div>
%= javascript begin
var data = [];
var plot = $.plot($('#plot'), [ data ]);
var url = '<%= url_for('data')->to_abs %>';
var ws = new WebSocket( url );
ws.onmessage = function(e){
var point = JSON.parse(e.data);
data.push(point);
plot.setData([data]);
plot.setupGrid();
plot.draw();
};
% end
ex/websocket.pl
use Mojo::Base -strict;
use Test::More;
use Test::Mojo;
use FindBin '$Bin';
require "$Bin/websocket.pl";
my $t = Test::Mojo->new;
$t->get_ok('/')
->status_is(200)
->element_exists( '#plot' );
$t->websocket_ok('/data')
->message_ok
->json_message_is( '/0' => 0 )
->json_message_has( '/1' )
->message_ok
->json_message_is( '/0' => 1 )
->finish_ok;
done_testing;
ex/websocket.t
mojo get -r reddit.com/r/perl 'p.title > a.title' text
mojo get http://api.metacpan.org/v0/module/CHI /version
./ex/hello.pl get / p 1 text
./ex/websocket.pl routes
./ex/websocket.pl eval -v 'app->home'
./ex/websocket.pl eval -V 'app->secrets'
mojo generate lite_app
mojo generate app
mojo generate plugin
mojo nopaste gist myfile.pl
galileo setup
./myapp.pl minion worker
curl -L https://cpanmin.us | perl - -M https://cpan.metacpan.org -n Mojolicious