Skip to content

Commit

Permalink
added error event to Mojo::IOLoop::Delay
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Sep 6, 2013
1 parent cf14cd8 commit a0b612b
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 18 deletions.
3 changes: 2 additions & 1 deletion Changes
@@ -1,5 +1,6 @@

4.32 2013-09-05
4.32 2013-09-06
- Added error event to Mojo::IOLoop::Delay.

4.31 2013-09-04
- Deprecated mode specific methods in application class.
Expand Down
33 changes: 24 additions & 9 deletions lib/Mojo/IOLoop/Delay.pm
Expand Up @@ -15,32 +15,38 @@ sub begin {
sub steps {
my $self = shift;
$self->{steps} = [@_];
$self->begin->();
$self->ioloop->timer(0 => $self->begin);
return $self;
}

sub wait {
my $self = shift;
my @args;

my ($err, @args);
$self->once(error => sub { shift->ioloop->stop; $err = shift });
$self->once(finish => sub { shift->ioloop->stop; @args = @_ });
$self->ioloop->start;
die $err if defined $err;

return wantarray ? @args : $args[0];
}

sub _step {
my ($self, $id) = (shift, shift);

$self->{args}[$id] = [@_];
return $self->{pending} if --$self->{pending} || $self->{lock};
return if $self->{failed} || --$self->{pending} || $self->{lock};
local $self->{lock} = 1;
my @args = map {@$_} @{delete $self->{args}};

$self->{counter} = 0;
if (my $cb = shift @{$self->{steps} ||= []}) { $self->$cb(@args) }
if (my $cb = shift @{$self->{steps} ||= []}) {
return $self->emit(error => $@)->{failed}++
unless eval { $self->$cb(@args); 1 };
}

if (!$self->{counter}) { $self->emit(finish => @args) }
elsif (!$self->{pending}) { $self->ioloop->timer(0 => $self->begin) }
return 0;
}

1;
Expand Down Expand Up @@ -104,6 +110,16 @@ L<Mojo::IOLoop>.
L<Mojo::IOLoop::Delay> inherits all events from L<Mojo::EventEmitter> and can
emit the following new ones.
=head2 error
$delay->on(error => sub {
my ($delay, $err) = @_;
...
});
Emitted if an error occurs in one of the steps and no more steps will be
reached.
=head2 finish
$delay->on(finish => sub {
Expand Down Expand Up @@ -137,10 +153,9 @@ implements the following new ones.
my $with_first_arg = $delay->begin(0);
Increment active event counter, the returned callback can be used to decrement
the active event counter again and will return the number of remaining active
events. Arguments passed to the callback are queued in the right order for the
next step or C<finish> event and C<wait> method, the first argument will be
ignored by default.
the active event counter again. Arguments passed to the callback are queued in
the right order for the next step or C<finish> event and C<wait> method, the
first argument will be ignored by default.
# Capture all arguments
my $delay = Mojo::IOLoop->delay;
Expand Down
62 changes: 54 additions & 8 deletions t/mojo/delay.t
Expand Up @@ -18,8 +18,8 @@ for my $i (1, 1) {
}
my $end = $delay->begin;
my $end2 = $delay->begin;
is $end->(), 3, 'three remaining';
is $end2->(), 2, 'two remaining';
$end->();
$end2->();
is_deeply [$delay->wait], [], 'no return values';
is_deeply \@results, [1, 1], 'right results';

Expand Down Expand Up @@ -78,23 +78,21 @@ is $finished, 1, 'finish event has been emitted once';
is $result, 'success', 'right result';

# End chain after third step
my $remaining;
($finished, $result) = ();
$delay = Mojo::IOLoop::Delay->new;
$delay->on(finish => sub { $finished++ });
$delay->steps(
sub { Mojo::IOLoop->timer(0 => shift->begin) },
sub {
$result = 'fail';
$remaining = shift->begin->();
$result = 'fail';
shift->begin->();
},
sub { $result = 'success' },
sub { $result = 'fail' }
);
is_deeply [$delay->wait], [], 'no return values';
is $remaining, 0, 'none remaining';
is $finished, 1, 'finish event has been emitted once';
is $result, 'success', 'right result';
is $finished, 1, 'finish event has been emitted once';
is $result, 'success', 'right result';

# End chain after second step
@results = ();
Expand Down Expand Up @@ -165,4 +163,52 @@ is_deeply [$delay->wait], [2, 3, 2, 1, 4, 5, 6, 23], 'right return values';
is $finished, 1, 'finish event has been emitted once';
is_deeply $result, [1, 2, 3, 2, 3, 2, 1, 4, 5, 6, 23], 'right results';

# Exception in first step
my $failed;
($finished, $result) = undef;
$delay = Mojo::IOLoop::Delay->new;
$delay->on(error => sub { $failed = pop });
$delay->on(finish => sub { $finished++ });
$delay->steps(sub { die 'First step!' }, sub { $result = 'failed' });
eval { $delay->wait };
like $@, qr/^First step!/, 'right error';
like $failed, qr/^First step!/, 'right error';
ok !$finished, 'finish event has not been emitted';
ok !$result, 'no result';

# Exception in second step
($failed, $finished, $result) = undef;
$delay = Mojo::IOLoop::Delay->new;
$delay->on(error => sub { $failed = pop });
$delay->on(finish => sub { $finished++ });
$delay->steps(
sub { Mojo::IOLoop->timer(0 => shift->begin) },
sub { die 'Second step!' },
sub { $result = 'failed' }
);
eval { $delay->wait };
like $@, qr/^Second step!/, 'right error';
like $failed, qr/^Second step!/, 'right error';
ok !$finished, 'finish event has not been emitted';
ok !$result, 'no result';

# Exception in second step (with active event)
($failed, $finished, $result) = undef;
$delay = Mojo::IOLoop::Delay->new;
$delay->on(error => sub { $failed = pop });
$delay->on(finish => sub { $finished++ });
$delay->steps(
sub { Mojo::IOLoop->timer(0 => shift->begin) },
sub {
Mojo::IOLoop->timer(0 => sub { Mojo::IOLoop->stop });
Mojo::IOLoop->timer(0 => shift->begin);
die 'Second step!';
},
sub { $result = 'failed' }
);
Mojo::IOLoop->start;
like $failed, qr/^Second step!/, 'right error';
ok !$finished, 'finish event has not been emitted';
ok !$result, 'no result';

done_testing();

0 comments on commit a0b612b

Please sign in to comment.