use Mojolicious::Lite;
get '/' => { text => 'I ♥ Mojolicious!' };
app->start;
> mojo get https://metacpan.org/release/Mojolicious '.release-modules li' all \
| grep -P '\S+'
Mojo - Web development toolkit
Mojo::Asset - HTTP content storage base class
Mojo::Asset::File - File storage for HTTP content
Mojo::Asset::Memory - In-memory storage for HTTP content
Mojo::Base - Minimal base class for Mojo projects
Mojo::ByteStream - ByteStream
Mojo::Cache - Naive in-memory cache
Mojo::Collection - Collection
Mojo::Content - HTTP content base class
Mojo::Content::MultiPart - HTTP multipart content
Mojo::Content::Single - HTTP content
Mojo::Cookie - HTTP cookie base class
Mojo::Cookie::Request - HTTP request cookie
Mojo::Cookie::Response - HTTP response cookie
Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors
Mojo::DOM::CSS - CSS selector engine
Mojo::DOM::HTML - HTML/XML engine
Mojo::Date - HTTP date
Mojo::EventEmitter - Event emitter base class
Mojo::Exception - Exceptions with context
Mojo::File - File system paths
Mojo::Headers - HTTP headers
Mojo::HelloWorld - Hello World!
Mojo::Home - Home sweet home
Mojo::IOLoop - Minimalistic event loop
Mojo::IOLoop::Client - Non-blocking TCP/IP and UNIX domain socket client
Mojo::IOLoop::Delay - Promises/A+ and flow-control helpers
Mojo::IOLoop::Server - Non-blocking TCP and UNIX domain socket server
Mojo::IOLoop::Stream - Non-blocking I/O stream
Mojo::IOLoop::Subprocess - Subprocesses
Mojo::IOLoop::TLS - Non-blocking TLS handshake
Mojo::JSON - Minimalistic JSON
Mojo::JSON::Pointer - JSON Pointers
Mojo::Loader - Load all kinds of things
Mojo::Log - Simple logger
Mojo::Message - HTTP message base class
Mojo::Message::Request - HTTP request
Mojo::Message::Response - HTTP response
Mojo::Parameters - Parameters
Mojo::Path - Path
Mojo::Promise - Promises/A+
Mojo::Reactor - Low-level event reactor base class
Mojo::Reactor::EV - Low-level event reactor with libev support
Mojo::Reactor::Poll - Low-level event reactor with poll support
Mojo::Server - HTTP/WebSocket server base class
Mojo::Server::CGI - CGI server
Mojo::Server::Daemon - Non-blocking I/O HTTP and WebSocket server
Mojo::Server::Hypnotoad - A production web serv...ALL GLORY TO THE HYPNOTOAD!
Mojo::Server::Morbo - Tonight at 11...DOOOOOOOOOOOOOOOM!
Mojo::Server::Morbo::Backend - Morbo backend base class
Mojo::Server::Morbo::Backend::Poll - Morbo default backend
Mojo::Server::PSGI - PSGI server
Mojo::Server::Prefork - Pre-forking non-blocking I/O HTTP and WebSocket server
Mojo::Template - Perl-ish templates
Mojo::Transaction - Transaction base class
Mojo::Transaction::HTTP - HTTP transaction
Mojo::Transaction::WebSocket - WebSocket transaction
Mojo::URL - Uniform Resource Locator
Mojo::Upload - Upload
Mojo::UserAgent - Non-blocking I/O HTTP and WebSocket user agent
Mojo::UserAgent::CookieJar - Cookie jar for HTTP user agents
Mojo::UserAgent::Proxy - User agent proxy manager
Mojo::UserAgent::Server - Application server
Mojo::UserAgent::Transactor - User agent transactor
Mojo::Util - Portable utility functions
Mojo::WebSocket - The WebSocket protocol
Mojolicious - Real-time web framework
Mojolicious::Command - Command base class
Mojolicious::Command::cgi - CGI command
Mojolicious::Command::cpanify - CPAN-ify command
Mojolicious::Command::daemon - Daemon command
Mojolicious::Command::eval - Eval command
Mojolicious::Command::generate - Generator command
Mojolicious::Command::generate::app - App generator command
Mojolicious::Command::generate::lite_app - Lite app generator command
Mojolicious::Command::generate::makefile - Makefile generator command
Mojolicious::Command::generate::plugin - Plugin generator command
Mojolicious::Command::get - Get command
Mojolicious::Command::inflate - Inflate command
Mojolicious::Command::prefork - Pre-fork command
Mojolicious::Command::psgi - PSGI command
Mojolicious::Command::routes - Routes command
Mojolicious::Command::test - Test command
Mojolicious::Command::version - Version command
Mojolicious::Commands - Command line interface
Mojolicious::Controller - Controller base class
Mojolicious::Lite - Micro real-time web framework
Mojolicious::Plugin - Plugin base class
Mojolicious::Plugin::Config - Perl-ish configuration plugin
Mojolicious::Plugin::DefaultHelpers - Default helpers plugin
Mojolicious::Plugin::EPLRenderer - Embedded Perl Lite renderer plugin
Mojolicious::Plugin::EPRenderer - Embedded Perl renderer plugin
Mojolicious::Plugin::HeaderCondition - Header condition plugin
Mojolicious::Plugin::JSONConfig - JSON configuration plugin
Mojolicious::Plugin::Mount - Application mount plugin
Mojolicious::Plugin::PODRenderer - POD renderer plugin
Mojolicious::Plugin::TagHelpers - Tag helpers plugin
Mojolicious::Plugins - Plugin manager
Mojolicious::Renderer - Generate dynamic content
Mojolicious::Routes - Always find your destination with routes
Mojolicious::Routes::Match - Find routes
Mojolicious::Routes::Pattern - Route pattern
Mojolicious::Routes::Route - Route
Mojolicious::Sessions - Session manager based on signed cookies
Mojolicious::Static - Serve static files
Mojolicious::Types - MIME types
Mojolicious::Validator - Validate values
Mojolicious::Validator::Validation - Perform validations
Test::Mojo - Testing Mojo
ojo - Fun one-liners with Mojo
> mojo get https://metacpan.org/release/Mojolicious '.release-modules li' all
| grep -P '\S+' \
| wc -l
> mojo get https://metacpan.org/release/Mojolicious '.release-modules li' all \
| grep -P '\S+' \
| grep -Piv 'http|web|mojolicious' \
| wc -l
> mojo get https://metacpan.org/release/Mojolicious '.release-modules li' all \
| grep -P '\S+' \
| grep -Piv 'http|web|mojolicious' \
| grep -Piv 'server|useragent|url|upload|test|dom|transaction' \
| wc -l
> mojo get https://metacpan.org/release/Mojolicious '.release-modules li' all \
| grep -P '\S+' \
| grep -Piv 'http|web|mojolicious' \
| grep -Piv 'server|useragent|url|upload|test|dom|transaction' \
| grep -Piv 'path|parameters|helloworld|^\s*ojo' \
| wc -l
Mojo::Base - Minimal base class for Mojo projects
Mojo::Cache - Naive in-memory cache
Mojo::Collection - Collection
Mojo::EventEmitter - Event emitter base class
Mojo::Exception - Exceptions with context
Mojo::Home - Home sweet home
Mojo::IOLoop - Minimalistic event loop
Mojo::IOLoop::Delay - Promises/A+ and flow-control helpers
Mojo::IOLoop::Stream - Non-blocking I/O stream
Mojo::IOLoop::Subprocess - Subprocesses
Mojo::IOLoop::TLS - Non-blocking TLS handshake
Mojo::JSON - Minimalistic JSON
Mojo::JSON::Pointer - JSON Pointers
Mojo::Loader - Load all kinds of things
Mojo::Log - Simple logger
Mojo::Promise - Promises/A+
Mojo::Reactor - Low-level event reactor base class
Mojo::Reactor::EV - Low-level event reactor with libev support
Mojo::Reactor::Poll - Low-level event reactor with poll support
Mojo::Template - Perl-ish templates
Mojo::Util - Portable utility functions
A simple base class for Mojo projects with fluent interfaces
package Cat;
use Mojo::Base -base;
has name => 'Nyan';
has ['age', 'weight'] => 4;
package Tiger;
use Mojo::Base 'Cat';
has friend => sub { Cat->new };
has stripes => 42;
use Mojo::Base -strict;
my $mew = Cat->new(name => 'Longcat');
say $mew->age;
say $mew->age(3)->weight(5)->age;
my $rawr = Tiger->new(stripes => 38, weight => 250);
say $rawr->tap(sub { $_->friend->name('Tacgnol') })->weight;
# use Mojo::Base -strict;
use strict;
use warnings;
use utf8;
use feature ':5.10';
use IO::Handle ();
# use Mojo::Base -base;
use strict;
use warnings;
use utf8;
use feature ':5.10';
use IO::Handle ();
push @ISA, 'Mojo::Base';
sub has { Mojo::Base::attr(__PACKAGE__, @_) }
# use Mojo::Base 'SomeBaseClass';
use strict;
use warnings;
use utf8;
use feature ':5.10';
use IO::Handle ();
require SomeBaseClass;
push @ISA, 'SomeBaseClass';
sub has { Mojo::Base::attr(__PACKAGE__, @_) }
# use Mojo::Base -role;
use strict;
use warnings;
use utf8;
use feature ':5.10';
use IO::Handle ();
use Role::Tiny;
sub has { Mojo::Base::attr(__PACKAGE__, @_) }
my $new_class = SubClass->with_roles('SubClass::Role::One');
my $new_class = SubClass->with_roles('+One', '+Two');
$object = $object->with_roles('+One', '+Two');
# Create a new class with the role "SubClass::Role::Foo" and instantiate it
my $new_class = SubClass->with_roles('+Foo');
my $object = $new_class->new;
Role support depends on Role::Tiny (2.000001+)
# Also enable signatures on 5.20+
use Mojo::Base -strict, -signatures;
use Mojo::Base -base, -signatures;
use Mojo::Base 'SomeBaseClass', -signatures;
use Mojo::Base -role, -signatures;
package Cat;
use Mojo::Base 'Mojo::EventEmitter';
# Emit events
sub poke {
my $self = shift;
$self->emit(roar => 3);
}
package main;
# Subscribe to events
my $tiger = Cat->new;
$tiger->on(roar => sub {
my ($tiger, $times) = @_;
say 'RAWR!' for 1 .. $times;
});
$tiger->poke;
$e->on(error => sub {
my ($e, $err) = @_;
say "This looks bad: $err";
});
$e = $e->catch(sub {...}); # Same thing, shorter.
Special event, fatal if not handled.
my $cb = $e->once(foo => sub {...});
# Unsubscribe last subscriber
$e->unsubscribe(foo => $e->subscribers('foo')->[-1]);
# Change order of subscribers
@{$e->subscribers('foo')} = reverse @{$e->subscribers('foo')};
use Mojo::Base -strict;
use Mojo::Exception;
# Throw exception and show stack trace
eval { Mojo::Exception->throw('Something went wrong!') };
say "$_->[0]: $_->[1]($_->[2])" for @{$@->frames};
say $@->line->[1]; # eval { ...
say $@->message; # Something went wrong!
say $@; # Something went wrong!
use Mojo::Log;
# Log to STDERR
my $log = Mojo::Log->new;
# Customize log file location and minimum log level
my $log = Mojo::Log->new(path => '/tmp/my.log', level => 'warn');
my $level = $log->level;
$log = $log->level('debug');
# also $ENV{MOJO_LOG_LEVEL}
# Log messages
$log->debug('Not sure what is happening here');
$log->info('FYI: it happened again');
$log->warn('This might be a problem');
$log->error('Garden variety error');
$log->fatal('Boom');
my $cb = $log->format;
$log->format(sub {
my ($time, $level, @lines) = @_;
return "[$level] I ♥ Mojolicious and don't care the message\n";
});
$log->on(message => sub {
my ($log, $level, @lines) = @_;
# Emitted for every log message
});
my $history = $log->history;
$log = $log->history([[time, 'debug', 'That went wrong']]);
my $size = $log->max_history_size; # 10 by default
$log = $log->max_history_size(5);
my $handle = $log->handle;
$log = $log->handle(IO::Handle->new);
$log->append("[Wed Aug 15 11:59:04 2018] [YAPC] I ♥ The perl conference\n");
my $path = $log->path
$log = $log->path('/var/log/mojo.log');
use Mojo::Base -strict;
use Mojo::Loader qw(data_section find_modules load_class);
# Find modules in a namespace
for my $module (find_modules 'Some::Namespace') {
# Load them safely
if ( my $e = load_class $module ) {
warn ref $e ? qq{Loading "$module" failed: $e}
: qq{"$module" not found!};
next;
}
}
package PerlMongers::Barcelona;
use Mojo::Base -base;
has cpan_authors => sub {{ map { chomp; split /\s*=\s*/ } <DATA> }};
__DATA__
ALEXM = Alex Muntada
DIEGOK = Diego Kuperman
ENELL = Enrique Nell
FXN = Xavier Noria
JAVIER = Javier Arturo Rodríguez Gutiérrez
JLMARTIN = José Luis Martínez Torres
MRUIZ = Míquel Ruiz Martín
package PerlMongers::Barcelona;
use Mojo::Base -base;
use Mojo::Loader qw/ data_section /;
has cpan_authors => sub {{ map { split /\s*=\s*/ } _lines('authors') }};
has events => sub {[ _lines('events') ]};
sub _lines { split /\n/, data_section(__PACKAGE__ => $_[0]) }
__DATA__
@@ authors
ALEXM = Alex Muntada
DIEGOK = Diego Kuperman
ENELL = Enrique Nell
FXN = Xavier Noria
@@ events
Barcelona Perl & Friends 2017
Barcelona Perl Workshop 2016
Barcelona Perl Workshop 2015
Barcelona Perl Workshop 2014
package PerlMongers::Barcelona;
use Mojo::Base -base;
use Mojo::Loader qw/ data_section /;
has cpan_authors => sub {{ map { split /\s*=\s*/ } _lines('authors') }};
has events => sub {[ _lines('events') ]};
sub _lines { split /\n/, data_section(__PACKAGE__ => $_[0]) }
__DATA__
@@ authors (base64)
QUxFWE0gPSBBbGV4IE11bnRhZGEKRElFR09LID0gRGllZ28gS3VwZXJtYW4KRU5FTEwgPSBFbnJp
cXVlIE5lbGwKRlhOID0gWGF2aWVyIE5vcmlh
@@ events (base64)
QmFyY2Vsb25hIFBlcmwgJiBGcmllbmRzIDIwMTcKQmFyY2Vsb25hIFBlcmwgV29ya3Nob3AgMjAx
NgpCYXJjZWxvbmEgUGVybCBXb3Jrc2hvcCAyMDE1CkJhcmNlbG9uYSBQZXJsIFdvcmtzaG9wIDIw
MTQ=
use Mojo::Base -strict;
use Mojo::Template;
# Use Perl modules
my $mt = Mojo::Template->new;
say $mt->render(<<'EOF');
% use Time::Piece;
% my $now = localtime;
Time: <%= $now->hms %>
EOF
# Render with arguments
say $mt->render(<<'EOF', [1 .. 13], 'Hello World!');
% my ($numbers, $title) = @_;
<%= $title %>
% for my $i (@$numbers) {
Test <%= $i %>
% }
EOF
# Render with named variables
say $mt->vars(1)->render(<<'EOF', {title => 'Hello World!'});
{
"title": "<%= $title %>"
}
EOF
<% Perl code %>
<%= Perl expression, replaced with result %>
<%== Perl expression, replaced with XML escaped result %>
<%# Comment, useful for debugging %>
<%% Replaced with "<%", useful for generating templates %>
% Perl code line, treated as "<% line =%>"
%= Perl expression line, treated as "<%= line %>"
%== Perl expression line, treated as "<%== line %>"
%# Comment line, useful for debugging
%% Replaced with "%", useful for generating templates
use Mojo::Base -strict;
use Mojo::Collection;
# Manipulate collection
my $collection = Mojo::Collection->new(qw(just works));
unshift @$collection, 'it';
say $collection->join(" "); # it just works
# Chain methods
$collection->map(sub { ucfirst })->shuffle->each(sub {
my ($word, $num) = @_;
say "$num: $word";
});
use Mojo::Base -strict;
use Mojo::Collection qw(c);
my $nums = c(1 .. 10);
say $nums->grep(sub{ $_ % 2 })->size; # count odds
say $nums->map(sub{ $_ % 2 || undef })->compact->size; # same
say $nums->map(sub{[$_, 100 - $_]})->flatten->reduce(sub{ $a + $b });
c(1 .. 10)->map(sub{ ($_) x $_ })->reduce(sub{ $a + $b });
c(1 .. 10)->map(sub{ $_ % 2 ? 'odd' : 'even' })->reduce(sub{ $a->{$b}++; $a }, {});
use Mojo::Collection qw(c);
# "G L A"
c('A', 'G', 'L', 'D', 'F')->slice(1, 2, 0)->join(' ');
# "Y A P C"
c('C', 'Y', 'A', 'D', 'P')->slice(0, 4, 2, 1)->reverse->join(' ');
use Mojo::Collection qw(c);
c(5..15, 0..10)->uniq->size; # 16
c(5..15, 0..10)->map(sub{ Car->new(wheels => $_) })
->sort(sub{ $a->wheels <=> $b->wheels })
->map('wheels')->uniq->to_array;
# [ 0..16 ]
c(0..16)->grep(qr/5/)->first; # 5
c(0..16)->grep(qr/5/)->last; # 15
A scalar-based container for file system paths that provides a friendly API for dealing with different operating systems.
use Mojo::Base -strict;
use Mojo::File;
my $path = Mojo::File->new('/home/diegok/.vimrc');
say $path->slurp; # ...
say $path->dirname; # /home/diegok
say $path->basename; # .vimrc
say $path->sibling('.zshrc'); # /home/diegok/.zshrc
use Mojo::Base -strict;
use Mojo::File 'path';
say path('foo/bar')->make_path->child('test.txt')->spurt('Some content')->to_abs;
use Mojo::Base -strict;
use Mojo::File 'path';
say path('/home/diegok/.vim')->list({dir=>1})->join("\n");
say path('/home/diegok/.vim')->list_tree->grep(qr/README/)->join("\n");
use Mojo::Base -strict;
use Mojo::File qw/ path tempdir /;
my $tmp = tempdir;
path('/home/diegok/.vim')->list_tree->grep(qr/README/)->each(sub{
$_->copy_to($tmp)
});
say $tmp->list->join("\n");
use Mojo::Base -strict;
use Mojo::File qw/ path /;
# IO::File
my $handle = path('some_file')->open('<:encoding(UTF-8)');
my $handle_rw = path('other_file')->open('+<');
my $handle_rw = path('other_file')->open('r+'); # same
use Mojo::Cache;
my $cache = Mojo::Cache->new(max_keys => 50);
$cache->set(foo => 'bar');
my $foo = $cache->get('foo');
use Mojo::Util qw/ b64_encode /;
use Mojo::File qw/ path /;
my $b64 = b64_encode path('mojo-picon.png')->slurp;
my $img = b64_decode $b64;
package Foo;
use Mojo::Base -base;
use Mojo::Util qw/ deprecated extract_usage /;
=head1 SYNOPSIS
Usage: Foo->new->help
=cut
sub help { extract_usage }
sub old_help { deprecated 'old_help is DEPRECATED in favor of help' }
my $checksum = md5_bytes $bytes;
# "acbd18db4cc2f85cedef654fccc4a4d8"
md5_sum 'foo';
my $checksum = sha1_bytes $bytes;
# "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"
sha1_sum 'foo';
monkey_patch 'Foo',
one => sub { say 'One!' },
two => sub { say 'Two!' },
three => sub { say 'Three!' };
# "Some \"word\" to test"
my $quoted = quote trim ' Some "word" to test ';
say unquote $quoted;
say unindent " sub {\n time\n }\n";
use Mojo::Base -strict;
use Mojo::Util qw/ md5_sum steady_time tablify /;
use Mojo::File qw/ path /;
my $t0 = steady_time;
say tablify path('/usr/bin')->list->map(sub{[
$_, eval{md5_sum($_->slurp)} || 'Unable to read file'
]});
say 'Took: 'steady_time - $t0, 'secs';
use Mojo::Base -strict;
use Mojo::IOLoop;
Mojo::IOLoop->server({port => 3003} => sub {
my ($loop, $stream) = @_;
$stream->on(read => sub {
my ($stream, $bytes) = @_;
say "-> $bytes";
$stream->write("ack: $bytes");
});
});
Mojo::IOLoop->client({port => 3003} => sub {
my ($loop, $err, $stream) = @_;
$stream->on(read => sub { say '<- ', pop });
my $count = 0;
$loop->recurring(2 => sub { ++$count && $stream->write("ping($count)") })
});
Mojo::IOLoop->timer(10 => sub { shift->stop });
Mojo::IOLoop->start unless Mojo::IOLoop->is_running;
use Mojo::Base -strict, -signatures;
use Mojo::IOLoop;
say "Main proccess is '$$'";
my $subprocess = Mojo::IOLoop->subprocess(
sub ( $subprocess ) { sleep 5 && return $$ },
sub ( $subprocess, $err, @results ) {
say $err ? "Subprocess error: $err"
: "Process '$$' got response from '$results[0]'.";
$subprocess->ioloop->stop;
}
);
Mojo::IOLoop->recurring(1 => sub { say "Waiting for '@{[ $subprocess->pid ]}'" });
Mojo::IOLoop->start;
Mojo::IOLoop->delay(
sub {
my $delay = shift;
Mojo::IOLoop->timer(2 => $delay->begin);
say 'Second step in 2 seconds.';
},
sub {
my $delay = shift;
Mojo::IOLoop->timer(1 => $delay->begin);
Mojo::IOLoop->timer(3 => $delay->begin);
say 'Third step in 3 seconds.';
},
sub { say 'And done after 5 seconds total.' }
)->wait;
use Mojo::Base -strict, -signatures;
use Mojo::Promise;
my $promise = Mojo::Promise->new;
my $loop = $promise->ioloop;
$loop->timer(2 => sub{ $promise->resolve(2) });
$promise->then(sub ( $waited ) {
my ($t1, $t3) = map { Mojo::Promise->new } 1..2;
$loop->timer(1 => sub{ $t1->resolve(1 + $waited) });
$loop->timer(3 => sub{ $t3->resolve(3 + $waited) });
Mojo::Promise->all($t1, $t3);
})->then(sub{ say "Done after $_[-1][0] seconds." })->wait;
use Mojo::Base -strict, -signatures;
use Mojo::Promise;
my $promise = Mojo::Promise->new;
my $loop = $promise->ioloop;
$loop->timer(2 => sub{ $promise->resolve(2) });
$promise->then(sub ( $waited ) {
my ($t1, $t3) = map { Mojo::Promise->new } 1..2;
$loop->timer(1 => sub{ $t1->resolve(1 + $waited) });
$loop->timer(3 => sub{ $t3->resolve(3 + $waited) });
Mojo::Promise->race($t1, $t3);
})->then(sub{ say "Done after $_[0] seconds." })->wait;
use Mojolicious::Lite -signatures;
my $hn = Mojo::URL->new('https://news.ycombinator.com/news');
get '/' => sub($c) {
$c->ua->get( $hn => sub{
$c->render( json => pop->res->dom->find('a.storylink')->map(sub{
[ $_->all_text, $_->attr('href') ]
})->to_array );
});
};
app->start;
use Mojolicious::Lite -signatures;
use Mojo::Collection qw(c);
my $hn = Mojo::URL->new('https://news.ycombinator.com/news');
get '/:pages' => [ pages => qr/[1-9]\d*/ ] => { pages => 3 } => sub($c) {
$c->render_later;
Mojo::Promise->all(
c( 1 .. $c->stash('pages') )->map(sub{
$c->ua->get_p( $hn->clone->query( p => $_ ) )->then(sub($tx) {
$tx->res->dom->find('a.storylink')->map(sub{
[ $_->all_text, $_->attr('href') ]
})->to_array;
})
})->@*
)->then(sub{
$c->render( json => c(@_)->flatten->to_array )
})->catch(sub{
$c->render( json => { error => [@_] } )
});
};
app->start;
use Mojolicious::Lite -signatures;
use Mojo::Collection qw(c);
use Mojo::Cache;
my $hn = Mojo::URL->new('https://news.ycombinator.com/news');
my $cache = Mojo::Cache->new;
get '/:pages' => [ pages => qr/[1-9]\d*/ ] => { pages => 3 } => sub($c) {
$c->render_later;
Mojo::Promise->all(
c( 1 .. $c->stash('pages') )->map(sub{
my $url = $hn->clone->query( p => $_ );
if ( my $cached = $cache->get($url) ) {
return Mojo::Promise->new->resolve( $cached );
}
$c->ua->get_p( $url )->then(sub($tx) {
my $res = $tx->res->dom->find('a.storylink')->map(sub{
[ $_->all_text, $_->attr('href') ]
})->to_array;
$cache->set( $url => $res );
$res;
})
})->@*
)->then(sub{
$c->render( json => c(@_)->flatten->to_array )
})->catch(sub{
$c->render( json => { error => [@_] } )
});
};
app->start;
use Mojolicious::Lite -signatures;
my $proxy_url = Mojo::URL->new('https://metacpan.org/');
any '/*rest' => { rest => '' } => sub($c) {
my $tx = Mojo::Transaction::HTTP->new( req => $c->req->clone );
$tx->req->url->$_($proxy_url->$_) for qw/ scheme host port /;
$tx->req->headers->header( Host => $tx->req->url->host_port );
$c->render_later;
$c->ua->start($tx, sub($ua, $tx) {
$c->tx->res($tx->res);
$c->rendered;
});
};
app->start;
use Mojolicious::Lite -signatures;
use Mojo::Cache;
my $cache = Mojo::Cache->new;
my $proxy_url = Mojo::URL->new('https://metacpan.org/');
any '/*rest' => { rest => '' } => sub($c) {
my $key = join '=', map {$c->req->$_} qw/ method url /;
if ( my $res = $cache->get($key) ) {
return $c->res($res) && $c->rendered;
}
my $tx = Mojo::Transaction::HTTP->new( req => $c->req->clone );
$tx->req->url->$_($proxy_url->$_) for qw/ scheme host port /;
$tx->req->headers->header( Host => $tx->req->url->host_port );
$c->render_later;
$c->ua->start($tx, sub($ua, $tx) {
$cache->set($key => $tx->res);
$c->tx->res($tx->res);
$c->rendered;
});
};
app->start;