File Coverage

blib/lib/AE/AdHoc.pm
Criterion Covered Total %
statement 96 98 97.9
branch 35 40 87.5
condition 13 16 81.2
subroutine 24 24 100.0
pod 6 6 100.0
total 174 184 94.5


line stmt bran cond sub pod time code
1             package AE::AdHoc;
2              
3 12     12   703684 use warnings;
  12         109  
  12         336  
4 12     12   53 use strict;
  12         19  
  12         400  
5              
6             =head1 NAME
7              
8             AE::AdHoc - Simplified interface for tests/examples of AnyEvent-related code.
9              
10             =head1 NON-DESCRIPTION
11              
12             This module is NOT for introducing oneself to AnyEvent, despite the mention of
13             "simplified". More over, it REQUIRES knowledge of what a conditional variable,
14             or simply "condvar", is. See L.
15              
16             This module is NOT for building other modules, it's for running them with
17             minimal typing.
18              
19             =head1 SYNOPSIS
20              
21             Suppose we have a subroutine named C
22             that is designed to run under AnyEvent. As do_stuff may have to wait for
23             some external events to happen, it does not return a value right away.
24             Instead, it will call C<$subref-E( $results )> when stuff is done.
25              
26             Now we need to test do_stuff, so we set up an event loop. We also need a timer,
27             because a test that runs forever is annoying. So the script goes like this:
28              
29             use AnyEvent;
30              
31             # set up event loop
32             my $cv = AnyEvent->condvar;
33             my $timer = AnyEvent->timer(
34             after => 10, cb => sub { $cv->croak("Timeout"); }
35             );
36              
37             do_stuff( @args, sub{ $cv->send(shift); } );
38              
39             # run event loop, get rid of timer
40             my $result = $cv->recv();
41             undef $timer;
42              
43             # finally
44             analyze_results( $result );
45              
46             Now, the same with AE::AdHoc:
47              
48             use AE::AdHoc;
49              
50             my $result = ae_recv {
51             do_stuff( @args, ae_send );
52             } 10; # timeout
53             analyze_results( $result );
54              
55             =head1 EXPORT
56              
57             Functions C, C, C, C, C, and
58             C are exported by default.
59              
60             =head1 SUBROUTINES
61              
62             B: Anywhere below, C<$cv> means L's conditional variable
63             responsible for current event loop. See C section of L.
64              
65             =cut
66              
67             our $VERSION = '0.09';
68              
69 12     12   51 use Carp;
  12         17  
  12         580  
70 12     12   4139 use AnyEvent::Strict;
  12         196243  
  12         351  
71 12     12   80 use Scalar::Util qw(weaken looks_like_number);
  12         22  
  12         573  
72              
73 12     12   58 use Exporter;
  12         17  
  12         608  
74              
75             BEGIN {
76 12     12   241 our @ISA = qw(Exporter);
77 12         5528 our @EXPORT = qw(ae_recv ae_send ae_croak ae_begin ae_end ae_goal ae_action);
78             };
79              
80             =head2 ae_recv { CODE; } [ $timeout ] %options;
81              
82             The main entry point of the module.
83              
84             Run CODE block, enter event loop and wait for $timeout seconds for callbacks
85             set up in CODE to fire, then die. Return whatever was sent via C.
86              
87             $timeout must be a nonzero real number. Negative value means "run forever".
88             $timeout=0 would be ambigous, so it's excluded.
89              
90             Options may include:
91              
92             =over
93              
94             =item * timeout - override the $timeout parameter (one timeout MUST be present).
95              
96             =item * soft_timeout - Override $timeout, and don't die,
97             but return undef instead.
98              
99             =back
100              
101             Other functions in this module would die if called outside of C.
102              
103             =cut
104              
105             # $cv is our so that it can be localized and act as a lock
106             our $cv;
107              
108             # These are for error pretty-printing.
109             my $iter; # ++ every time
110             our $where; # "$file:$line[$iter]"
111              
112             sub ae_recv (&@) { ## no critic
113 28     28 1 12441 my $code = shift;
114 28   66     144 my $timeout = @_ % 2 && shift; # load bare timeout if present
115 28         59 my %opt = @_;
116              
117 28   100     178 $timeout = $opt{timeout} || $opt{soft_timeout} || $timeout;
118              
119             # check we're not in event loop before dying
120 28 100       92 $cv and _croak("Nested calls to ae_recv are not allowed");
121 27         203 local $cv = AnyEvent->condvar;
122              
123 27 100 100     2705 croak "Parameter timeout must be a nonzero real number"
124             if (!$timeout or !looks_like_number($timeout));
125              
126             # find out where we are
127 25         43 $iter++;
128 25         77 my @caller = caller(0);
129 25         686 local $where = "ae_recv[$iter] at $caller[1]:$caller[2]";
130              
131             my $on_timeout = $opt{soft_timeout}
132 3     3   258894 ? sub { $cv->send }
133 25 100   8   127 : sub { $cv->croak("Timeout after $timeout seconds"); };
  8         327941  
134 25         41 my $timer;
135 25 50       163 $timeout > 0 and $timer = AnyEvent->timer( after => $timeout,
136             cb => $on_timeout,
137             );
138 25         906 _clear_goals();
139 25         59 $code->();
140 24         1068 return $cv->recv;
141             # on exit, $timer is autodestroyed
142             # on exit, $cv is restored => destroyed
143             };
144              
145             =head2 ae_send ( [@fixed_args] )
146              
147             Create callback for normal event loop ending.
148              
149             Returns a sub that feeds its arguments to C<$cv-Esend()>. Arguments given to
150             the function itself are prepended, as in
151             C<$cv-Esend(@fixed_args, @callback_args)>.
152              
153             B that ae_recv will return all sent data "as is" in list context, and
154             only first argument in scalar context.
155              
156             May be called as ae_send->( ... ) if you want to stop event loop immediately
157             (i.e. in a handcrafted callback).
158              
159             =head2 ae_croak ( [$fixed_error] )
160              
161             Create callback for event loop termination.
162              
163             Returns a sub that feeds its first argument to $cv->croak(). If argument is
164             given, it will be used instead.
165              
166             =head2 ae_begin ( [ sub { ... } ] )
167              
168             =head2 ae_end
169              
170             These subroutines provide ability to wait for several events to complete.
171              
172             The AnyEvent's condition variable has a counter that is incremented by
173             C and decreased by C. Optionally, the C function
174             may also set a callback.
175              
176             Whenever the counter reaches zero, either that callback or just C is
177             executed on the condvar.
178              
179             B: If you do provide callback and want the event loop to stop there,
180             consider putting C( ... )> somewhere inside the callback.
181              
182             B: C acts at once, and does NOT return a closure. ae_end,
183             however, returns a subroutine reference just like C/C do.
184              
185             See begin/end section in L.
186              
187             =cut
188              
189             # set prototypes
190             sub ae_send (@); ## no critic
191             sub ae_croak (;$); ## no critic
192             sub ae_end (); ## no critic
193              
194             # define ae_send, ae_croak and ae_end at once
195             foreach my $action (qw(send croak end)) {
196             my $name = "ae_$action";
197             my $code = sub {
198 17     17   27833 my @args = @_;
199              
200 17 100       104 croak("$name called outside ae_recv") unless $cv;
201 16         24 my $myiter = $iter; # remember where cb was created
202              
203 16         37 my @caller = caller(0);
204 16         341 my $exact = "$name at $caller[1]:$caller[2] from $where";
205              
206 16 50       42 carp "Useless use of callback $name in void context, use $name->(...) to return immediately"
207             unless defined wantarray;
208              
209             return sub {
210 16 100   16   100755 return _error( "Leftover $exact called outside ae_recv" )
211             unless $cv;
212 15 100       43 return _error( "Leftover $exact called in $where")
213             unless $iter == $myiter;
214 14         93 $cv->$action(@args, @_);
215 16         113 }; # end closure
216             }; # end generated sub
217 12     12   80 no strict 'refs'; ## no critic
  12         20  
  12         354  
218 12     12   54 no warnings 'prototype'; ## no critic
  12         21  
  12         8148  
219             *{$name} = $code;
220             };
221              
222             sub ae_begin(@) { ## no critic
223 6 100   6 1 649 croak("ae_begin called outside ae_recv") unless $cv;
224              
225 5         14 $cv->begin(@_);
226             };
227              
228              
229             =head1 ADVANCED MULTIPLE GOAL INTERFACE
230              
231             =head2 ae_goal( "name", @fixed_args )
232              
233             Create a named callback.
234              
235             When callback is created, a "goal" is set.
236              
237             When such callback is called, anything passed to it is saved in a special hash
238             as array reference (prepended with @fixed_args, if any).
239              
240             When all goals are completed, the hash of results is returned by C.
241              
242             If ae_send is called at some point, the list of incomplete and complete goals
243             is still available via C and C calls.
244              
245             The goals and results are reset every time upon entering ae_recv.
246              
247             =cut
248              
249             my %goals;
250             my %results;
251 25     25   37 sub _clear_goals { %goals = (); %results = (); };
  25         39  
252              
253             sub ae_goal {
254 14     14 1 1333 my ($name, @fixed_args) = @_;
255              
256 14 100       115 croak "ae_goal called outside ae_recv" unless $cv;
257 13         21 my $myiter = $iter;
258              
259 13         34 my @caller = caller(0);
260 13         357 my $exact = "ae_goal('$name') at $caller[1]:$caller[2] from $where";
261              
262 13 100       42 $goals{$name}++ unless $results{$name};
263             return sub {
264 9 100   9   3414 return _error( "Leftover $exact called outside ae_recv" )
265             unless $cv;
266 8 100       23 return _error( "Leftover $exact called in $where")
267             unless $iter == $myiter;
268 7   100     52 $results{$name} ||= [ @fixed_args, @_ ];
269 7         12 delete $goals{$name};
270 7 100       36 $cv->send(\%results) unless %goals;
271 13         82 };
272             };
273              
274             =head2 AE::AdHoc->goals
275              
276             Return goals not yet achieved as hash ref.
277              
278             =head2 AE::AdHoc->results
279              
280             Return results of completed goals as hash ref.
281              
282             =cut
283              
284 4     4 1 19 sub goals { return \%goals; };
285 6     6 1 3244 sub results { return \%results; };
286              
287             =head1 ADDITIONAL ROUTINES
288              
289             =head2 ae_action { CODE } %options
290              
291             Perform CODE after entering the event loop via ae_recv
292             (a timer is used internally).
293              
294             CODE will NOT run after current event loop is terminated (see ae_recv).
295              
296             Options may include:
297              
298             =over
299              
300             =item * after - delay before code execution (in seconds, may be fractional)
301              
302             =item * interval - delay between code executions (in seconds, may be fractional)
303              
304             =item * count - how many times to execute. If zero or omitted, means unlimited
305             execution when interval is given, and just one otherwise.
306              
307             =back
308              
309             =cut
310              
311             sub ae_action (&@) { ## no critic
312 2     2 1 14 my $code = shift;
313 2         5 my %opt = @_;
314              
315             # TODO copypaste from ae_goal, make a sub
316 2 50       35 croak "ae_action called outside ae_recv" unless $cv;
317 2         4 my $myiter = $iter;
318 2         6 my @caller = caller(0);
319 2         35 my $exact = "ae_action at $caller[1]:$caller[2] from $where";
320              
321 2   100     8 $opt{after} ||= 0;
322              
323 2         4 my $count = $opt{count};
324 2         3 my $inf = !$count;
325 2         3 my $n = 0;
326              
327 2         3 my $timer;
328             my $cb = sub {
329 4 50   4   75755 if (!$cv) {
330 0         0 undef $timer;
331 0         0 return _error( "Leftover $exact called outside ae_recv" );
332             };
333 4 100       27 $myiter == $iter or undef $timer;
334 4 50 33     13 $inf or $count-->0 or undef $timer;
335 4 100       40 $timer and $code->($n++);
336 2         8 };
337             $timer = AnyEvent->timer(
338 2         7 after=>$opt{after}, interval=>$opt{interval}, cb=>$cb);
339 2         54 return;
340             };
341              
342             =head1 ERROR HANDLING
343              
344             Dying within event loop is a bad idea, so we issue B and write
345             errors to magic variables. It is up to the user to check these variables.
346              
347             =over
348              
349             =item * C<$AE::AdHoc::errstr> - last error (as in L<::DBI>).
350              
351             =item * C<@AE::AdHoc::errors> - all errors.
352              
353             =item * C<$AE::AdHoc::warnings> - set this to false to suppress warnings.
354              
355             =back
356              
357             =cut
358              
359             our @errors;
360             our $errstr;
361             our $warnings = 1; # by default, complain loudly
362              
363             sub _error {
364 5     5   12 $errstr = shift;
365 5         13 push @errors, $errstr;
366 5 100       37 carp __PACKAGE__.": ERROR: $errstr" if $warnings;
367 5         706 return;
368             };
369             sub _croak {
370 1     1   2 _error(@_);
371 1         11 croak shift;
372             };
373              
374             =head1 CAVEATS
375              
376             This module is still under heavy development, and is subject to change.
377             Feature/change requests are accepted.
378              
379             =head2 Callback confinement
380              
381             If event loop is entered several times, the callbacks created in one
382             invocations will NOT fire in another. Instead, they'll issue a warning
383             and return (see "Error handling" below).
384              
385             Error message will be like C
386             called in ae_recv[2] at file:117>
387              
388             This is done so to isolate invocations as much as possible.
389              
390             However, detection of "this invocation" will go wrong if callback maker is
391             called in a callback itself. For instance, this will always work the same:
392              
393             # ...
394             callback => sub { ae_send->(@_); },
395             # ...
396              
397             =cut
398              
399             =head1 AUTHOR
400              
401             Konstantin S. Uvarin, C<< >>
402              
403             =head1 BUGS
404              
405             Please report any bugs or feature requests to C, or through
406             the web interface at L. I will be notified, and then you'll
407             automatically be notified of progress on your bug as I make changes.
408              
409             =head1 SUPPORT
410              
411             You can find documentation for this module with the perldoc command.
412              
413             perldoc AE::AdHoc
414              
415              
416             You can also look for information at:
417              
418             =over 4
419              
420             =item * github:
421              
422             L
423              
424             =item * RT: CPAN's request tracker
425              
426             L
427              
428             =item * AnnoCPAN: Annotated CPAN documentation
429              
430             L
431              
432             =item * CPAN Ratings
433              
434             L
435              
436             =item * Search CPAN
437              
438             L
439              
440             =back
441              
442             =head1 SEE ALSO
443              
444             L
445              
446             =head1 ACKNOWLEDGEMENTS
447              
448              
449             =head1 LICENSE AND COPYRIGHT
450              
451             Copyright 2012 Konstantin S. Uvarin.
452              
453             This program is free software; you can redistribute it and/or modify it
454             under the terms of either: the GNU General Public License as published
455             by the Free Software Foundation; or the Artistic License.
456              
457             See http://dev.perl.org/licenses/ for more information.
458              
459              
460             =cut
461              
462             1; # End of AE::AdHoc