Generator-Object
view release on metacpan or search on metacpan
lib/Generator/Object.pm view on Meta::CPAN
my $gen = Generator::Object->new(sub{...; $_->yield});
Takes a subref which is the body of the generator. Returns an instance of
L<Generator::Object>.
=cut
sub new {
my $class = shift;
my $sub = shift;
return bless { sub => $sub, retval => [] }, $class;
}
=head1 METHODS
=head2 exhausted
while (1) {
next if defined $gen->next;
print "Done\n" if $gen->exhausted;
}
When the generator is exhausted the C<next> method will return C<undef>.
However, since C<next> might legitimately return C<undef>, this method is
provided to check that the generator has indeed been exhausted. If the
generator is restarted, then this method will again returns false.
=cut
sub exhausted { shift->{exhausted} }
=head2 next
my $first = $gen->next;
my $second = $gen->next;
This method iterates the generator until C<yield> is called or the body is
returned from. It returns any value passed to C<yield>, in list context all
arguments are returned, in scalar context the first argument is returned. The
context of the C<next> call is available from the C<wantarray> method for more
manual control.
When the generator is exhausted, that is to say, when the body function
returns, C<next> returns C<undef>. Check C<exhausted> to differentiate between
exhaustion and a yielded C<undef>. Any values returned from the body are
available via the C<retval> method, again list return is emulated and the
C<wantarray> method (of the final C<next> call) can be checked when returning.
=cut
sub next {
my $self = shift;
return undef if $self->exhausted;
# protect some state values from leaking
local $self->{orig} = $Coro::current;
local $self->{wantarray} = wantarray;
local $self->{yieldval};
$self->{coro} = Coro->new(sub {
local $_ = $self;
$self->{retval} = [ $self->{sub}->() ];
$self->{exhausted} = 1;
$self->{orig}->schedule_to;
}) unless $self->{coro};
$self->{coro}->schedule_to;
my $yield = $self->{yieldval} || [];
return $self->{wantarray} ? @$yield : $yield->[0];
}
=head2 restart
my $gen = generator { my $x = 1; $_->yield($x++) while 1 };
my $first = $gen->next;
$gen->restart;
$first == $gen->next; # true
Restarts the generator to its initial state. Of course if your generator has
made external changes, those will remain. Any values in C<retval> are cleared
and C<exhausted> is reset (if applicable).
Note: C<restart> is no longer implicitly called when C<next> is invoked on an
exhasted generator. You may recreate the old behavior by simply doing
$gen->restart if $gen->exhausted;
=cut
sub restart {
my $self = shift;
delete $self->{coro};
delete $self->{exhausted};
$self->{retval} = [];
}
=head2 retval
my $gen = generator { return 'val' };
$gen->next;
my $val = $gen->retval; # 'val'
Returns the value or values returned from the generator upon exhaustion if any.
In list context all returned values are given, in scalar context the first
element is returned. Note that the context in which C<next> was called as the
generator is exhausted is available via the C<wantarray> method for manual
control.
Before the generator is exhausted (and therefore before it has really returned
anything) the value of retval is C<undef> in scalar context and an empty list
in list context. Note that version 0.01 returned C<undef> in both contexts but
this has been corrected in version 0.02.
=cut
sub retval {
my $self = shift;
return undef unless $self->{retval};
return
wantarray
? @{ $self->{retval} }
: $self->{retval}[0];
}
=head2 wantarray
my $gen = generator {
while (1) {
$_->wantarray
? $_->yield('next called in list context')
: $_->yield('next called in scalar context');
}
}
my ($list) = $gen->next;
my $scalar = $gen->next;
Much like the Perl built-in of the same name, this method provides the context
in which the C<next> method is called, making that information available to the
generator body.
=cut
sub wantarray { shift->{wantarray} }
=head2 yield
my $gen = generator { ...; $_->yield($val) while 1 };
This method is the guts of the generator. When called C<yield> suspends the
state of the interpreter as it exists inside the generator body and returns to
the point at which C<next> was called. The values passed will be returned by
( run in 1.104 second using v1.01-cache-2.11-cpan-140bd7fdf52 )