AE-AdHoc

 view release on metacpan or  search on metacpan

lib/AE/AdHoc.pm  view on Meta::CPAN

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
};

lib/AE/AdHoc.pm  view on Meta::CPAN

	$opt{after} ||= 0;

	my $count = $opt{count};
	my $inf = !$count;
	my $n = 0;

	my $timer;
	my $cb = sub {
		if (!$cv) {
			undef $timer;
			return _error( "Leftover $exact called outside ae_recv" );
		};
		$myiter == $iter or undef $timer;
		$inf or $count-->0 or undef $timer;
		$timer and $code->($n++);
	};
	$timer = AnyEvent->timer(
		after=>$opt{after}, interval=>$opt{interval}, cb=>$cb);
	return;
};

=head1 ERROR HANDLING

Dying within event loop is a bad idea, so we issue B<warnings> and write
errors to magic variables. It is up to the user to check these variables.

=over

=item * C<$AE::AdHoc::errstr> - last error (as in L<::DBI>).

=item * C<@AE::AdHoc::errors> - all errors.

=item * C<$AE::AdHoc::warnings> - set this to false to suppress warnings.

=back

=cut

our @errors;
our $errstr;
our $warnings = 1; # by default, complain loudly

sub _error {
	$errstr = shift;
	push @errors, $errstr;
	carp __PACKAGE__.": ERROR: $errstr" if $warnings;
	return;
};
sub _croak {
	_error(@_);
	croak shift;
};

=head1 CAVEATS

This module is still under heavy development, and is subject to change.
Feature/change requests are accepted.

=head2 Callback confinement

If event loop is entered several times, the callbacks created in one
invocations will NOT fire in another. Instead, they'll issue a warning
and return (see "Error handling" below).

Error message will be like C<ae_send at file:13 from ae_recv[1] at file:12
called in ae_recv[2] at file:117>

This is done so to isolate invocations as much as possible.

However, detection of "this invocation" will go wrong if callback maker is
called in a callback itself. For instance, this will always work the same:

	# ...
        callback => sub { ae_send->(@_); },
	# ...

=cut

=head1 AUTHOR

Konstantin S. Uvarin, C<< <khedin at gmail.com> >>

=head1 BUGS

Please report any bugs or feature requests to C<bug-ae-adhoc at rt.cpan.org>, or through
the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=AE-AdHoc>.  I will be notified, and then you'll
automatically be notified of progress on your bug as I make changes.

=head1 SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc AE::AdHoc


You can also look for information at:

=over 4

=item * github:

L<https://github.com/dallaylaen/perl-AE-AdHoc>

=item * RT: CPAN's request tracker

L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=AE-AdHoc>

=item * AnnoCPAN: Annotated CPAN documentation

L<http://annocpan.org/dist/AE-AdHoc>

=item * CPAN Ratings

L<http://cpanratings.perl.org/d/AE-AdHoc>

=item * Search CPAN

L<http://search.cpan.org/dist/AE-AdHoc/>

=back



( run in 0.522 second using v1.01-cache-2.11-cpan-d7f47b0818f )