package Future::Mojo; use strict; use warnings; use Carp 'croak'; use Scalar::Util 'blessed', 'weaken'; use Mojo::IOLoop; use Role::Tiny::With; use parent 'Future'; our $VERSION = '1.002'; with 'Future::Role::Promisify'; sub new { my $proto = shift; my $self = $proto->SUPER::new; $self->{loop} = ref $proto ? $proto->{loop} : (shift() // Mojo::IOLoop->singleton); return $self; } sub new_timer { my $proto = shift; my $self = (blessed $_[0] and $_[0]->isa('Mojo::IOLoop')) ? $proto->new(shift) : $proto->new; $self->_set_timer(1, @_); return $self; } sub new_timeout { my $proto = shift; my $self = (blessed $_[0] and $_[0]->isa('Mojo::IOLoop')) ? $proto->new(shift) : $proto->new; $self->_set_timer(0, @_); return $self; } sub _set_timer { my ($self, $succeed, $after) = @_; weaken(my $weakself = $self); my $cb = $succeed ? sub { $weakself->done if $weakself } : sub { $weakself->fail('Timeout') if $weakself }; my $id = $self->loop->timer($after => $cb); $self->on_cancel(sub { shift->loop->remove($id) }); return $self; } sub loop { shift->{loop} } sub await { my $self = shift; croak 'Awaiting a future while the event loop is running would recurse' if $self->{loop}->is_running; $self->{loop}->one_tick until $self->is_ready; } sub done_next_tick { weaken(my $self = shift); my @result = @_; $self->loop->next_tick(sub { $self->done(@result) if $self }); return $self; } sub fail_next_tick { weaken(my $self = shift); my ($exception, @details) = @_; croak 'Expected a true exception' unless $exception; $self->loop->next_tick(sub { $self->fail($exception, @details) if $self }); return $self; } 1; =head1 NAME Future::Mojo - use Future with Mojo::IOLoop =head1 SYNOPSIS use Future::Mojo; use Mojo::IOLoop; my $loop = Mojo::IOLoop->new; my $future = Future::Mojo->new($loop); $loop->timer(3 => sub { $future->done('Done') }); print $future->get, "\n"; =head1 DESCRIPTION This subclass of L stores a reference to the associated L instance, allowing the C method to block until the Future is ready. For a full description on how to use Futures, see the L documentation. =head1 CONSTRUCTORS =head2 new my $future = Future::Mojo->new; my $future = Future::Mojo->new($loop); Returns a new Future. Uses L if no loop is specified. =head2 new_timer my $future = Future::Mojo->new_timer($seconds); my $future = Future::Mojo->new_timer($loop, $seconds); Returns a new Future that will become ready after the specified delay. Uses L if no loop is specified. =head2 new_timeout my $future = Future::Mojo->new_timeout($seconds); my $future = Future::Mojo->new_timeout($loop, $seconds); Returns a new Future that will fail after the specified delay. Uses L if no loop is specified. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 loop $loop = $future->loop; Returns the underlying L object. =head2 await $future->await; Runs the underlying L until the future is ready. If the event loop is already running, an exception is thrown. =head2 done_next_tick $future = $future->done_next_tick(@result); A shortcut to calling the L method on the L. Ensures that a returned Future object is not ready immediately, but will wait for the next I/O round. =head2 fail_next_tick $future = $future->fail_next_tick($exception, @details); A shortcut to calling the L method on the L. Ensures that a returned Future object is not ready immediately, but will wait for the next I/O round. =head2 promisify my $promise = $future->promisify; Composed from L. =head1 BUGS Report any issues on the public bugtracker. =head1 AUTHOR Dan Book =head1 CONTRIBUTORS =over =item Jose Luis Martinez (pplu) =back =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2015 by Dan Book. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) =head1 SEE ALSO L