Data-Enumerable-Lazy

 view release on metacpan or  search on metacpan

lib/Data/Enumerable/Lazy.pm  view on Meta::CPAN

fewer than N elements in the enumerable, the entire enumerable would be
returned as a list.

=cut

sub take {
  my ($self, $slice_size) = @_;
  my $ix = 0;
  my @acc;
  push @acc, $self->next() while ($self->has_next() && $ix++ < $slice_size);
  return \@acc;
}

=head2 take_while($callback)

This function takes elements until it meets the first one that does not
satisfy the conditional callback.
The callback takes only 1 argument: an element. It should return true if
the element should be taken. Once it returned false, the stream is over.

=cut

sub take_while {
  my ($self, $callback) = @_;
  my $next_el;
  my $prev_has_next;
  my $initialized = 0;
  Data::Enumerable::Lazy->new({
    on_has_next => sub {
      $initialized = 1;
      defined $prev_has_next
        and return $prev_has_next;
      $prev_has_next = 0;
      if ($self->has_next()) {
        $next_el = $self->next();
        if ($callback->($next_el)) {
          $prev_has_next = 1;
        }
      }
      return $prev_has_next;
    },
    on_next => sub {
      my ($new_self) = @_;
      $initialized or $new_self->has_next();
      $prev_has_next
        or return $new_self->yield(Data::Enumerable::Lazy->empty());
      undef $prev_has_next;
      $new_self->yield($next_el);
    },
    is_finite => $self->is_finite(),
  });
}

=head2 continue($ext = %{ on_next => sub {}, ... })

Creates a new enumerable by extending the existing one. on_next is
the only manfatory argument. on_has_next might be overriden if some
custom logic comes into play.

is_finite is inherited from the parent enumerable by default. All additional
attributes would be transparently passed to the constuctor.

=cut

sub continue {
  my ($this, $ext) = @_;
  my %ext = %$ext;
  my $on_next = delete $ext{on_next}
    or croak '`on_next` should be defined on stream continuation';
  ref($on_next) eq 'CODE'
    or croak '`on_next` should be a function';
  Data::Enumerable::Lazy->new({
    on_next => sub {
      my $self = shift;
      $self->yield(
        $this->has_next() ?
          $on_next->($self, $this->next()) :
          Data::Enumerable::Lazy->empty
      );
    },
    on_has_next => delete $ext->{on_has_next} // $this->on_has_next(),
    is_finite   => delete $ext->{is_finite}   // $this->is_finite(),
    no_wrap     => delete $ext->{no_wrap}     // 0,
    %ext,
  });
}

=head2 count()

Counts the number of the elements in the stream. This method iterates through
the stream so it makes it exhausted by the end of the computatuion.

=cut

sub count {
  my ($self) = @_;
  croak 'Only finite enumerables might be counted. Use is_finite=1'
    unless $self->is_finite();
  my $cnt = 0;
  for (; $self->has_next(); $self->next()) {
    $cnt++;
  }
  return $cnt;
}

=head2 yield($result)

This method is supposed to be called from C<on_next> callback only. This is
the only valid result for an Enumerable to return the next step result.
Effectively, it ensures the returned result conforms to the required interface
and is wrapped in a lazy wrapper if needed.

=cut

sub yield {
  my $self = shift;
  my $val = shift;
  my $val_is_stream = $val && ref($val) eq 'Data::Enumerable::Lazy' &&
    $val->isa('Data::Enumerable::Lazy');
  if ($self->no_wrap() || $val_is_stream) {
    return $val;



( run in 2.933 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )