File Coverage

blib/lib/Generator/Object.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Generator::Object;
2              
3             =head1 NAME
4              
5             Generator::Object - Generator objects for Perl using Coro
6              
7             =head1 SYNOPSIS
8              
9             use strict; use warnings;
10             use Generator::Object;
11              
12             my $gen = generator {
13             my $x = 0;
14             while (1) {
15             $x += 2;
16             $_->yield($x);
17             }
18             };
19              
20             print $gen->next; # 2
21             print $gen->next; # 4
22              
23             =head1 DESCRIPTION
24              
25             L provides a class for creating Python-like generators for
26             Perl using C. Calling the C method will invoke the generator, while
27             inside the generator body, calling the C method on the object will
28             suspend the interpreter and return execution to the main thread. When C
29             is called again the execution will return to the point of the C inside
30             the generator body. Arguments passed to C are returned from C.
31             This pattern allows for long-running processes to return values, possibly
32             forever, with lazy evaluation.
33              
34             For convenience the generator object is provided to the function body as C<$_>.
35             Further the context of the C method call is provided via the C
36             object method. When/if the generator is exhausted, the C method will
37             return C and the C method will return true. Any return value
38             from the body will then be available from the C method. The generator
39             may be restarted at any time by using the C method. C will
40             be empty after the generator restarts.
41              
42             Note: in version 0.01 of this module the generator would automatically
43             restart when calling C again after it was exhausted. This behavior was
44             removed in version 0.02 because upon reflection this is not usually what the
45             author means and since C is available it can be done manually.
46              
47             The internals of the object are entirely off-limits and where possible they
48             have been hidden to prevent access. No subclass api is presented nor planned.
49             The use of L internally shouldn't interfere with use of L
50             externally.
51              
52             =cut
53              
54 2     2   25912 use strict;
  2         3  
  2         51  
55 2     2   7 use warnings;
  2         2  
  2         72  
56              
57             our $VERSION = '0.02';
58             $VERSION = eval $VERSION;
59              
60 2     2   1707 use Coro ();
  0            
  0            
61              
62             =head1 EXPORTS
63              
64             =head2 generator
65              
66             my $gen = generator { ...; $_->yield($val) while 1 };
67              
68             Convenience function for creating instances of L. Takes a
69             block (subref) which is the body of the generator. Returns an instance of
70             L.
71              
72             =cut
73              
74             sub import {
75             my $class = shift;
76             my $caller = caller;
77              
78             no strict 'refs';
79             *{"${caller}::generator"} = sub (&) {
80             my $sub = shift;
81             return $class->new($sub);
82             };
83              
84             # yield??
85             }
86              
87             =head1 CONSTRUCTOR
88              
89             =head2 new
90              
91             my $gen = Generator::Object->new(sub{...; $_->yield});
92              
93             Takes a subref which is the body of the generator. Returns an instance of
94             L.
95              
96             =cut
97              
98             sub new {
99             my $class = shift;
100             my $sub = shift;
101             return bless { sub => $sub, retval => [] }, $class;
102             }
103              
104             =head1 METHODS
105              
106             =head2 exhausted
107              
108             while (1) {
109             next if defined $gen->next;
110             print "Done\n" if $gen->exhausted;
111             }
112              
113             When the generator is exhausted the C method will return C.
114             However, since C might legitimately return C, this method is
115             provided to check that the generator has indeed been exhausted. If the
116             generator is restarted, then this method will again returns false.
117              
118             =cut
119              
120             sub exhausted { shift->{exhausted} }
121              
122             =head2 next
123              
124             my $first = $gen->next;
125             my $second = $gen->next;
126              
127             This method iterates the generator until C is called or the body is
128             returned from. It returns any value passed to C, in list context all
129             arguments are returned, in scalar context the first argument is returned. This
130             emulates returning a list. The context of the C call is available from
131             the C method for more manual control.
132              
133             When the generator is exhausted, that is to say, when the body function
134             returns, C returns C. Check C to differentiate between
135             exhaustion and a yielded C. Any values returned from the body are
136             available via the C method, again list return is emulated and the
137             C method (of the final C call) can be checked when returning.
138              
139             =cut
140              
141             sub next {
142             my $self = shift;
143             return undef if $self->exhausted;
144              
145             # protect some state values from leaking
146             local $self->{orig} = $Coro::current;
147             local $self->{wantarray} = wantarray;
148             local $self->{yieldval};
149              
150             $self->{coro} = Coro->new(sub {
151             local $_ = $self;
152             $self->{retval} = [ $self->{sub}->() ];
153             $self->{exhausted} = 1;
154             $self->{orig}->schedule_to;
155             }) unless $self->{coro};
156              
157             $self->{coro}->schedule_to;
158              
159             return
160             $self->{wantarray}
161             ? @{ $self->{yieldval} }
162             : $self->{yieldval}[0];
163             }
164              
165             =head2 restart
166              
167             my $gen = generator { my $x = 1; $_->yield($x++) while 1 };
168             my $first = $gen->next;
169             $gen->restart;
170             $first == $gen->next; # true
171              
172             Restarts the generator to its initial state. Of course if your generator has
173             made external changes, those will remain. Any values in C are cleared
174             and C is reset (if applicable).
175              
176             Note: C is no longer implicitly called when C is invoked on an
177             exhasted generator. You may recreate the old behavior by simply doing
178              
179             $gen->restart if $gen->exhausted;
180              
181             =cut
182              
183             sub restart {
184             my $self = shift;
185             delete $self->{coro};
186             delete $self->{exhausted};
187             $self->{retval} = [];
188             }
189              
190             =head2 retval
191              
192             my $gen = generator { return 'val' };
193             $gen->next;
194             my $val = $gen->retval; # 'val'
195              
196             Returns the value or values returned from the generator upon exhaustion if any.
197             In list context all returned values are given, in scalar context the first
198             element is returned. This emulates returning a list. Note that the context in
199             which C was called as the generator is exhausted is available via the
200             C method for manual control.
201              
202             Before the generator is exhausted (and therefore before it has really returned
203             anything) the value of retval is C in scalar context and an empty list
204             in list context. Note that version 0.01 returned C in both contexts but
205             this has been corrected in version 0.02.
206              
207             =cut
208              
209             sub retval {
210             my $self = shift;
211             return undef unless $self->{retval};
212             return
213             wantarray
214             ? @{ $self->{retval} }
215             : $self->{retval}[0];
216             }
217              
218             =head2 wantarray
219              
220             my $gen = generator {
221             while (1) {
222             $_->wantarray
223             ? $_->yield('next called in list context')
224             : $_->yield('next called in scalar context');
225             }
226             }
227              
228             my ($list) = $gen->next;
229             my $scalar = $gen->next;
230              
231             Much like the Perl built-in of the same name, this method provides the context
232             in which the C method is called, making that information available to the
233             generator body.
234              
235             =cut
236              
237             sub wantarray { shift->{wantarray} }
238              
239             =head2 yield
240              
241             my $gen = generator { ...; $_->yield($val) while 1 };
242              
243             This method is the guts of the generator. When called C suspends the
244             state of the interpreter as it exists inside the generator body and returns to
245             the point at which C was called. The values passed will be returned by
246             C (see its documentation for more).
247              
248             This method should not be called outside the generator body. For now, doing
249             so dies. In the future though this might change to be a safer no-op in the
250             future, or else the method may only be made available inside the body as
251             safe-guards. In the meantime, just don't do it!
252              
253             =cut
254              
255             sub yield {
256             my $self = shift;
257             die "Must not call yield outside the generator!\n"
258             unless $self->{orig};
259              
260             $self->{yieldval} = [ @_ ];
261             $self->{orig}->schedule_to;
262             }
263              
264             =head1 FUTURE WORK
265              
266             I intend (possibly soon) to allow arguments to be passed to the generator body
267             possibly even on every call to C. Stay tuned.
268              
269             =head1 SEE ALSO
270              
271             =over
272              
273             =item L
274              
275             =back
276              
277             A few similar modules already exist. Their API and design choices weren't to my
278             liking, but they may appeal to you. Certainly I used them as reference and
279             thanks are due.
280              
281             =over
282              
283             =item L
284              
285             =item L
286              
287             =back
288              
289             =head1 SOURCE REPOSITORY
290              
291             L
292              
293             =head1 AUTHOR
294              
295             Joel Berger, Ejoel.a.berger@gmail.comE
296              
297             =head1 COPYRIGHT AND LICENSE
298              
299             Copyright (C) 2013-2015 by Joel Berger
300              
301             This library is free software; you can redistribute it and/or modify
302             it under the same terms as Perl itself.
303              
304             =cut
305              
306             1;
307