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 )