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 )