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 )