Mojo::Promise::Role::Repeat - Promise looping construct with break
version 0.006
# stupidly complicated while loop Mojo::Promise->with_roles('+Repeat')->repeat( 5, sub { my $n = shift; $_->('yay') unless $n > 0; print "($n)"; return $n-1; })->then( sub { print @_; } )->wait # # (5)(4)(3)(2)(1)yay # web treasure hunt pattern my @clues; $ua->get_p('http://example.com/start_here.html')->with_roles('+Repeat') ->repeat( sub { my $res = shift->result; die $res->message if $res->is_error; push @clues, $res->dom->at('#found_clue')->all_text; $_->() unless my $next_url = $res->dom->at('a#go_here_next')->{href}; $ua->get_p($next_url) })->then( sub { # do stuff with @clues ... },sub { # error handling ... })
Mojo::Promise::Role::Repeat, a role intended for Mojo::Promise objects, provides a looping construct for control flows involving promises and a "break" function that can escape through arbitrarily many levels of nested loops.
In all of the following, $class is a Mojo::Promise class with this role applied, $promise is an instance object of such a class, and $coderef is a code reference similar to what you feed to then or catch.
$class
$promise
$coderef
Mojo::Promise::Role::Repeat supplies the following methods to its host object/class:
$done_p = $class ->repeat(@initial, $coderef); $done_p = $promise->repeat(@initial, $coderef);
The first form is equivalent to
$done_p = $class->resolve(@initial) ->then($coderef)->then($coderef)->then($coderef) # ... forever
The second form is equivalent to
$done_p = $promise->then( sub { (@initial, @_) } ) ->then($coderef)->then($coderef)->then($coderef) # ... forever
In both cases, the value returned is effectively the promise generated by the "last" then call, the effect being to invoke the handler ($coderef) repeatedly for as often as it keeps returning normally, each time passing the values returned from the previous iteration, and with $_ bound to a "break" function that, when called, does not return but instead exits the handler, abandons the loop, and resolves that final promise ($done_p) with the value(s) provided.
then
$_
$done_p
If the "break" function is invoked with a promise passed as its first argument, the handler and loop are likewise abandoned, and the final promise awaits resolution/rejection of the passed promise.
If any iteration of the handler dies or returns a returns a promise that is rejected, the final promise is likewise rejected.
Note that the "break" function ($_) can be used to break out of nested handlers, but since $_ is dynamically bound and is likely to have changed by the time a nested handler runs, it is highly recommended that you use a lexical variable to capture this function for use in nested handlers,, e.g.,
$promise->repeat( sub { my $break = $_; ... $ua->get_p(...)->then( sub { ... $break->(@result) if (condition...); ... })->then( sub { ... }) })
Note that this method is EXPERIMENTAL and might change without warning.
$done_p = $class ->repeat_catch(@initial, $coderef); $done_p = $promise->repeat_catch(@initial, $coderef);
$done_p = $class->reject(@initial) ->catch($coderef)->catch($coderef)->catch($coderef) # ... forever
$done_p = $promise->catch( sub { "die"(@initial, @_) } ) ->catch($coderef)->catch($coderef)->catch($coderef) # ... forever
where "die" is the imaginary version of die that takes multiple values and throws them as a list rather than concatenating them.
"die"
In both cases, the value returned is effectively the promise generated by the "last" catch call, the effect being to invoke the handler ($coderef) repeatedly for as often as it keeps failing, each time passing the (error) values thrown from the previous iteration, and with $_ bound to a "break" function that, when called, does not return but instead exits the handler, abandons the loop, and rejects that final promise ($done_p) with the value(s) provided.
catch
If the "break" function $_ is invoked with a promise passed as its first argument, the loop is likewise abandoned and the final promise awaits resolution/rejection of the passed promise.
If any iteration of the handler returns normally or returns a returns a promise that is resolved, the final promise is likewise resolved with the same value(s).
Mojo::Promise, Mojolicious, Mojolicious::Guides, https://mojolicious.org.
Roger Crew <wrog@cpan.org>
This software is Copyright (c) 2019 by Roger Crew.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
To install Mojo::Promise::Role::Repeat, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Mojo::Promise::Role::Repeat
CPAN shell
perl -MCPAN -e shell install Mojo::Promise::Role::Repeat
For more information on module installation, please visit the detailed CPAN module installation guide.