AE-AdHoc

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

Revision history for AE-AdHoc

0.08	Sat Oct 27 2012
        * API: Add ae_action { CODE } for delayed execution.
		* API: Add timeout and soft_timeout options to ae_recv.

0.07    Sun Sep 16 2012
        * API: Add magic variables for error handling
        * FIX: Fix ae_goal, add verbose error messages for leftover callbacks

0.05    Sun Sep 09 2012
        * API: Add multiple goal interface (ae_goal)

0.04    Sun Sep 09 2012
        * API: Add arglist support to callbacks: ae_recv { ae_send->(1..5) };
        * API: Add extra arguments to callback: ae_recv { ae_send(1..5) };
        * Example added (port-probe.pl)

0.03    Thu Sep 06 2012
        * API: Make empty/zero $timeout illegal.

0.0203  Tue Aug 14 2012
        * Fixed empty $timeout undef warning.
        * Minor code cleanup.

0.02    Sat Aug 11 2012
        First version, released on an unsuspecting world.
        - ae_recv, ae_send and ae_croak wotk and pass most basic tests

INSTALL  view on Meta::CPAN

To install AE::AdHoc, run the following commands:

perl Makefile.PL
make
make test
make install

MANIFEST  view on Meta::CPAN

Changes
examples/port-probe-multi.pl
examples/port-probe.pl
ignore.txt
INSTALL
lib/AE/AdHoc.pm
Makefile.PL
MANIFEST
README
t/00-load.t
t/10-basic.t
t/11-begin-end.t
t/12-nested-dies.t
t/13-null-timeout.t
t/14-xargs.t
t/15-goals.t
t/16-goals2.t
t/17-goals-leftover.t
t/boilerplate.t
t/manifest.t
t/pod-coverage.t
t/pod.t
t/18-all-leftover.t
t/19-soft-timeout.t
t/20-ae_action.t
META.yml                                 Module YAML meta-data (added by MakeMaker)
META.json                                Module JSON meta-data (added by MakeMaker)

META.json  view on Meta::CPAN

{
   "abstract" : "Simplified interface for tests/examples of AnyEvent-related code.",
   "author" : [
      "Konstantin S. Uvarin <khedin@gmail.com>"
   ],
   "dynamic_config" : 1,
   "generated_by" : "ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112621",
   "license" : [
      "perl_5"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : "2"
   },
   "name" : "AE-AdHoc",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : 0
         }
      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : 0
         }
      },
      "runtime" : {
         "requires" : {
            "AnyEvent" : 0,
            "AnyEvent::Strict" : 0,
            "Scalar::Util" : 0,
            "Test::Exception" : 0,
            "Test::More" : 0
         }
      }
   },
   "release_status" : "stable",
   "version" : "0.0805"
}

META.yml  view on Meta::CPAN

---
abstract: 'Simplified interface for tests/examples of AnyEvent-related code.'
author:
  - 'Konstantin S. Uvarin <khedin@gmail.com>'
build_requires:
  ExtUtils::MakeMaker: 0
configure_requires:
  ExtUtils::MakeMaker: 0
dynamic_config: 1
generated_by: 'ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112621'
license: perl
meta-spec:
  url: http://module-build.sourceforge.net/META-spec-v1.4.html
  version: 1.4
name: AE-AdHoc
no_index:
  directory:
    - t
    - inc
requires:
  AnyEvent: 0
  AnyEvent::Strict: 0
  Scalar::Util: 0
  Test::Exception: 0
  Test::More: 0
version: 0.0805

Makefile.PL  view on Meta::CPAN

use strict;
use warnings;
use ExtUtils::MakeMaker;

WriteMakefile(
    NAME                => 'AE::AdHoc',
    AUTHOR              => q{Konstantin S. Uvarin <khedin@gmail.com>},
    VERSION_FROM        => 'lib/AE/AdHoc.pm',
    ABSTRACT_FROM       => 'lib/AE/AdHoc.pm',
    ($ExtUtils::MakeMaker::VERSION >= 6.3002
      ? ('LICENSE'=> 'perl')
      : ()),
    PL_FILES            => {},
    PREREQ_PM => {
        'Test::More' => 0,
        'Test::Exception' => 0,
        'AnyEvent' => 0,
        'AnyEvent::Strict' => 0,
	'Scalar::Util' => 0,
    },
    dist                => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
    clean               => { FILES => 'AE-AdHoc-*' },
);

README  view on Meta::CPAN

AE-AdHoc

AE::AdHoc is a simple interface around AnyEvent intended for tests, examples,
and hastily written scripts.

It boils down to:

    use AE::AdHoc;

    my $result = ae_recv {
        do_something ( # the code under test
            on_success => ae_send,  # callback - all done, stop event loop
            on_failure => ae_croak, # callback - something happened, abort event loop
        );
    } 10; # timeout - fail test if it takes too long

    # later
    is ($result, $excepted_result, "...");

This module is under development for now.

INSTALLATION

To install this module, run the following commands:

	perl Makefile.PL
	make
	make test
	make install

SUPPORT AND DOCUMENTATION

After installing, you can find documentation for this module with the
perldoc command.

    perldoc AE::AdHoc

You can also look for information at:

    RT, CPAN's request tracker
        http://rt.cpan.org/NoAuth/Bugs.html?Dist=AE-AdHoc

    AnnoCPAN, Annotated CPAN documentation
        http://annocpan.org/dist/AE-AdHoc

    CPAN Ratings
        http://cpanratings.perl.org/d/AE-AdHoc

    Search CPAN
        http://search.cpan.org/dist/AE-AdHoc/


LICENSE AND COPYRIGHT

Copyright (C) 2012 Konstantin S. Uvarin

This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

examples/port-probe-multi.pl  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use AE::AdHoc;
use AnyEvent::Socket;
use Getopt::Long;

my $timeout = 1;

GetOptions (
	"timeout=s" => \$timeout,
	"help" => \&usage,
) or usage();

my @probe = map {
	/^(.*):(\d+)$/ or die "Expecting host:port. See $0 --help\n"; [$1, $2, $_];
} @ARGV;
usage() unless @probe;

# Real work
eval {
	ae_recv {
		tcp_connect $_->[0], $_->[1], ae_goal("$_->[0]:$_->[1]") for @probe;
	} $timeout;
};
die $@ if $@ and $@ !~ /^Timeout/;

my @offline = sort keys %{ AE::AdHoc->goals };
my (@alive, @reject);

my $results = AE::AdHoc->results;
foreach (keys %$results) {
	# tcp_connect will not feed any args if connect failed
	ref $results->{$_}->[0]
		? push @alive, $_
		: push @reject, $_;
};

print "Connected: @alive\n" if @alive;
print "Rejected: @reject\n" if @reject;
print "Timed out: @offline\n" if @offline;
# /Real work

sub usage {
	print <<"USAGE";
Probe tcp connection to several hosts at once
Usage: $0 [ options ] host:port host:port ...
Options may include:
	--timeout <seconds> - may be fractional as well
	--help - this message
USAGE
	exit 1;
};

examples/port-probe.pl  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use AE::AdHoc;
use AnyEvent::Socket;
use Getopt::Long;

my $timeout = 1;

GetOptions (
	"timeout=s" => \$timeout,
	"help" => \&usage,
) or usage();

my @probe = map {
	/^(.*):(\d+)$/ or die "Expecting host:port. See $0 --help\n"; [$1, $2, $_];
} @ARGV;
usage() unless @probe;

# Real work
my $alive = ae_recv {
	tcp_connect $_->[0], $_->[1], ae_send("$_->[0]:$_->[1]") for @probe;
} $timeout;
print "Connect to $alive succeeded!\n";
# /Real work

sub usage {
	print <<"USAGE";
Probe tcp connection to several hosts at once
Usage: $0 [ options ] host:port host:port ...
Options may include:
	--timeout <seconds> - may be fractional as well
	--help - this message
USAGE
	exit 1;
};

ignore.txt  view on Meta::CPAN

blib*
Makefile
Makefile.old
Build
Build.bat
_build*
pm_to_blib*
*.tar.gz
.lwpcookies
cover_db
pod2htm*.tmp
AE-AdHoc-*
MANIFEST.bak
MYMETA.*

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

# define ae_send, ae_croak and ae_end at once
foreach my $action (qw(send croak end)) {
	my $name = "ae_$action";
	my $code = sub {
		my @args = @_;

		croak("$name called outside ae_recv") unless $cv;
		my $myiter = $iter; # remember where cb was created

		my @caller = caller(0);
		my $exact = "$name at $caller[1]:$caller[2] from $where";

		return sub {
			return _error( "Leftover $exact called outside ae_recv" )
				unless $cv;
			return _error( "Leftover $exact called in $where")
				unless $iter == $myiter;
			$cv->$action(@args, @_);
		}; # end closure
	}; # end generated sub
	no strict 'refs'; ## no critic
	no warnings 'prototype'; ## no critic
	*{$name} = $code;
};

sub ae_begin(@) { ## no critic
	croak("ae_begin called outside ae_recv") unless $cv;

	$cv->begin(@_);
};


=head1 ADVANCED MULTIPLE GOAL INTERFACE

=head2 ae_goal( "name", @fixed_args )

Create a named callback.

When callback is created, a "goal" is set.

When such callback is called, anything passed to it is saved in a special hash
as array reference (prepended with @fixed_args, if any).

When all goals are completed, the hash of results is returned by C<ae_recv>.

If ae_send is called at some point, the list of incomplete and complete goals
is still available via C<goals> and C<results> calls.

The goals and results are reset every time upon entering ae_recv.

=cut

my %goals;
my %results;
sub _clear_goals { %goals = (); %results = (); };

sub ae_goal {
	my ($name, @fixed_args) = @_;

	croak "ae_goal called outside ae_recv" unless $cv;
	my $myiter = $iter;

	my @caller = caller(0);
	my $exact = "ae_goal('$name') at $caller[1]:$caller[2] from $where";

	$goals{$name}++ unless $results{$name};
	return sub {
		return _error( "Leftover $exact called outside ae_recv" )
			unless $cv;
		return _error( "Leftover $exact called in $where")
			unless $iter == $myiter;
		$results{$name} ||= [ @fixed_args, @_ ];
		delete $goals{$name};
		$cv->send(\%results) unless %goals;
	};
};

=head2 AE::AdHoc->goals

Return goals not yet achieved as hash ref.

=head2 AE::AdHoc->results

Return results of completed goals as hash ref.

=cut

sub goals { return \%goals; };
sub results { return \%results; };

=head1 ADDITIONAL ROUTINES

=head2 ae_action { CODE } %options

Perform CODE after entering the event loop via ae_recv
(a timer is used internally).

CODE will NOT run after current event loop is terminated (see ae_recv).

Options may include:

=over

=item * after - delay before code execution (in seconds, may be fractional)

=item * interval - delay between code executions (in seconds, may be fractional)

=item * count - how many times to execute. If zero or omitted, means unlimited
execution when interval is given, and just one otherwise.

=back

=cut

sub ae_action (&@) { ## no critic
	my $code = shift;
	my %opt = @_;

	# TODO copypaste from ae_goal, make a sub
	croak "ae_action called outside ae_recv" unless $cv;
	my $myiter = $iter;
	my @caller = caller(0);
	my $exact = "ae_action at $caller[1]:$caller[2] from $where";

	$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

=head1 SEE ALSO

L<AnyEvent>

=head1 ACKNOWLEDGEMENTS


=head1 LICENSE AND COPYRIGHT

Copyright 2012 Konstantin S. Uvarin.

This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.


=cut

1; # End of AE::AdHoc

t/00-load.t  view on Meta::CPAN

#!perl -T

use Test::More tests => 1;

BEGIN {
    use_ok( 'AE::AdHoc' ) || print "Bail out!
";
}

diag( "Testing AE::AdHoc $AE::AdHoc::VERSION, Perl $], $^X" );

t/10-basic.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More tests => 9;
use Test::Exception;

use AE::AdHoc;

throws_ok {
	ae_recv { ; } 0.01;
} qr(Timeout), "empty body => reach timeout => die";

lives_and {
	is ((ae_recv { ae_send->(137); } 0.01), 137 );
} "plain ae_send is fine";

throws_ok {
	ae_send;
} qr(outside), "outside = no go";

throws_ok {
	ae_begin;
} qr(outside), "outside = no go";

my $timer;
throws_ok {
	ae_recv {
		$timer = AnyEvent->timer( after => 0.1, cb => ae_send );
		note "timer ref = $timer";
	} 0.01;
} qr(Timeout), "Start rotten timer test";

# check that later-on callback generates a warning
{
	my @warn;
	local $SIG{__WARN__} = sub { push @warn, @_ };
	throws_ok {
		ae_recv { ; } 0.2;
	} qr(Timeout), "Rotten timer didn't spoil later tests:";
	is (scalar @warn, 1, " - 1 warning issued");
	like ($warn[0], qr(Leftover), " - It was about 'Leftover': $warn[0]");
	ok (ref $timer, " - Rotten timer still alive at this point (but harmless): $timer");

};

t/11-begin-end.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More;
use Test::Exception;

use AE::AdHoc;

my @timers;

plan tests => 5;

lives_ok {
	my $timer;
	ae_recv {
		ae_begin;
		$timer = AnyEvent->timer( after => 0.01, cb => ae_end );
	} 1;
} "A simple begin/end example works";

throws_ok {
	my $timer;
	ae_recv {
		ae_begin;
		ae_begin;
		$timer = AnyEvent->timer( after => 0.01, cb => ae_end );
	} 0.02;
} qr(Timeout), "A simple example with extra begin dies";

my @trace;
my $val;

lives_ok {
	ae_recv {
		my $tm;
		my $iter;
		my $attimer;
		$attimer = sub {
			push @trace, ++$iter;
			ae_end->();
			$tm = AE::timer 0.01, 0, $attimer;
		};
		$tm = AE::timer 0.01, 0, $attimer;
		ae_begin( sub { ae_send->(++$val) } ) for (1,2);
	} 1;
} "More complex example lives";

is ($val, 1, "Begin's callback executed once");
is_deeply(\@trace, [1, 2], "end->() executed twice");

t/12-nested-dies.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More;
use Test::Exception;

use AE::AdHoc;
$AE::AdHoc::warnings = 0;

plan tests => 1;
throws_ok {
	ae_recv {
		ae_recv {
		} 1;
	} 2;
} qr(nested)i, "Nested calls not allowed";

t/13-null-timeout.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More;
use Test::Exception;

use AE::AdHoc;

my @warn;
$SIG{__WARN__} = sub { push @warn, shift };

plan tests => 4;

throws_ok {
	ae_recv{ };
} qr(timeout.*non-?zero), "No timeout = no go";

throws_ok {
	ae_recv{ } "foo";
} qr(timeout.*non-?zero), "Non-numeric timeout = no go";

throws_ok {
	ae_recv{ } 0.01;
} qr(^Timeout after), "Timeout with empty body";

is (scalar @warn, 0, "no warnings");
note "warning: $_" for @warn;

t/14-xargs.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More tests => 5;
use Test::Exception;

use AE::AdHoc;

my @list;
my $scalar;

@list = ae_recv {
	ae_send(1..5)->(6..10);
} 0.01;

is_deeply (\@list, [1..10], "Extra args in list context");

$scalar = ae_recv {
	ae_send(1..5)->(6..10);
} 0.01;

is ($scalar, 1, "Extra args in scalar context");

$scalar = ae_recv {
	ae_send->(6..10);
} 0.01;

is ($scalar, 6, "Multiple args in scalar context");

# Error handling

throws_ok {
	ae_recv {
		ae_croak("bump bump")->("real error");
	} 0.01;
} qr(^bump bump), "Extra args in croak";

unlike ($@, qr(real error), "Sorry, no real error for you");

t/15-goals.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More tests => 5;
use Test::Exception;
use AnyEvent::Strict;
use Data::Dumper;

use AE::AdHoc;

my $result;

throws_ok {
	ae_goal("foo");
} qr(outside), "no ae_recv = no go";
note $@;

# We use sub {} in timers here because timer passes random args to its
# callback. See L<::AnyEvent> timer section.

lives_ok {
	my ($t1, $t2);
	$result = ae_recv {
		$t1 = AnyEvent->timer( after => 0,
			cb => sub { ae_goal("task1")->() }
		);
		$t2 = AnyEvent->timer( after => 0,
			cb => sub { ae_goal("task2", "fixed")->() }
		);
	} 1;
} "No timeout - goals complete";

note "Got: ".Dumper($result);

is_deeply ($result,
	{ task1 => [], task2 => [ "fixed" ]},
	"Results as expected (sans timer callback args)"
);
is_deeply (AE::AdHoc->results(), $result, "AE::AdHoc::results consistent");
is_deeply (AE::AdHoc->goals(), {}, "AE::AdHoc::goals is empty (all complete)");

t/16-goals2.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More tests => 8;
use Test::Exception;

use AE::AdHoc;

throws_ok {
	ae_recv {
		ae_goal("never");
		ae_goal("always")->();
	} 0.1;
} qr(^Timeout), "Goals not done, sorry";
is_deeply( AE::AdHoc->results, { always => [] }, "1 goal done");
is_deeply( AE::AdHoc->goals, { never => 1 }, "1 goal left");

ae_recv { ae_send->(137) } 0.1;

is_deeply( AE::AdHoc->results, { }, "results cleared");
is_deeply( AE::AdHoc->goals, { }, "goals cleared");

throws_ok {
	ae_recv {
		ae_goal("never") for 1..3;
		ae_goal("always")->($_) for 1..3;
	} 0.1;
} qr(^Timeout), "Goals not done, sorry";
is_deeply( AE::AdHoc->results, { always => [1] }, "only first goal callback counts");
is_deeply( AE::AdHoc->goals, { never => 3 }, "1 goal left, but 3 times");

t/17-goals-leftover.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More tests => 3;
use Data::Dumper;

use AE::AdHoc;
$AE::AdHoc::warnings = 0;

my $timer;
ae_recv {
	$timer = AnyEvent->timer( after => 0, cb => ae_goal("pollute") );
	ae_send->("return right now");
} 0.1;

my $timer2;
ae_recv {
	$timer2 = AnyEvent->timer( after => 0.1, cb => ae_goal("clean") );
} 0.2;

my @keys = sort keys %{ AE::AdHoc->results };
is_deeply( \@keys, ["clean"], "AE results are clean" );
note "Results: ".Dumper( AE::AdHoc->results );

is (scalar @AE::AdHoc::errors, 1, "Exactly 1 error");
like ($AE::AdHoc::errstr, qr(^Leftover.*ae_goal), "Leftover error present");
note "Error was: $AE::AdHoc::errstr";

t/18-all-leftover.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More tests => 5;
use Test::Exception;

use AE::AdHoc;
$AE::AdHoc::warnings = 0;

my $sub;

ae_recv { $sub = ae_send; ae_send->("stop now"); } 0.01;
lives_ok { $sub->() } "Don't die if event loop MAY exist";
like ($AE::AdHoc::errstr, qr(Leftover.*outside), "Error was catched");
note $AE::AdHoc::errstr;

ae_recv { $sub = ae_goal("foo"); ae_send->("stop now"); } 0.01;
lives_ok { $sub->() } "Don't die if event loop MAY exist";
like ($AE::AdHoc::errstr, qr(Leftover.*outside), "Error was catched");
note $AE::AdHoc::errstr;

is (scalar @AE::AdHoc::errors, 2, "Exactly two errors");

t/19-soft-timeout.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More tests => 2;
use Test::Exception;

use AE::AdHoc;

lives_ok {
	ae_recv { } soft_timeout => 0.1
} "soft timeout";

throws_ok {
	ae_recv { } timeout => 0.1
} qr(Timeout.*seconds), "hard timeout in options";

t/20-ae_action.t  view on Meta::CPAN

#!/usr/bin/perl -w

use strict;
use Test::More tests => 5;
use Test::Exception;

use AE::AdHoc;

my @res;
ae_recv {
	ae_action { push @res, @_ } after=>0.03, interval =>0.1;
} soft_timeout=>0.2;

is_deeply (\@res, [ 0, 1 ], "Timer fired twice");

my $x;
ae_recv {
	ae_action { $x++ };
	ok (!$x, "Action didn't work yet");
} soft_timeout=>0.2;

is ($x, 1, "Action w/o parameters works (finally)");
is_deeply (\@res, [ 0, 1 ], "Timer *still* fired twice");

is_deeply (\@AE::AdHoc::errors, [], "No errors in this test");

t/boilerplate.t  view on Meta::CPAN

#!perl -T

use strict;
use warnings;
use Test::More tests => 3;

sub not_in_file_ok {
    my ($filename, %regex) = @_;
    open( my $fh, '<', $filename )
        or die "couldn't open $filename for reading: $!";

    my %violated;

    while (my $line = <$fh>) {
        while (my ($desc, $regex) = each %regex) {
            if ($line =~ $regex) {
                push @{$violated{$desc}||=[]}, $.;
            }
        }
    }

    if (%violated) {
        fail("$filename contains boilerplate text");
        diag "$_ appears on lines @{$violated{$_}}" for keys %violated;
    } else {
        pass("$filename contains no boilerplate text");
    }
}

sub module_boilerplate_ok {
    my ($module) = @_;
    not_in_file_ok($module =>
        'the great new $MODULENAME'   => qr/ - The great new /,
        'boilerplate description'     => qr/Quick summary of what the module/,
        'stub function definition'    => qr/function[12]/,
    );
}

TODO: {
#  local $TODO = "Need to replace the boilerplate text";

  not_in_file_ok(README =>
    "The README is used..."       => qr/The README is used/,
    "'version information here'"  => qr/to provide version information/,
  );

  not_in_file_ok(Changes =>
    "placeholder date/time"       => qr(Date/time)
  );

  module_boilerplate_ok('lib/AE/AdHoc.pm');


}

t/manifest.t  view on Meta::CPAN

#!perl -T

use strict;
use warnings;
use Test::More;

unless ( $ENV{RELEASE_TESTING} ) {
    plan( skip_all => "Author tests not required for installation" );
}

eval "use Test::CheckManifest 0.9";
plan skip_all => "Test::CheckManifest 0.9 required" if $@;
ok_manifest();

t/pod-coverage.t  view on Meta::CPAN

use strict;
use warnings;
use Test::More;

# Ensure a recent version of Test::Pod::Coverage
my $min_tpc = 1.08;
eval "use Test::Pod::Coverage $min_tpc";
plan skip_all => "Test::Pod::Coverage $min_tpc required for testing POD coverage"
    if $@;

# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version,
# but older versions don't recognize some common documentation styles
my $min_pc = 0.18;
eval "use Pod::Coverage $min_pc";
plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage"
    if $@;

all_pod_coverage_ok();

t/pod.t  view on Meta::CPAN

#!perl -T

use strict;
use warnings;
use Test::More;

# Ensure a recent version of Test::Pod
my $min_tp = 1.22;
eval "use Test::Pod $min_tp";
plan skip_all => "Test::Pod $min_tp required for testing POD" if $@;

all_pod_files_ok();

 view all matches for this distribution
 view release on metacpan -  search on metacpan

( run in 2.132 seconds using v1.00-cache-2.02-grep-82fe00e-cpan-72ae3ad1e6da )