Hello community, here is the log from the commit of package perl-Mojolicious for openSUSE:Factory checked in at 2019-04-20 17:13:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/perl-Mojolicious (Old) and /work/SRC/openSUSE:Factory/.perl-Mojolicious.new.5536 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "perl-Mojolicious" Sat Apr 20 17:13:04 2019 rev:107 rq:695937 version:8.14 Changes: -------- --- /work/SRC/openSUSE:Factory/perl-Mojolicious/perl-Mojolicious.changes 2019-02-04 14:25:45.669043835 +0100 +++ /work/SRC/openSUSE:Factory/.perl-Mojolicious.new.5536/perl-Mojolicious.changes 2019-04-20 17:13:12.510927460 +0200 @@ -1,0 +2,30 @@ +Fri Apr 19 05:17:46 UTC 2019 - Stephan Kulow <co...@suse.com> + +- updated to 8.14 + see /usr/share/doc/packages/perl-Mojolicious/Changes + + 8.14 2019-04-18 + - Added EXPERIMENTAL timer method to Mojo::Promise. + - Added header_exists and header_exists_not methods to Test::Mojo. + - Fixed a bug where the finally callback in Mojo::Promise was passed a value, + which is incompatible with the JavaScript API. + - Fixed a bug in Mojo::Promise where the finally method could change promise + values. + - Fixed a merge bug in Mojo::Parameters where multiple values sharing the same + name could get lost. + +------------------------------------------------------------------- +Fri Mar 22 06:19:30 UTC 2019 - Stephan Kulow <co...@suse.com> + +- updated to 8.13 + see /usr/share/doc/packages/perl-Mojolicious/Changes + + 8.13 2019-03-21 + - Added EXPERIMENTAL map method to Mojo::Promise. (jberger) + - Added EXPERIMENTAL min_compress_size attribute to Mojolicious::Renderer. + (CandyAngel, mjemmeson) + - Improved the security of signed cookies by also signing the cookie name. + Note that this means that all sessions will be reset. + - Fixed Mojo::IOLoop::Server to not check if listen sockets are writable. + +------------------------------------------------------------------- Old: ---- Mojolicious-8.12.tar.gz New: ---- Mojolicious-8.14.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ perl-Mojolicious.spec ++++++ --- /var/tmp/diff_new_pack.RZEvoP/_old 2019-04-20 17:13:14.114929881 +0200 +++ /var/tmp/diff_new_pack.RZEvoP/_new 2019-04-20 17:13:14.114929881 +0200 @@ -17,7 +17,7 @@ Name: perl-Mojolicious -Version: 8.12 +Version: 8.14 Release: 0 %define cpan_name Mojolicious Summary: Real-time web framework ++++++ Mojolicious-8.12.tar.gz -> Mojolicious-8.14.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/Changes new/Mojolicious-8.14/Changes --- old/Mojolicious-8.12/Changes 2019-01-31 00:20:26.000000000 +0100 +++ new/Mojolicious-8.14/Changes 2019-04-18 20:53:24.000000000 +0200 @@ -1,4 +1,22 @@ +8.14 2019-04-18 + - Added EXPERIMENTAL timer method to Mojo::Promise. + - Added header_exists and header_exists_not methods to Test::Mojo. + - Fixed a bug where the finally callback in Mojo::Promise was passed a value, + which is incompatible with the JavaScript API. + - Fixed a bug in Mojo::Promise where the finally method could change promise + values. + - Fixed a merge bug in Mojo::Parameters where multiple values sharing the same + name could get lost. + +8.13 2019-03-21 + - Added EXPERIMENTAL map method to Mojo::Promise. (jberger) + - Added EXPERIMENTAL min_compress_size attribute to Mojolicious::Renderer. + (CandyAngel, mjemmeson) + - Improved the security of signed cookies by also signing the cookie name. + Note that this means that all sessions will be reset. + - Fixed Mojo::IOLoop::Server to not check if listen sockets are writable. + 8.12 2019-01-27 - Added EXPERIMENTAL timeout method to Mojo::Promise. (batman) - Removed deprecated module Mojolicious::Plugin::PODRenderer. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/META.json new/Mojolicious-8.14/META.json --- old/Mojolicious-8.12/META.json 2019-02-01 17:33:33.000000000 +0100 +++ new/Mojolicious-8.14/META.json 2019-04-18 21:10:14.000000000 +0200 @@ -58,6 +58,6 @@ }, "x_IRC" : "irc://irc.freenode.net/#mojo" }, - "version" : "8.12", - "x_serialization_backend" : "JSON::PP version 4.00" + "version" : "8.14", + "x_serialization_backend" : "JSON::PP version 4.02" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/META.yml new/Mojolicious-8.14/META.yml --- old/Mojolicious-8.12/META.yml 2019-02-01 17:33:33.000000000 +0100 +++ new/Mojolicious-8.14/META.yml 2019-04-18 21:10:14.000000000 +0200 @@ -31,5 +31,5 @@ homepage: https://mojolicious.org license: http://www.opensource.org/licenses/artistic-license-2.0 repository: https://github.com/mojolicious/mojo.git -version: '8.12' +version: '8.14' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Mojo/Base.pm new/Mojolicious-8.14/lib/Mojo/Base.pm --- old/Mojolicious-8.12/lib/Mojo/Base.pm 2018-12-30 19:18:59.000000000 +0100 +++ new/Mojolicious-8.14/lib/Mojo/Base.pm 2019-04-12 19:38:24.000000000 +0200 @@ -242,7 +242,7 @@ use Role::Tiny; sub has { Mojo::Base::attr(__PACKAGE__, @_) } -On Perl 5.20+ you can also append a C<-signatures> flag to all three forms and +On Perl 5.20+ you can also append a C<-signatures> flag to all four forms and enable support for L<subroutine signatures|perlsub/"Signatures">. # Also enable signatures diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Mojo/IOLoop/Server.pm new/Mojolicious-8.14/lib/Mojo/IOLoop/Server.pm --- old/Mojolicious-8.12/lib/Mojo/IOLoop/Server.pm 2019-01-02 14:56:13.000000000 +0100 +++ new/Mojolicious-8.14/lib/Mojo/IOLoop/Server.pm 2019-03-19 18:30:39.000000000 +0100 @@ -91,7 +91,8 @@ my $self = shift; weaken $self; ++$self->{active} - and $self->reactor->io($self->{handle} => sub { $self->_accept }); + and $self->reactor->io($self->{handle} => sub { $self->_accept }) + ->watch($self->{handle}, 1, 0); } sub stop { delete($_[0]{active}) and $_[0]->reactor->remove($_[0]{handle}) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Mojo/Parameters.pm new/Mojolicious-8.14/lib/Mojo/Parameters.pm --- old/Mojolicious-8.12/lib/Mojo/Parameters.pm 2018-11-22 21:21:52.000000000 +0100 +++ new/Mojolicious-8.14/lib/Mojo/Parameters.pm 2019-04-02 20:49:20.000000000 +0200 @@ -53,8 +53,9 @@ sub merge { my $self = shift; - my @pairs = @_ == 1 ? @{shift->pairs} : @_; - while (my ($name, $value) = splice @pairs, 0, 2) { + my $merge = @_ == 1 ? shift->to_hash : {@_}; + for my $name (sort keys %$merge) { + my $value = $merge->{$name}; defined $value ? $self->param($name => $value) : $self->remove($name); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Mojo/Promise.pm new/Mojolicious-8.14/lib/Mojo/Promise.pm --- old/Mojolicious-8.12/lib/Mojo/Promise.pm 2019-01-29 14:41:50.000000000 +0100 +++ new/Mojolicious-8.14/lib/Mojo/Promise.pm 2019-04-18 20:48:16.000000000 +0200 @@ -41,6 +41,31 @@ return $new; } +sub map { + my ($class, $options) = (shift, ref $_[0] eq 'HASH' ? shift : {}); + my ($cb, @items) = @_; + + my @start = map { $_->$cb } splice @items, 0, + $options->{concurrency} // @items; + my $proto = $class->resolve($start[0]); + + my (@trigger, @wait); + for my $item (@items) { + my $p = $proto->clone; + push @trigger, $p; + push @wait, $p->then(sub { local $_ = $item; $_->$cb }); + } + + my @all = map { + $proto->clone->resolve($_)->then( + sub { shift(@trigger)->resolve if @trigger; @_ }, + sub { @trigger = (); $proto->clone->reject($_[0]) }, + ) + } (@start, @wait); + + return $class->all(@all); +} + sub race { my ($class, @promises) = @_; my $new = $promises[0]->clone; @@ -63,12 +88,8 @@ return $new; } -sub timeout { - my ($self, $after, $err) - = (ref $_[0] ? shift : shift->new, @_, 'Promise timeout'); - $self->ioloop->timer($after => sub { $self->reject($err) }); - return $self; -} +sub timer { shift->_timer('resolve', @_) } +sub timeout { shift->_timer('reject', @_) } sub wait { my $self = shift; @@ -89,19 +110,18 @@ sub _finally { my ($new, $finally, $method, @result) = @_; - my ($res) = eval { $finally->(@result) }; - return $new->$method(@result) - unless $res && blessed $res && $res->can('then'); - $res->then(sub { $new->$method(@result) }, sub { $new->$method(@result) }); + return $new->reject($@) unless eval { $finally->(); 1 }; + return $new->$method(@result); } sub _settle { my ($self, $status) = (shift, shift); - $self = $self->new unless ref $self; + my $thenable = blessed $_[0] && $_[0]->can('then'); + $self = $thenable ? $_[0]->clone : $self->new unless ref $self; $_[0]->then(sub { $self->resolve(@_); () }, sub { $self->reject(@_); () }) and return $self - if blessed $_[0] && $_[0]->can('then'); + if $thenable; return $self if $self->{result}; @@ -120,6 +140,14 @@ return $new->resolve(@res); } +sub _timer { + my ($self, $method, $after, @result) = @_; + $self = $self->new unless ref $self; + $result[0] = 'Promise timeout' if $method eq 'reject' && !@result; + $self->ioloop->timer($after => sub { $self->$method(@result) }); + return $self; +} + 1; =encoding utf8 @@ -286,10 +314,36 @@ # Do something on fulfillment and rejection $promise->finally(sub { - my @value_or_reason = @_; say "We are done!"; }); +=head2 map + + my $new = Mojo::Promise->map(sub { ... }, @items); + my $new = Mojo::Promise->map({concurrency => 3}, sub { ... }, @items); + +Apply a function that returns a L<Mojo::Promise> to each item in a list of +items while optionally limiting concurrency. Returns a L<Mojo::Promise> that +collects the results in the same manner as L</all>. If any item's promise is +rejected, any remaining items which have not yet been mapped will not be. Note +that this method is EXPERIMENTAL and might change without warning! + + # Perform 3 requests at a time concurrently + Mojo::Promise->map({concurrency => 3}, sub { $ua->get_p($_) }, @urls) + ->then(sub{ say $_->[0]->res->dom->at('title')->text for @_ }); + +These options are currently available: + +=over 2 + +=item concurrency + + concurrency => 3 + +The maximum number of items that are in progress at the same time. + +=back + =head2 race my $new = Mojo::Promise->race(@promises); @@ -355,6 +409,17 @@ } ); +=head2 timer + + my $new = Mojo::Promise->timer(5 => 'Success!'); + $promise = $promise->timer(5 => 'Success!'); + $promise = $promise->timer(5); + +Create a new L<Mojo::Promise> object with a timer or attach a timer to an +existing promise. The promise will be resolved after the given amount of time in +seconds with or without a value. Note that this method is EXPERIMENTAL and might +change without warning! + =head2 timeout my $new = Mojo::Promise->timeout(5 => 'Timeout!'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Mojolicious/Controller.pm new/Mojolicious-8.14/lib/Mojolicious/Controller.pm --- old/Mojolicious-8.12/lib/Mojolicious/Controller.pm 2018-11-22 21:21:59.000000000 +0100 +++ new/Mojolicious-8.14/lib/Mojolicious/Controller.pm 2019-03-13 21:34:12.000000000 +0100 @@ -85,7 +85,7 @@ my $valid; for my $secret (@$secrets) { - my $check = Mojo::Util::hmac_sha1_sum($value, $secret); + my $check = Mojo::Util::hmac_sha1_sum("$name=$value", $secret); ++$valid and last if Mojo::Util::secure_compare($signature, $check); } if ($valid) { push @results, $value } @@ -239,8 +239,8 @@ return $self->every_signed_cookie($name)->[-1] unless defined $value; # Response cookie - my $checksum = Mojo::Util::hmac_sha1_sum($value, $self->app->secrets->[0]); - return $self->cookie($name, "$value--$checksum", $options); + my $sum = Mojo::Util::hmac_sha1_sum("$name=$value", $self->app->secrets->[0]); + return $self->cookie($name, "$value--$sum", $options); } sub stash { Mojo::Util::_stash(stash => @_) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Mojolicious/Guides/Contributing.pod new/Mojolicious-8.14/lib/Mojolicious/Guides/Contributing.pod --- old/Mojolicious-8.12/lib/Mojolicious/Guides/Contributing.pod 2018-12-31 13:37:21.000000000 +0100 +++ new/Mojolicious-8.14/lib/Mojolicious/Guides/Contributing.pod 2019-04-12 19:39:32.000000000 +0200 @@ -182,22 +182,6 @@ =back -=head1 DONATIONS - -L<Mojolicious> is open source and free to use. However, the amount of effort -needed to maintain the project and develop new features for it is not -sustainable without proper financial backing. You can support the ongoing -development of L<Mojolicious> through PayPal (C<donati...@mojolicious.org>). - -If you run a business and use L<Mojolicious> in a revenue generating product, it -makes business sense to support L<Mojolicious> development. Because it ensures -that the project your product relies on stays healthy and actively maintained. -It can also help your exposure within the community and will make it easier to -attract L<Mojolicious> developers. - -Please email us (C<donati...@mojolicious.org>) if you have any questions about -becoming a sponsor. - =head1 CODE OF CONDUCT Like the technical community as a whole, the L<Mojolicious> team and community diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Mojolicious/Guides/Routing.pod new/Mojolicious-8.14/lib/Mojolicious/Guides/Routing.pod --- old/Mojolicious-8.12/lib/Mojolicious/Guides/Routing.pod 2019-01-05 02:32:59.000000000 +0100 +++ new/Mojolicious-8.14/lib/Mojolicious/Guides/Routing.pod 2019-04-05 00:21:34.000000000 +0200 @@ -855,7 +855,7 @@ my $resource = $r->any("/$name")->to("$name#"); # Render a list of resources - $resource->get->to('#index')->name($name); + $resource->get('/')->to('#index')->name($name); # Render a form to create a new resource (submitted to "store") $resource->get('/create')->to('#create')->name("create_$name"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Mojolicious/Renderer.pm new/Mojolicious-8.14/lib/Mojolicious/Renderer.pm --- old/Mojolicious-8.12/lib/Mojolicious/Renderer.pm 2018-11-22 21:21:59.000000000 +0100 +++ new/Mojolicious-8.14/lib/Mojolicious/Renderer.pm 2019-03-13 23:50:43.000000000 +0100 @@ -14,7 +14,8 @@ has default_format => 'html'; has encoding => 'UTF-8'; has [qw(handlers helpers)] => sub { {} }; -has paths => sub { [] }; +has min_compress_size => 860; +has paths => sub { [] }; # Bundled templates my $TEMPLATES = path(__FILE__)->sibling('resources', 'templates'); @@ -122,7 +123,7 @@ # Gzip compression my $res = $c->res; - if ($self->compress) { + if ($self->compress && length($output) >= $self->min_compress_size) { my $headers = $res->headers; $headers->append(Vary => 'Accept-Encoding'); my $gzip = ($c->req->headers->accept_encoding // '') =~ /gzip/i; @@ -328,6 +329,15 @@ Registered helpers. +=head2 min_compress_size + + my $size = $renderer->min_compress_size; + $renderer = $renderer->min_compress_size(1024); + +Minimum output size in bytes required for compression to be used if enabled, +defaults to C<860>. Note that this attribute is EXPERIMENTAL and might change +without warning! + =head2 paths my $paths = $renderer->paths; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Mojolicious.pm new/Mojolicious-8.14/lib/Mojolicious.pm --- old/Mojolicious-8.12/lib/Mojolicious.pm 2019-01-02 19:04:39.000000000 +0100 +++ new/Mojolicious-8.14/lib/Mojolicious.pm 2019-03-21 23:06:06.000000000 +0100 @@ -59,7 +59,7 @@ has validator => sub { Mojolicious::Validator->new }; our $CODENAME = 'Supervillain'; -our $VERSION = '8.12'; +our $VERSION = '8.14'; sub BUILD_DYNAMIC { my ($class, $method, $dyn_methods) = @_; @@ -1078,6 +1078,8 @@ Michael Harris +Michael Jemmeson + Mike Magowan Mirko Westermeier diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/lib/Test/Mojo.pm new/Mojolicious-8.14/lib/Test/Mojo.pm --- old/Mojolicious-8.12/lib/Test/Mojo.pm 2018-11-22 21:21:40.000000000 +0100 +++ new/Mojolicious-8.14/lib/Test/Mojo.pm 2019-03-23 02:23:14.000000000 +0100 @@ -121,6 +121,20 @@ sub get_ok { shift->_build_ok(GET => @_) } sub head_ok { shift->_build_ok(HEAD => @_) } +sub header_exists { + my ($self, $name, $desc) = @_; + $desc = _desc($desc, qq{header "$name" exists}); + return $self->_test('ok', !!@{$self->tx->res->headers->every_header($name)}, + $desc); +} + +sub header_exists_not { + my ($self, $name, $desc) = @_; + $desc = _desc($desc, qq{no "$name" header}); + return $self->_test('ok', !@{$self->tx->res->headers->every_header($name)}, + $desc); +} + sub header_is { my ($self, $name, $value, $desc) = @_; $desc = _desc($desc, "$name: " . ($value // '')); @@ -724,6 +738,20 @@ Perform a C<HEAD> request and check for transport errors, takes the same arguments as L<Mojo::UserAgent/"head">, except for the callback. +=head2 header_exists + + $t = $t->header_exists('ETag'); + $t = $t->header_exists('ETag', 'header exists'); + +Check if response header exists. + +=head2 header_exists_not + + $t = $t->header_exists_not('ETag'); + $t = $t->header_exists_not('ETag', 'header is missing'); + +Opposite of L</"header_exists">. + =head2 header_is $t = $t->header_is(ETag => '"abc321"'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/t/mojo/parameters.t new/Mojolicious-8.14/t/mojo/parameters.t --- old/Mojolicious-8.12/t/mojo/parameters.t 2018-11-22 21:22:59.000000000 +0100 +++ new/Mojolicious-8.14/t/mojo/parameters.t 2019-04-02 20:54:59.000000000 +0200 @@ -37,6 +37,17 @@ is $params->merge(Mojo::Parameters->new(z => 6))->to_string, 'foo=b%3Bar&a=4&a=5&b=6&b=7&c=f%3Boo&x=1&y=3&z=6', 'right format'; +# Merge (instances) +$params + = Mojo::Parameters->new->merge(Mojo::Parameters->new(foo => [123, 456])); +is_deeply $params->to_hash, {foo => [123, 456]}, 'right structure'; +$params = Mojo::Parameters->new(foo => 321) + ->merge(Mojo::Parameters->new(foo => [123, 456])); +is_deeply $params->to_hash, {foo => [123, 456]}, 'right structure'; +$params = Mojo::Parameters->new(bar => 321) + ->merge(Mojo::Parameters->new(foo => [123, 456])); +is_deeply $params->to_hash, {foo => [123, 456], bar => 321}, 'right structure'; + # Param $params = Mojo::Parameters->new('foo=b%3Bar&a=4&a=5&b=6&b=7&c=f%3Boo&x=1&y=3&z=6'); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/t/mojo/promise.t new/Mojolicious-8.14/t/mojo/promise.t --- old/Mojolicious-8.12/t/mojo/promise.t 2019-01-29 14:40:35.000000000 +0100 +++ new/Mojolicious-8.14/t/mojo/promise.t 2019-04-18 20:51:27.000000000 +0200 @@ -31,11 +31,11 @@ # Resolved with finally $promise = Mojo::Promise->new; @results = (); -$promise->finally(sub { @results = @_; 'fail' }) +$promise->finally(sub { @results = ('finally'); 'fail' }) ->then(sub { push @results, @_ }); $promise->resolve('hello', 'world'); Mojo::IOLoop->one_tick; -is_deeply \@results, ['hello', 'world', 'hello', 'world'], 'promise settled'; +is_deeply \@results, ['finally', 'hello', 'world'], 'promise settled'; # Rejected $promise = Mojo::Promise->new; @@ -62,11 +62,11 @@ # Rejected with finally $promise = Mojo::Promise->new; @errors = (); -$promise->finally(sub { @errors = @_; 'fail' }) +$promise->finally(sub { @errors = ('finally'); 'fail' }) ->then(undef, sub { push @errors, @_ }); $promise->reject('bye', 'world'); Mojo::IOLoop->one_tick; -is_deeply \@errors, ['bye', 'world', 'bye', 'world'], 'promise settled'; +is_deeply \@errors, ['finally', 'bye', 'world'], 'promise settled'; # No state change $promise = Mojo::Promise->new; @@ -120,17 +120,31 @@ Mojo::IOLoop->one_tick; is_deeply \@errors, ['hello world'], 'promise rejected'; +# Double finally +$promise = Mojo::Promise->new; +@results = (); +$promise->finally(sub { push @results, 'finally1' }) + ->finally(sub { push @results, 'finally2' }); +$promise->resolve('pass'); +Mojo::IOLoop->one_tick; +is_deeply \@results, ['finally1', 'finally2'], 'promise not resolved'; + # Resolved nested with finally $promise = Mojo::Promise->new; $promise2 = Mojo::Promise->new; @results = (); -$promise->finally(sub {$promise2})->finally(sub { @results = @_ }); +$promise->finally(sub {$promise2})->finally(sub { @results = ('finally') }); $promise->resolve('pass'); Mojo::IOLoop->one_tick; -is_deeply \@results, [], 'promise not resolved'; -$promise2->resolve('fail'); +is_deeply \@results, ['finally'], 'promise already resolved'; + +# Exception in finally +$promise = Mojo::Promise->new; +@results = (); +$promise->finally(sub { die "Test!\n" })->catch(sub { push @results, @_ }); +$promise->resolve('pass'); Mojo::IOLoop->one_tick; -is_deeply \@results, ['pass'], 'promise resolved'; +is_deeply \@results, ["Test!\n"], 'promise rejected'; # Clone my $loop = Mojo::IOLoop->new; @@ -196,6 +210,17 @@ Mojo::Promise->timeout(0.025)->catch(sub { @errors = @_ })->wait; is_deeply \@errors, ['Promise timeout'], 'default timeout message'; +# Timer without value +@results = (); +Mojo::Promise->timer(0.025)->then(sub { @results = (@_, 'works!') })->wait; +is_deeply \@results, ['works!'], 'default timer result'; + +# Timer with values +@results = (); +Mojo::Promise->new->timer(0, 'first', 'second') + ->then(sub { @results = (@_, 'works too!') })->wait; +is_deeply \@results, ['first', 'second', 'works too!'], 'timer result'; + # All $promise = Mojo::Promise->new->then(sub {@_}); $promise2 = Mojo::Promise->new->then(sub {@_}); @@ -239,4 +264,58 @@ is_deeply \@errors, ['first', 'works too', 'second', 'works too'], 'promises rejected'; +# Map +my @started; +(@results, @errors) = (); +$promise = Mojo::Promise->map(sub { push @started, $_; $_ }, 1 .. 5) + ->then(sub { @results = @_ }, sub { @errors = @_ }); +is_deeply \@started, [1, 2, 3, 4, 5], 'all started without concurrency'; +$promise->wait; +is_deeply \@results, [[1], [2], [3], [4], [5]], 'correct result'; +is_deeply \@errors, [], 'promise not rejected'; + +# Map (with concurrency limit) +my $concurrent = 0; +(@results, @errors) = (); +Mojo::Promise->map( + {concurrency => 3}, + sub { + my $n = $_; + fail 'Concurrency too high' if ++$concurrent > 3; + Mojo::Promise->resolve->then(sub { + fail 'Concurrency too high' if $concurrent-- > 3; + $n; + }); + }, + 1 .. 5 +)->then(sub { @results = @_ }, sub { @errors = @_ })->wait; +is_deeply \@results, [[1], [2], [3], [4], [5]], 'correct result'; +is_deeply \@errors, [], 'promise not rejected'; + +# Map (with reject) +(@started, @results, @errors) = (); +Mojo::Promise->map( + {concurrency => 3}, + sub { + my $n = $_; + push @started, $n; + Mojo::Promise->resolve->then(sub { Mojo::Promise->reject($n) }); + }, + 1 .. 5 +)->then(sub { @results = @_ }, sub { @errors = @_ })->wait; +is_deeply \@results, [], 'promise not resolved'; +is_deeply \@errors, [1], 'correct errors'; +is_deeply \@started, [1, 2, 3], 'only initial batch started'; + +# Map (custom event loop) +my $ok; +$loop = Mojo::IOLoop->new; +$promise + = Mojo::Promise->map(sub { Mojo::Promise->new(ioloop => $loop)->resolve }, 1); +is $promise->ioloop, $loop, 'same loop'; +isnt $promise->ioloop, Mojo::IOLoop->singleton, 'not the singleton'; +$promise->then(sub { $ok = 1; $loop->stop }); +$loop->start; +ok $ok, 'loop completed'; + done_testing(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/t/mojo/template.t new/Mojolicious-8.14/t/mojo/template.t --- old/Mojolicious-8.12/t/mojo/template.t 2018-11-22 21:23:08.000000000 +0100 +++ new/Mojolicious-8.14/t/mojo/template.t 2019-03-19 21:38:55.000000000 +0100 @@ -39,6 +39,11 @@ $output = $mt->render('<%= (1,2,3)[1] %><%== (1,2,3)[2] %>'); is $output, "23\n", 'no ambiguity'; +# String +$mt = Mojo::Template->new; +$output = $mt->render('Just a <%= "test" %>'); +is $output, "Just a test\n", 'rendered string'; + # Trim tag $mt = Mojo::Template->new; $output = $mt->render(" ♥ <%= 'test♥' =%> \n"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/t/mojolicious/lite_app.t new/Mojolicious-8.14/t/mojolicious/lite_app.t --- old/Mojolicious-8.12/t/mojolicious/lite_app.t 2018-11-22 21:23:19.000000000 +0100 +++ new/Mojolicious-8.14/t/mojolicious/lite_app.t 2019-03-23 02:24:28.000000000 +0100 @@ -726,7 +726,10 @@ ->header_is(Server => 'Mojolicious (Perl)')->content_is('root fallback!'); # Root with format -$t->get_ok('/.html')->status_is(200)->header_is(Server => 'Mojolicious (Perl)') +$t->get_ok('/.html')->status_is(200)->header_exists_not('Servers') + ->header_exists_not('Servers', 'the header is missing') + ->header_exists('Server')->header_exists('Server', 'the header exists') + ->header_is(Server => 'Mojolicious (Perl)') ->content_is("/root.html\n/root.html\n/root.html\n/root.html\n/root.html\n"); # Reverse proxy with "X-Forwarded-For" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Mojolicious-8.12/t/mojolicious/renderer.t new/Mojolicious-8.14/t/mojolicious/renderer.t --- old/Mojolicious-8.12/t/mojolicious/renderer.t 2018-11-22 21:23:12.000000000 +0100 +++ new/Mojolicious-8.14/t/mojolicious/renderer.t 2019-03-13 01:05:14.000000000 +0100 @@ -143,6 +143,17 @@ 'right "Content-Encoding" value'; is $c->res->body, $output, 'same string'; +# Compression (below minimum length) +$output = 'a' x 850; +$c = $app->build_controller; +$c->req->headers->accept_encoding('gzip'); +$renderer->respond($c, $output, 'html'); +is $c->res->headers->content_type, 'text/html;charset=UTF-8', + 'right "Content-Type" value'; +ok !$c->res->headers->vary, 'no "Vary" value'; +ok !$c->res->headers->content_encoding, 'no "Content-Encoding" value'; +is $c->res->body, $output, 'same string'; + # Missing method (AUTOLOAD) my $class = ref $first->myapp; eval { $first->myapp->missing };