Async-Methods
view release on metacpan or search on metacpan
lib/Async/Methods.pm view on Meta::CPAN
}
sub AUTOLOAD {
my ($self, @args) = @_;
my ($method) = our $AUTOLOAD =~ /^catch::(.+)$/;
$self->catch::_($method => @args);
}
package await;
sub this {
my ($self) = @_;
return $self->get if $self->can('get');
if ($self->isa('Mojo::Promise')) {
# This logic stolen from Mojo::Promis::Role::Get v0.1.2
Carp::croak "'get' cannot be called when the event loop is running"
if $self->ioloop->is_running;
my (@result, $rejected);
$self->then(sub { @result = @_ }, sub { $rejected = 1; @result = @_ })
->wait;
if ($rejected) {
my $reason = $result[0] // 'Promise was rejected';
die $reason if ref $reason or $reason =~ m/\n\z/;
Carp::croak $reason;
}
return wantarray ? @result : $result[0];
}
Carp::croak "Don't know how to await::this for $self";
}
sub await::_ {
my ($self, $method, @args) = @_;
if ($self eq 'await') {
Carp::croak "Call of '${method} await' should be '${method} +await'";
}
my $f = ($self->can('then')
? $self->then::_($method, @args)
: $self->$method(@args)
);
$f->await::this;
}
sub AUTOLOAD {
my ($self, @args) = @_;
my ($method) = our $AUTOLOAD =~ /^await::(.+)$/;
$self->await::_($method => @args);
}
1;
=head1 NAME
Async::Methods - Namespaced sugar methods for async/await and future/promise based code
=head1 SYNOPSIS
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;
# Normal synchronous code
print $ua->get('http://trout.me.uk/')->result->body;
# Equivalent code running synchronously atop promises
print $ua->get_p('http://trout.me.uk')->then::result->await::body;
# Equivalent code within an async subroutine
use Mojo::Base -async_await, -signatures;
async sub fetch ($url) {
await $ua->get_p($url)->then::result->then::body;
}
print fetch($url)->await::this;
=head1 DESCRIPTION
L<Async::Methods> provides a set of helper methods operating via namespace
that make chaining together asynchronous methods easier. This is not at all
meant to be a replacement for the C<async> and C<await> keywords available
via L<Future::AsyncAwait> or the C<-async_await> flag to L<Mojo::Base> and
in fact is largely meant to be used I<with> such facilities.
Note that in the following code I use C<$p> for example variables but they
can be L<Future> or L<Mojo::Promise> objects or (hopefully) objects of any
other class that provides a similar interface.
Note that methods of each type provided can be called three ways:
$obj->the_type::some_method(@args);
will call C<some_method> on a relevant object, and is effectively simply
sugar for the second type,
$obj->the_type::_(some_method => @args);
which calls the method name given in its first argument (yes, this means that
you can't use the first syntax to call a method called C<_> but the author of
this module strongly suspects that won't be an inconvience in most cases).
Thirdly, to match perl's capacity to allow <$obj->$cb(@args)> as a syntax, you
can also call:
$obj->the_type::_(sub { ... } => @args);
$obj->the_type::_($cb => @args);
to call that code reference as a method.
=head1 METHODS
=head2 start::
my $p = $obj->start::some_method(@args);
my $p = $obj->start::_(some_method => @args);
my $p = $obj->start::_(sub { ... } => @args);
L</start::> methods don't do anything special in and of themselves but
register the C<$obj> with L<Async::Methods> to allow L</catch::> and
L</else::> to work correctly (see their documentation below for why you
might find that useful). Other than the registration part, this is
entirely equivalent to
my $p = $obj->some_method(@args);
=head2 then::
my $then_p = $p->then::some_method(@args);
my $then_p = $p->then::_(some_method => @args);
my $then_p = $p->then::_(sub { ... } => @args);
L</then::> allows for chaining an additional method call from the return
value of the previous promise (assuming it's successful). As such, on its own
this is equivalent to
my $then_p = $p->then(
sub ($obj, @rest) { $obj->some_method(@args, @rest)) }
);
Note that L</then::> does not require anything special of the promise upon
( run in 0.338 second using v1.01-cache-2.11-cpan-df04353d9ac )