AE-AdHoc
view release on metacpan - search on metacpan
view release on metacpan or search on metacpan
lib/AE/AdHoc.pm view on Meta::CPAN
package AE::AdHoc;
use warnings;
use strict;
=head1 NAME
AE::AdHoc - Simplified interface for tests/examples of AnyEvent-related code.
=head1 NON-DESCRIPTION
This module is NOT for introducing oneself to AnyEvent, despite the mention of
"simplified". More over, it REQUIRES knowledge of what a conditional variable,
or simply "condvar", is. See L<Anyevent::Intro>.
This module is NOT for building other modules, it's for running them with
minimal typing.
=head1 SYNOPSIS
Suppose we have a subroutine named C<do_stuff( @args, $subref )>
that is designed to run under AnyEvent. As do_stuff may have to wait for
some external events to happen, it does not return a value right away.
Instead, it will call C<$subref-E<gt>( $results )> when stuff is done.
Now we need to test do_stuff, so we set up an event loop. We also need a timer,
because a test that runs forever is annoying. So the script goes like this:
use AnyEvent;
# set up event loop
my $cv = AnyEvent->condvar;
my $timer = AnyEvent->timer(
after => 10, cb => sub { $cv->croak("Timeout"); }
);
do_stuff( @args, sub{ $cv->send(shift); } );
# run event loop, get rid of timer
my $result = $cv->recv();
undef $timer;
# finally
analyze_results( $result );
Now, the same with AE::AdHoc:
use AE::AdHoc;
my $result = ae_recv {
do_stuff( @args, ae_send );
} 10; # timeout
analyze_results( $result );
=head1 EXPORT
Functions C<ae_recv>, C<ae_send>, C<ae_croak>, C<ae_begin>, C<ae_end>, and
C<ae_goal> are exported by default.
=head1 SUBROUTINES
B<Note>: Anywhere below, C<$cv> means L<AnyEvent>'s conditional variable
responsible for current event loop. See C<condvar> section of L<AnyEvent>.
=cut
our $VERSION = '0.0805';
use Carp;
use AnyEvent::Strict;
use Scalar::Util qw(weaken looks_like_number);
use Exporter;
BEGIN {
our @ISA = qw(Exporter);
our @EXPORT = qw(ae_recv ae_send ae_croak ae_begin ae_end ae_goal ae_action);
};
=head2 ae_recv { CODE; } [ $timeout ] %options;
The main entry point of the module.
Run CODE block, enter event loop and wait for $timeout seconds for callbacks
set up in CODE to fire, then die. Return whatever was sent via C<ae_send>.
$timeout must be a nonzero real number. Negative value means "run forever".
$timeout=0 would be ambigous, so it's excluded.
Options may include:
=over
=item * timeout - override the $timeout parameter (one timeout MUST be present).
=item * soft_timeout - Override $timeout, and don't die,
but return undef instead.
=back
Other functions in this module would die if called outside of C<ae_recv>.
=cut
# $cv is our so that it can be localized and act as a lock
our $cv;
# These are for error pretty-printing.
my $iter; # ++ every time
our $where; # "$file:$line[$iter]"
sub ae_recv (&@) { ## no critic
my $code = shift;
my $timeout = @_ % 2 && shift; # load bare timeout if present
my %opt = @_;
$timeout = $opt{timeout} || $opt{soft_timeout} || $timeout;
# check we're not in event loop before dying
$cv and _croak("Nested calls to ae_recv are not allowed");
local $cv = AnyEvent->condvar;
croak "Parameter timeout must be a nonzero real number"
if (!$timeout or !looks_like_number($timeout));
# find out where we are
$iter++;
my @caller = caller(0);
local $where = "ae_recv[$iter] at $caller[1]:$caller[2]";
my $on_timeout = $opt{soft_timeout}
? sub { $cv->send }
: sub { $cv->croak("Timeout after $timeout seconds"); };
my $timer;
$timeout > 0 and $timer = AnyEvent->timer( after => $timeout,
cb => $on_timeout,
);
_clear_goals();
$code->();
return $cv->recv;
# on exit, $timer is autodestroyed
# on exit, $cv is restored => destroyed
};
=head2 ae_send ( [@fixed_args] )
Create callback for normal event loop ending.
Returns a sub that feeds its arguments to C<$cv-E<gt>send()>. Arguments given to
the function itself are prepended, as in
C<$cv-E<gt>send(@fixed_args, @callback_args)>.
B<NOTE> that ae_recv will return all sent data "as is" in list context, and
only first argument in scalar context.
May be called as ae_send->( ... ) if you want to stop event loop immediately
(i.e. in a handcrafted callback).
=head2 ae_croak ( [$fixed_error] )
Create callback for event loop termination.
Returns a sub that feeds its first argument to $cv->croak(). If argument is
given, it will be used instead.
=head2 ae_begin ( [ sub { ... } ] )
=head2 ae_end
These subroutines provide ability to wait for several events to complete.
The AnyEvent's condition variable has a counter that is incremented by
C<begin()> and decreased by C<end()>. Optionally, the C<begin()> function
may also set a callback.
Whenever the counter reaches zero, either that callback or just C<send()> is
executed on the condvar.
B<Note>: If you do provide callback and want the event loop to stop there,
consider putting C<ae_send-E<gt>( ... )> somewhere inside the callback.
B<Note>: C<ae_begin()> acts at once, and does NOT return a closure. ae_end,
however, returns a subroutine reference just like C<ae_send>/C<ae_croak> do.
See begin/end section in L<AnyEvent>.
=cut
# set prototypes
sub ae_send (@); ## no critic
sub ae_croak (;$); ## no critic
sub ae_end (); ## no critic
view all matches for this distributionview release on metacpan - search on metacpan
( run in 2.214 seconds using v1.00-cache-2.02-grep-82fe00e-cpan-d29e8ade9f55 )