Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Five Point Oh

Five Point Oh

What's new in Mojolicious 5.0?

Sebastian Riedel

May 26, 2014
Tweet

More Decks by Sebastian Riedel

Other Decks in Programming

Transcript

  1. Features may only be changed in a major release or

    after being deprecated for at least 3 months.
  2. 4.15 2013-06-18 - Added around_action hook. ! 4.42 2013-09-30 -

    Added EXPERIMENTAL form validation support. ! 4.63 2013-12-19 - Added support for rotating secrets. ! 4.89 2014-03-13 - Added support for template variants.
  3. use Mango::BSON ':bson'; ! $app->renderer->add_handler(bson => sub { my ($renderer,

    $c, $output, $options) = @_; ! delete $options->{encoding}; $$output = bson_encode delete $c->stash->{bson}; ! return 1; });
  4. hook before_render => sub { my ($self, $args) = @_;

    $args->{handler}= ‘bson’ if $args->{bson}; };
  5. package Mojo::Template::SandBox; use Mojo::Base -strict;sub { my $_M = '';

    my $self = shift; Scalar::Util::weaken $self;no strict 'refs'; no warnings 'redefine';my $_H = $self->app->renderer- >helpers;sub url_for; *url_for = sub { $_H->{'url_for'}->($self, @_) };sub flash; *flash = sub { $_H- >{'flash'}->($self, @_) };sub form_for; *form_for = sub { $_H->{'form_for'}->($self, @_) };sub stylesheet; *stylesheet = sub { $_H->{'stylesheet'}->($self, @_) };sub link_to; *link_to = sub { $_H- >{'link_to'}->($self, @_) };sub range_field; *range_field = sub { $_H->{'range_field'}->($self, @_) };sub datetime_field; *datetime_field = sub { $_H->{'datetime_field'}->($self, @_) };sub content_for; *content_for = sub { $_H->{'content_for'}->($self, @_) };sub tag; *tag = sub { $_H- >{'tag'}->($self, @_) };sub email_field; *email_field = sub { $_H->{'email_field'}->($self, @_) };sub t; *t = sub { $_H->{'t'}->($self, @_) };sub search_field; *search_field = sub { $_H->{'search_field'}- >($self, @_) };sub text_area; *text_area = sub { $_H->{'text_area'}->($self, @_) };sub url_field; *url_field = sub { $_H->{'url_field'}->($self, @_) };sub title; *title = sub { $_H->{'title'}->($self, @_) };sub extends; *extends = sub { $_H->{'extends'}->($self, @_) };sub stash; *stash = sub { $_H- >{'stash'}->($self, @_) };sub week_field; *week_field = sub { $_H->{'week_field'}->($self, @_) };sub color_field; *color_field = sub { $_H->{'color_field'}->($self, @_) };sub param; *param = sub { $_H- >{'param'}->($self, @_) };sub config; *config = sub { $_H->{'config'}->($self, @_) };sub content; *content = sub { $_H->{'content'}->($self, @_) };sub tel_field; *tel_field = sub { $_H->{'tel_field'}- >($self, @_) };sub javascript; *javascript = sub { $_H->{'javascript'}->($self, @_) };sub hidden_field; *hidden_field = sub { $_H->{'hidden_field'}->($self, @_) };sub file_field; *file_field = sub { $_H->{'file_field'}->($self, @_) };sub date_field; *date_field = sub { $_H->{'date_field'}- >($self, @_) };sub layout; *layout = sub { $_H->{'layout'}->($self, @_) };sub select_field; *select_field = sub { $_H->{'select_field'}->($self, @_) };sub check_box; *check_box = sub { $_H- >{'check_box'}->($self, @_) };sub radio_button; *radio_button = sub { $_H->{'radio_button'}->($self, @_) };sub number_field; *number_field = sub { $_H->{'number_field'}->($self, @_) };sub input_tag; *input_tag = sub { $_H->{'input_tag'}->($self, @_) };sub dumper; *dumper = sub { $_H->{'dumper'}- >($self, @_) };sub app; *app = sub { $_H->{'app'}->($self, @_) };sub current_route; *current_route = sub { $_H->{'current_route'}->($self, @_) };sub url_with; *url_with = sub { $_H->{'url_with'}->($self, @_) };sub password_field; *password_field = sub { $_H->{'password_field'}->($self, @_) };sub session; *session = sub { $_H->{'session'}->($self, @_) };sub month_field; *month_field = sub { $_H- >{'month_field'}->($self, @_) };sub submit_button; *submit_button = sub { $_H->{'submit_button'}- >($self, @_) };sub time_field; *time_field = sub { $_H->{'time_field'}->($self, @_) };sub image; *image = sub { $_H->{'image'}->($self, @_) };sub text_field; *text_field = sub { $_H->{'text_field'}- >($self, @_) };sub include; *include = sub { $_H->{'include'}->($self, @_) };use strict;my $_S = $self->stash; my $extends = $_S->{'extends'}; my $layout = $_S->{'layout'};; do { $_M .= _escape scalar 1 + 1 ;$_M .= "\n";; $_M } }; 4.0
  6. #line 1 "inline template fcec5765d660bdc75c1aef523711141f" package Mojo::Template::SandBox; use Mojo::Base -strict;

    sub { my $_M = ''; my $self = shift; my $_S = $self->stash;; do { $_M .= _escape scalar 1 + 1 ;$_M .= "\n"; #line 1 "inline template fcec5765d660bdc75c1aef523711141f" ; $_M } }; 5.0
  7. # /login -> {name => ‘mojo’} # /login/mango -> {name

    => ‘mango’} $r->get(‘/login/:name’)->to(name => ‘mojo’);
  8. # /login -> undef # /mango/login -> {name => ‘mango’}

    $r->get(‘/:name/login’)->to(name => ‘mojo’); 4.0
  9. # /login -> {name => ‘mojo’} # /mango/login -> {name

    => ‘mango’} $r->get(‘/:name/login’)->to(name => ‘mojo’); 5.0
  10. GET /test HTTP/1.1 Upgrade: websocket Connection: Upgrade Host: 127.0.0.1:3000 Origin:

    http://127.0.0.1:3000 Pragma: no-cache Cache-Control: no-cache Sec-WebSocket-Key: QNJvHFfev8zJM9oB1nfuXQ== Sec-WebSocket-Version: 13 Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36
  11. HTTP/1.1 101 Switching Protocols Server: Mojolicious (Perl) Date: Sun, 04

    May 2014 17:23:58 GMT Connection: Upgrade Upgrade: websocket Sec-WebSocket-Accept: HLM2ousE+PBz6rhlnJGc74gmPwc= Sec-WebSocket-Extensions: permessage-deflate Content-Length: 0
  12. get ‘/delayed’ => sub { my $self = shift; Mojo::IOLoop->timer(3

    => sub { $self->render(text => ‘3 seconds delayed.’); }); };
  13. under ‘/delayed’ => sub { my $self = shift; Mojo::IOLoop->timer(3

    => sub { $self->continue; }); return undef; }; ! get ‘/’ => {text => ‘3 seconds delayed.’};
  14. <html> <body> <!—- ALL GLORY TO THE HYPNOTOAD —-> <p>Welcome</p>

    <p>to</p> <p>Mojoconf<!—- 2014 -—></p> <body> </html> ! my $tag = $dom->at(‘p:last-child’); my $text = $tag->text; 4.0
  15. <html> <body> <!—- ALL GLORY TO THE HYPNOTOAD —-> <p>Welcome</p>

    <p>to</p> <p>Mojoconf<!—- 2014 -—></p> <body> </html> ! my $tag = $dom->at(‘p:last-child’); my $text = $tag->contents->first; my $comment = $tag->contents->last; 5.0
  16. <html> <body> <!—- ALL GLORY TO THE HYPNOTOAD —-> <p>Welcome</p>

    <p>to</p> <p>Mojoconf<!—- 2014 -—></p> <body> </html> ! my $tag = $dom->at(‘p:last-child’); my $comment = $tag->[1]; my $text = $comment->previous_sibling;
  17. <html> <body> <!—- ALL GLORY TO THE HYPNOTOAD —-> <p>Welcome</p>

    <p>to</p> <p>Mojoconf<!—- 2014 -—></p> <body> </html> ! my $all = $dom->all_contents; my $comments = $all->grep(sub { $_->node eq ‘comment’ }); $comments->remove;
  18. cdata <![CDATA[ Foo ]]> comment <!—- Foo —-> doctype <!doctype

    html> pi <?foo?> raw Foo&nbsp;Bar root <html>...</html> tag <p>Foo</foo> text Foo Bar
  19. <html> <body> <p>Welcome</p> <p>to</p> <p>Mojoconf</p> <body> </html> ! my $text

    = $dom->at(‘p’)->[0]; $text->wrap(‘<b></b>’);
  20. <html> <body> <p><b>Welcome</b></p> <p>to</p> <p>Mojoconf</p> <body> </html> ! my $tag

    = $dom->at(‘p’)->next_sibling; $tag->wrap_content(‘<i></i>’);
  21. <html> <body> <p>Welcome</p> <p>to</p> <p>Mojoconf</p> <body> </html> ! my $text

    = $dom->find(‘p’)->last->[0]; $text->content(‘Mojoconf 2014’);
  22. @@ create.html.ep %= form_for create => begin %= text_field ‘title’

    %= text_field ‘description’ %= submit_button %= end
  23. get ‘/create’ => sub { my $self = shift; !

    my $validation = $self->validation; return $self->render unless $validation->has_data; ! $validation->required(‘title’)->like(qr/^\w+$/); $validation->optional(‘description’)->size(1, 250); ! return $self->render if $validation->has_error; $self->redirect_to(‘overview’); };
  24. @@ create.html.ep %= form_for create => begin %= csrf_field %=

    text_field ‘title’ %= text_field ‘description’ %= submit_button %= end
  25. <form action=“/create”> <input name="csrf_token" type="hidden" value="fa6a08..." /> <input name=“title” type=“text”

    /> <input name=“description” type=“text” /> <input value="Ok" type="submit" /> </form>
  26. app->minion->add_task(slow_log => sub { my ($job, $msg) = @_; sleep

    5; $job->app->log->debug(qq{Received message "$msg".}); });
  27. get '/log' => sub { my $self = shift; $self->minion->enqueue(slow_log

    => [‘mojo rocks!’]); $self->render(text => 'Your message will be logged soon.'); };