NAME
   Async::Methods - Namespaced sugar methods for async/await and
   future/promise based code

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;

DESCRIPTION
   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 "async" and "await" keywords
   available via Future::AsyncAwait or the "-async_await" flag to
   Mojo::Base and in fact is largely meant to be used *with* such
   facilities.

   Note that in the following code I use $p for example variables but they
   can be Future or 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 "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 "_" 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.

METHODS
 start::
     my $p = $obj->start::some_method(@args);
     my $p = $obj->start::_(some_method => @args);
     my $p = $obj->start::_(sub { ... } => @args);

   "start::" methods don't do anything special in and of themselves but
   register the $obj with Async::Methods to allow "catch::" and "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);

 then::
     my $then_p = $p->then::some_method(@args);
     my $then_p = $p->then::_(some_method => @args);
     my $then_p = $p->then::_(sub { ... } => @args);

   "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 "then::" does not require anything special of the promise upon
   which it's called to provide the base functionality, but *does* need to
   be called on the result of something rooted in "start::" if you want to
   be able to chain "else::" or "catch::" from the return value.

 else::
     my $else_p = $p->else::some_method(@args);
     my $else_p = $p->else::_(some_method => @args);
     my $else_p = $p->else::_(sub { ... } => @args);

   "else::" must be called on the result of a "start::" chained to a
   "then::", and provides a callback if the start::ed method fails, invoked
   on the *original* invocant. This makes it the "other half" of
   Async::Methods' support for two-arg "<-"then>>, so:

     my $else_p = $obj->start::one(@args1)
                      ->then::two(@args2)
                      ->else::three(@args3);

   is functionally equivalent to:

     my $else_p = $obj->one(@args1)
                      ->then(
                          sub ($then_obj, @then_rest) {
                            $then_obj->two(@args2, @then_rest)
                          },
                          sub (@error) {
                            $obj->three(@args3, @error)
                          },
                        );

   which the author hopes explains why you might, on the whole, not really
   mind being forced to type start::.

   Note that because "else::" always resolves to the second argument to a
   two-arg "then" call, it can't be used in isolation. Fortunately, we
   already provide "catch::" for that, which is documented next.

 catch::
     my $catch_p = $p->catch::some_method(@args);
     my $catch_p = $p->catch::_(some_method => @args);
     my $catch_p = $p->catch::_(sub { ... } => @args);

   "catch::" can be called on the result of either a "start::" call or a
   "start::" -> "then::" chain, and will catch any/all errors produced up
   to this point, as opposed to "else::" which catches errors *before* the
   preceding "then::" call.

   As such, morally equivalent to:

     my $catch_p = $obj->start::whatever(...)
                       ->catch(sub ($obj, @error) {
                           $obj->some_method(@args, @error)
                         });

 await::
     my $ret = $p->await::this;

   "await::this" is simple generic sugar for (at top level of your code
   outside of an already-running event loop) spinning the event loop until
   the promise completes and then either returning the result on success or
   "die()"ing with the error on failure. For a future, it's equivalent to

     my $ret = $f->get;

   but if called on a Mojo::Promise loads Mojo::Promise::Role::Get and uses
   that to complete the operation, so "await::this" can be called on either
   and still provides a uniform interface. Assuming you install
   Mojo::Promise::Role::Get if you need it of course - otherwise you'll get
   an exception from the relevant "require" call.

     my $ret = $p->await::some_method(@args);
     my $ret = $p->await::_(some_method => @args);
     my $ret = $p->await::_(sub { ... } => @args);

   "await::" requires absolutely nothing of the promise upon which it's
   called, and other than the special case of "this" is equivalent to

     my $ret = $p->then::some_method(@args)->await::this;

   Hopefully obvious caveat: If you want to await a method called "this"
   you'll need to call one of

     my $ret = $p->then::this(@args)->await::this;
     my $ret = $p->await::_(this => @args);

   but "this" did not strike the author as a sufficiently common method
   name to be a deal-breaker in practice.

AUTHOR
    mst - Matt S. Trout (cpan:MSTROUT) <[email protected]>

CONTRIBUTORS
    Grinnz - Dan Book (cpan:DBOOK) <[email protected]>

COPYRIGHT
   Copyright (c) 2020 the Async::Methods "AUTHOR" and "CONTRIBUTORS" as
   listed above.

LICENSE
   This library is free software and may be distributed under the same
   terms as perl itself.