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) <mst@shadowcat.co.uk>

CONTRIBUTORS
     Grinnz - Dan Book (cpan:DBOOK) <dbook@cpan.org>

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.

