Import Upstream version 0.02

This commit is contained in:
su-fang 2022-09-27 15:12:00 +08:00
commit 9ce9388092
17 changed files with 1891 additions and 0 deletions

7
Changes Normal file
View File

@ -0,0 +1,7 @@
Revision history for Perl extension Iterator.
0.01 2005 August 18
- First version
0.02 2005 August 23
- Fixed several documentation typos.

BIN
Iterator-Util-ppm.tar.gz Normal file

Binary file not shown.

13
Iterator-Util.ppd Normal file
View File

@ -0,0 +1,13 @@
<SOFTPKG NAME="Iterator-Util" VERSION="0,01,0,0">
<TITLE>Iterator-Util</TITLE>
<ABSTRACT>Essential utilities for the Iterator class.</ABSTRACT>
<AUTHOR>Eric Roode &lt;roode@cpan.org&gt;</AUTHOR>
<IMPLEMENTATION>
<DEPENDENCY NAME="Exception-Class" VERSION="1,21,0,0" />
<DEPENDENCY NAME="Iterator" VERSION="0,01,0,0" />
<DEPENDENCY NAME="Test-Simple" VERSION="0,40,0,0" />
<CODEBASE HREF="" />
</IMPLEMENTATION>
</SOFTPKG>

17
MANIFEST Normal file
View File

@ -0,0 +1,17 @@
Changes
Makefile.PL
MANIFEST
README
Util.pm
Iterator-Util.ppd
Iterator-Util-ppm.tar.gz
t/doc.t
t/iappend.t
t/iarray.t
t/ihead.t
t/ilist.t
t/imap.t
t/ipairwise.t
t/irange.t
t/iskip.t
META.yml Module meta-data (added by MakeMaker)

13
META.yml Normal file
View File

@ -0,0 +1,13 @@
# http://module-build.sourceforge.net/META-spec.html
#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
name: Iterator-Util
version: 0.02
version_from: Util.pm
installdirs: site
requires:
Exception::Class: 1.21
Iterator: 0.01
Test::Simple: 0.40
distribution_type: module
generated_by: ExtUtils::MakeMaker version 6.17

64
Makefile.PL Normal file
View File

@ -0,0 +1,64 @@
use ExtUtils::MakeMaker;
# See lib/ExtUtils/MakeMaker.pm for details of how to influence
# the contents of the Makefile that is written.
WriteMakefile(
'NAME' => 'Iterator::Util',
'VERSION_FROM' => 'Util.pm', # finds $VERSION
'PREREQ_PM' => {'Test::Simple' => '0.40',
'Exception::Class' => '1.21',
'Iterator' => '0.01',
},
($] >= 5.005 ? ## Add these new keywords supported since 5.005
(ABSTRACT_FROM => 'Util.pm', # retrieve abstract from module
AUTHOR => 'Eric Roode <roode@cpan.org>') : ()),
);
package MY;
sub dist_core
{
my $text = shift->SUPER::dist_core(@_);
$text =~ s/^(\$\(DISTVNAME\)[^:]*): (.*)/$1: ppd ppm $2/mg;
return $text;
}
sub realclean
{
my $text = shift->SUPER::realclean(@_);
$text .= <<'CLEAN';
rm -rf $(PPDFILE) $(PPMFILE)
CLEAN
return $text;
}
sub ppd
{
my $self = shift;
my $text = $self->SUPER::ppd(@_);
$text =~ s/(ppd\s*:)/$1 \$(PPDFILE)\n\n\$(PPDFILE) :/;
$text =~ s[(?<=<CODEBASE HREF=\\")]
[http://search.cpan.org/src/ROODE/$self->{DISTNAME}-$self->{VERSION}/$self->{DISTNAME}-ppm.tar.gz];
# This release is allegedly OS and architecture independent (as it's pure perl)
$text =~ s/<OS NAME[^>]+>(?:\\[nt])*//;
$text =~ s/<ARCHITECTURE NAME[^>]+>(?:\\[nt])*//;
$text = <<'PRE' . $text;
PPMNAME = $(DISTNAME)-ppm
PPDFILE = $(DISTNAME).ppd
PPMFILE = $(PPMNAME).tar.gz
PRE
$text .= <<'PPM';
ppm: $(PPMFILE)
$(PPMFILE): pm_to_blib $(INST_LIBDIR)/.exists $(INST_ARCHAUTODIR)/.exists $(INST_AUTODIR)/.exists
$(TAR) $(TARFLAGS) - blib | $(COMPRESS) -c > $(PPMFILE)
PPM
return $text;
}

69
README Normal file
View File

@ -0,0 +1,69 @@
Iterator::Util version 0.02
===========================
This module contains many useful utility functions for use with the
Iterator class (q.v.). The inspiration for many of these functions
has been Mark Jason Dominus's lectures and recent book (_Higher Order
Perl_, Morgan Kauffman, 2005).
An "iterator" is an object, represented as a code block that generates
the "next value" of a sequence, and generally implemented as a
closure. Iterator.pm provides a class that simplifies creation and
use of these iterator objects, and provides many general-purpose
iterator functions.
EXAMPLES
$it = irange (1, 3);
$i = $it->value; # returns 1
$i = $it->value; # returns 2
$i = $it->value; # returns 3
$i = $it->value; # throws an Iterator::X::Exhausted exception.
$another_it = imap {$_ * $_} irange (7, 10);
while ($another_it->isnt_exhausted)
{
print $another_it->value, "\n";
}
# The above prints 49, 64, 81, 100 and throws no exceptions.
# Another call to $another_it->value would throw an exception.
DEVELOPMENT STATE
This is a brand-new module. It has a decent test suite, but has
not been extensively field-tested. Therefore, it should be considered
"beta" software, and used with care.
If you find any bugs, or if any behavior of Iterator surprises you,
I would be grateful if you could send me an email message about it.
Thanks.
INSTALLATION
To install this module, do the standard Perl module four-step:
perl Makefile.PL or perl Makefile.pl LIB='my/install/path'
make
make test
make install
DEPENDENCIES
This module requires these other modules and libraries:
Iterator
COPYRIGHT AND LICENSE
Eric J. Roode, roode@cpan.org
To avoid my spam filter, please include "Perl", "module", or this
module's name in the message's subject line, and/or GPG-sign your
message.
Copyright (c) 2005 by Eric J. Roode. All Rights Reserved.
This module is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

806
Util.pm Normal file
View File

@ -0,0 +1,806 @@
=for gpg
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
=head1 NAME
Iterator::Util - Essential utilities for the Iterator class.
=head1 VERSION
This documentation describes version 0.02 of Iterator::Util, August 23, 2005.
=cut
use strict;
use warnings;
package Iterator::Util;
our $VERSION = '0.02';
use base 'Exporter';
use vars qw/@EXPORT @EXPORT_OK %EXPORT_TAGS/;
@EXPORT = qw(imap igrep irange ilist iarray ihead iappend
ipairwise iskip iskip_until imesh izip iuniq);
@EXPORT_OK = (@EXPORT);
use Iterator;
# Function name: imap
# Synopsis: $iter = imap {code} $another_iterator;
# Description: Transforms an iterator.
# Created: 07/27/2005 by EJR
# Parameters: code - Transformation code
# $another_iterator - any other iterator.
# Returns: Transformed iterator.
# Exceptions: Iterator::X::Parameter_Error
# Iterator::X::Am_Now_Exhausted
sub imap (&$)
{
my ($transformation, $iter) = @_;
Iterator::X::Parameter_Error->throw(q{Argument to imap must be an Iterator object})
unless UNIVERSAL::isa($iter, 'Iterator');
return Iterator->new( sub
{
Iterator::is_done if ($iter->is_exhausted);
local $_ = $iter->value ();
return $transformation-> ();
});
}
# Function name: igrep
# Synopsis: $iter = igrep {code} $another_iterator;
# Description: Filters an iterator.
# Created: 07/27/2005 by EJR
# Parameters: code - Filter condition.
# $another_iterator - any other iterator.
# Returns: Filtered iterator.
# Exceptions: Iterator::X::Parameter_Error
# Iterator::X::Am_Now_Exhausted
sub igrep (&$)
{
my ($test, $iter) = @_;
Iterator::X::Parameter_Error->throw(q{Argument to imap must be an Iterator object})
unless UNIVERSAL::isa($iter, 'Iterator');
return Iterator->new(sub
{
while ($iter->isnt_exhausted ())
{
local $_ = $iter->value ();
return $_ if $test-> ();
}
Iterator::is_done();
});
}
# Function name: irange
# Synopsis: $iter = irange ($start, $end, $step);
# Description: Generates an arithmetic sequence of numbers.
# Created: 07/27/2005 by EJR
# Parameters: $start - First value.
# $end - Final value. (may be omitted)
# $step - Increment value. (may be omitted)
# Returns: Sequence iterator
# Exceptions: Iterator::X::Am_Now_Exhausted
# Notes: If the $end value is omitted, iterator is unbounded.
# If $step is omitted, it defaults to 1.
# $step may be negative (or even zero).
sub irange
{
my ($from, $to, $step) = @_;
$step = 1 unless defined $step;
return Iterator->new (sub
{
# Reached limit?
Iterator::is_done
if (defined($to)
&& ($step>0 && $from>$to || $step<0 && $from<$to) );
# This iteration's return value
my $retval = $from;
$from += $step;
return $retval;
});
}
# Function name: ilist
# Synopsis: $iter = ilist (@list);
# Description: Creates an iterator from a list
# Created: 07/28/2005 by EJR
# Parameters: @list - list of values to iterate over
# Returns: Array (list) iterator
# Exceptions: Iterator::X::Am_Now_Exhausted
# Notes: Makes an internal copy of the list.
sub ilist
{
my @items = @_;
my $index=0;
return Iterator->new( sub
{
Iterator::is_done if ($index >= @items);
return $items[$index++];
});
}
# Function name: iarray
# Synopsis: $iter = iarray ($a_ref);
# Description: Creates an iterator from an array reference
# Created: 07/28/2005 by EJR
# Parameters: $a_ref - Reference to array to iterate over
# Returns: Array iterator
# Exceptions: Iterator::X::Parameter_Error
# Iterator::X::Am_Now_Exhausted
# Notes: Does not make an internal copy of the list.
sub iarray ($)
{
my $items = shift;
my $index=0;
Iterator::X::Parameter_Error->throw->
(q{Argument to iarray must be an array reference})
if ref $items ne 'ARRAY';
return Iterator->new( sub
{
Iterator::is_done if $index >= @$items;
return $items->[$index++];
});
}
# Function name: ihead
# Synopsis: $iter = ihead ($num, $some_other_iterator);
# Synopsis: @valuse = ihead ($num, $iterator);
# Description: Returns at most $num items from other iterator.
# Created: 07/28/2005 by EJR
# 08/02/2005 EJR: combined with ahead, per Will Coleda
# Parameters: $num - Max number of items to return
# $some_other_iterator - another iterator
# Returns: limited iterator
# Exceptions: Iterator::X::Parameter_Error
# Iterator::X::Am_Now_Exhausted
sub ihead
{
my $num = shift;
my $iter = shift;
Iterator::X::Parameter_Error->throw
(q{Second parameter for ihead must be an Iterator})
unless UNIVERSAL::isa($iter, 'Iterator');
# List context? Return the first $num elements.
if (wantarray)
{
my @a;
while ($iter->isnt_exhausted && (!defined($num) || $num-- > 0))
{
push @a, $iter->value;
}
return @a;
}
# Scalar context: return an iterator to return at most $num elements.
return Iterator->new(sub
{
Iterator::is_done if $num <= 0;
$num--;
return $iter->value;
});
}
# Function name: iappend
# Synopsis: $iter = iappend (@iterators);
# Description: Joins a bunch of iterators together.
# Created: 07/28/2005 by EJR
# Parameters: @iterators - any number of other iterators
# Returns: A "merged" iterator.
# Exceptions: Iterator::X::Parameter_Error
# Iterator::X::Am_Now_Exhausted
sub iappend
{
my @its = @_;
# Check types
foreach (@its)
{
Iterator::X::Parameter_Error->throw
(q{All parameters for iarray must be Iterators})
unless UNIVERSAL::isa($_, 'Iterator');
}
# Passthru, if there's only one.
return $its[0] if @its == 1;
return Iterator->new (sub
{
my $val;
# Any empty iterators at front of list? Remove'em.
while (@its && $its[0]->is_exhausted)
{
shift @its;
}
# No more iterators? Then we're done.
Iterator::is_done
if @its == 0;
# Return the next value of the iterator at the head of the list.
return $its[0]->value;
});
}
# Function name: ipairwise
# Synopsis: $iter = ipairwise {code} ($iter1, $iter2);
# Description: Applies an operation to pairs of values from iterators.
# Created: 07/28/2005 by EJR
# Parameters: code - transformation, may use $a and $b
# $iter1 - First iterator; "$a" value.
# $iter2 - First iterator; "$b" value.
# Returns: Iterator
# Exceptions: Iterator::X::Parameter_Error
# Iterator::X::Am_Now_Exhausted
sub ipairwise (&$$)
{
my $op = shift;
my $iterA = shift;
my $iterB = shift;
# Check types
for ($iterA, $iterB)
{
Iterator::X::Parameter_Error->throw
(q{Second and third parameters for ipairwise must be Iterators})
unless UNIVERSAL::isa($_, 'Iterator');
}
return Iterator->new(sub
{
Iterator::is_done
if $iterA->is_exhausted || $iterB->is_exhausted;
# Localize $a and $b
# My thanks to Benjamin Goldberg for this little bit of evil.
my ($caller_a, $caller_b) = do
{
my $pkg;
my $i = 1;
while (1)
{
$pkg = caller($i++);
last if $pkg ne 'Iterator' && $pkg ne 'Iterator::Util';
}
no strict 'refs';
\*{$pkg.'::a'}, \*{$pkg.'::b'};
};
# Set caller's $a and $b
local (*$caller_a, *$caller_b) = \($iterA->value, $iterB->value);
# Invoke caller's operation
return $op->();
});
}
# Function name: iskip
# Synopsis: $iter = iskip $num, $another_iterator
# Description: Skips the first $num values of another iterator
# Created: 07/28/2005 by EJR
# Parameters: $num - how many values to skip
# $another_iterator - another iterator
# Returns: Sequence iterator
# Exceptions: None
sub iskip
{
my $num = shift;
my $it = shift;
Iterator::X::Parameter_Error->throw
(q{Second parameter for iskip must be an Iterator})
unless UNIVERSAL::isa($it, 'Iterator');
# Discard first $num values
$it->value while $it->isnt_exhausted && $num-->0;
return $it;
}
# Function name: iskip_until
# Synopsis: $iter = iskip_until {code}, $another_iterator
# Description: Skips values of another iterator until {code} is true.
# Created: 07/28/2005 by EJR
# Parameters: {code} - Determines when to start returning values
# $another_iterator - another iterator
# Returns: Sequence iterator
# Exceptions: Iterator::X::Am_Now_Exhausted
sub iskip_until (&$)
{
my $code = shift;
my $iter = shift;
my $value;
my $found_it = 0;
Iterator::X::Parameter_Error->throw
(q{Second parameter for iskip_until must be an Iterator})
unless UNIVERSAL::isa($iter, 'Iterator');
# Discard first $num values
while ($iter->isnt_exhausted)
{
local $_ = $iter->value;
if ($code->())
{
$found_it = 1;
$value = $_;
last;
}
}
# Didn't find it? Pity.
Iterator::is_done
unless $found_it;
# Return an iterator with this value, and all remaining values.
return iappend ilist($value), $iter;
}
# Function name: imesh / izip
# Synopsis: $iter = imesh ($iter1, $iter2, ...)
# Description: Merges other iterators together.
# Created: 07/30/2005 by EJR
# Parameters: Any number of other iterators.
# Returns: Sequence iterator
# Exceptions: Iterator::X::Parameter_Error
# Iterator::X::Am_Now_Exhausted
foreach my $sub (qw/imesh izip/)
{
no strict 'refs';
*$sub = sub
{
use strict 'refs';
my @iterators = @_;
my $it_index = 0;
foreach my $iter (@iterators)
{
Iterator::X::Parameter_Error->throw(
"Argument to $sub is not an iterator")
unless UNIVERSAL::isa($iter, 'Iterator');
}
return Iterator->new (sub
{
Iterator::is_done
if $iterators[$it_index]->is_exhausted();
my $retval = $iterators[$it_index]->value();
if (++$it_index >= @iterators)
{
$it_index = 0;
}
return $retval;
});
};
}
# Function name: iuniq
# Synopsis: $iter = iuniq ($another_iterator);
# Description: Removes duplicate entries from an iterator.
# Created: 07/30/2005 by EJR
# Parameters: Another iterator.
# Returns: Sequence iterator
# Exceptions: Iterator::X::Parameter_Error
# Iterator::X::Am_Now_Exhausted
sub iuniq
{
Iterator::X::Parameter_Error->throw ("Too few parameters to iuniq")
if @_ < 1;
Iterator::X::Parameter_Error->throw ("Too many parameters to iuniq")
if @_ > 1;
my $iter = shift;
Iterator::X::Parameter_Error->throw("Argument to iuniq is not an iterator")
unless UNIVERSAL::isa($iter, 'Iterator');
my %did_see;
return Iterator->new (sub
{
my $value;
while (1)
{
Iterator::is_done
if $iter->is_exhausted;
$value = $iter->value;
last if !$did_see{$value}++;
}
return $value;
});
}
1;
__END__
=head1 SYNOPSIS
use Iterator::Util;
# Transform sequences
$iterator = imap { transformation code } $some_other_iterator;
# Filter sequences
$iterator = igrep { condition code } $some_other_iterator;
# Range of values (arithmetic sequence)
$iter = irange ($start, $end, $increment);
$iter = irange ($start, $end);
$iter = irange ($start);
# Iterate over an arbitrary list
$iter = ilist (item, item, ...);
$iter = ilist (@items);
# Iterate over an array, by reference
$iter = iarray (\@array);
# Return at most $num items from an iterator
$iter = ihead ($num, $some_other_iterator);
@values = ihead ($num, $some_other_iterator);
# Append multiple iterators into one
$iter = iappend ($it1, $it2, $it3, ...);
# Apply a function to pairs of iterator values
$iter = ipairwise {code} $iter_A, $iter_B;
# Skip the first $num values of an iterator
$iter = iskip ($num, $some_other_iterator);
# Skip values from an iterator until a condition is met
$iter = iskip_until {code} $some_other_iterator;
# Mesh iterators together
$iter = imesh ($iter, $iter, ...);
$iter = izip ($iter, $iter, ...);
# Return each value of an iterator once
$iter = iuniq ($another_iterator);
=head1 DESCRIPTION
This module implements many useful functions for creating and
manipulating iterator objects.
An "iterator" is an object, represented as a code block that generates
the "next value" of a sequence, and generally implemented as a
closure. For further information, including a tutorial on using
iterator objects, see the L<Iterator> documentation.
=head1 FUNCTIONS
=over 4
=item imap
$iter = imap { transformation code } $some_other_iterator;
Returns an iterator that is a transformation of some other iterator.
Within the transformation code, C<$_> is set to each value of the
other iterator, in turn.
I<Examples:>
$evens = imap { $_ * 2 } irange (0); # returns 0, 2, 4, ...
$squares = imap { $_ * $_ } irange (7); # 49, 64, 81, 100, ...
=item igrep
$iter = igrep { condition } $some_other_iterator;
Returns an iterator that selectively returns values from some other
iterator. Within the C<condition> code, C<$_> is set to each value of
the other iterator, in turn.
I<Examples:>
$fives = igrep { $_ % 5 == 0 } irange (0,10); # returns 0, 5, 10
$small = igrep { $_ < 10 } irange (8,12); # returns 8, 9
=item irange
$iter = irange ($start, $end, $increment);
$iter = irange ($start, $end);
$iter = irange ($start);
C<irange> returns a sequence of numbers. The sequence begins with
C<$start>, ends at C<$end>, and steps by C<$increment>. This is sort
of the Iterator version of a C<for> loop.
If C<$increment> is not specified, 1 is used. C<$increment> may be
negative -- or even zero, in which case iterator returns an infinite
sequence of C<$start>.
If C<$end> is not specified (is C<undef>), the sequence is infinite.
I<Examples:>
$iter = irange (1, 2); # Iterate from 1 to 2
$val = $iter->value(); # $val is now 1.
$val = $iter->value(); # $val is now 2.
$bool = $iter->is_exhausted(); # $bool is now true.
$iter = irange (10, 8, -1); # Iterate from 10 down to 8
$iter = irange (1); # Iterate from 1, endlessly.
=item ilist
$iter = ilist (@items);
Returns an iterator that iterates over an arbitrary sequence of
values. It's sort of an Iterator version of C<foreach>.
This function makes an internal copy of the list, so it may not be
appropriate for an extremely large list.
I<Example:>
$iter = ilist (4, 'minus five', @foo, 7);
$val = $iter->value(); # $val is now 4
$val = $iter->value(); # $val is now 'minus five'
...
=item iarray
$iter = iarray (\@array);
Returns an iterator that iterates over an array. Note that since it
uses a reference to that array, if you modify the array, that will be
reflected in the values returned by the iterator. This may be What
You Want. Or it may cause Hard-To-Find Bugs.
=item ihead
$iter = ihead ($num, $some_other_iterator);
@values = ihead ($num, $some_iterator);
In scalar context, creates an iterator that returns at most C<$num>
items from another iterator, then stops.
In list context, returns the first C<$num> items from the iterator.
If C<$num> is C<undef>, all remaining values are pulled
from the iterator until it is exhausted. Use C<undef> with caution;
iterators can be huge -- or infinite.
I<Examples:>
$iota5 = ihead 5, irange 1; # returns 1, 2, 3, 4, 5.
$iter = irange 1; # infinite sequence, starting with 1
@vals = ihead (5, $iter); # @vals is (1, 2, 3, 4, 5)
$nextval = $iter->value; # $nextval is 6.
=item iappend
$iter = iappend (@list_of_iterators);
Creates an iterator that consists of any number of other iterators
glued together. The resulting iterator pulls values from the first
iterator until it's exhausted, then from the second, and so on.
=item ipairwise
$iter = ipairwise {code} $it_A, $it_B;
Creates a new iterator which applies C<{code}> to pairs of elements of
two other iterators, C<$it_A> and C<$it_B> in turn. The pairs are
assigned to C<$a> and C<$b> before invoking the code.
The new iterator is exhausted when either C<$it_A> or C<$it_B> are
exhausted.
This function is analogous to the L<pairwise|List::MoreUtils/pairwise>
function from L<List::MoreUtils>.
I<Example:>
$first = irange 1; # 1, 2, 3, 4, ...
$second = irange 4, undef, 2; # 4, 6, 8, 10, ...
$third = ipairwise {$a * $b} $first, $second; # 4, 12, 24, 40, ...
=item iskip
$iter = iskip ($num, $another_iterator);
Returns an iterator that contains the values of C<$another_iterator>,
minus the first C<$num> values. In other words, skips the first
C<$num> values of C<$another_iterator>.
I<Example:>
$iter = ilist (24, -1, 7, 8); # Bunch of random values
$cdr = iskip 1, $iter; # "pop" the first value
$val = $cdr->value(); # $val is -1.
=item iskip_until
$iter = iskip_until {code} $another_iterator;
Returns an iterator that skips the leading values of C<$another_iterator>
until C<{code}> evaluates to true for one of its values. C<{code}>
can refer to the current value as C<$_>.
I<Example:>
$iter = iskip_until {$_ > 5} irange 1; # returns 6, 7, 8, 9, ...
=item imesh
=item izip
$iter = imesh ($iter1, $iter2, ...);
This iterator accepts any number of other iterators, and "meshes"
their values together. First it returns the first value of the first
iterator, then the first value of the second iterator, and so on,
until it has returned the first value of all of its iterator
arguments. Then it goes back and returns the second value of the
first iterator, and so on. It stops when any of its iterator
arguments is exhausted.
I<Example:>
$i1 = ilist ('a', 'b', 'c');
$i2 = ilist (1, 2, 3);
$i3 = ilist ('rock', 'paper', 'scissors');
$iter = imesh ($i1, $i2, $i3);
# $iter will return, in turn, 'a', 1, 'rock', 'b', 2, 'paper', 'c',...
C<izip> is a synonym for C<imesh>.
=item iuniq
$iter = iuniq ($another_iterator);
Creates an iterator to return unique values from another iterator;
weeds out duplicates.
I<Example:>
$iter = ilist (1, 2, 2, 3, 1, 4);
$uniq = iuniq ($iter); # returns 1, 2, 3, 4.
=back
=head1 EXPORTS
All function names are exported to the caller's namespace by default.
=head1 DIAGNOSTICS
Iterator::Util uses L<Exception::Class> objects for throwing
exceptions. If you're not familiar with Exception::Class, don't
worry; these exception objects work just like C<$@> does with C<die>
and C<croak>, but they are easier to work with if you are trapping
errors.
See the L<Iterator|Iterator/DIAGNOSTICS> module documentation for more
information on trapping and handling these exceptions.
=over 4
=item * Parameter Errors
Class: C<Iterator::X::Parameter_Error>
You called an Iterator method with one or more bad parameters. Since
this is almost certainly a coding error, there is probably not much
use in handling this sort of exception.
As a string, this exception provides a human-readable message about
what the problem was.
=item * Exhausted Iterators
Class: C<Iterator::X::Exhausted>
You called C<value|Iterator/value> on an iterator that is exhausted;
that is, there are no more values in the sequence to return.
As a string, this exception is "Iterator is exhausted."
=item * User Code Exceptions
Class: C<Iterator::X::User_Code_Error>
This exception is thrown when the sequence generation code throws any
sort of error besides C<Am_Now_Exhausted>. This could be because your
code explicitly threw an error (that is, C<die>d), or because it
otherwise encountered an exception (any runtime error).
This exception has one method, C<eval_error>, which returns the
original C<$@> that was trapped by the Iterator object. This may be a
string or an object, depending on how C<die> was invoked.
As a string, this exception evaluates to the stringified C<$@>.
=item * I/O Errors
Class: C<Iterator::X::IO_Error>
This exception is thrown when any sort of I/O error occurs; this
only happens with the filesystem iterators.
This exception has one method, C<os_error>, which returns the original
C<$!> that was trapped by the Iterator object.
As a string, this exception provides some human-readable information
along with C<$!>.
=item * Internal Errors
Class: C<Iterator::X::Internal_Error>
Something happened that I thought couldn't possibly happen. I would
appreciate it if you could send me an email message detailing the
circumstances of the error.
=back
=head1 REQUIREMENTS
Requires the following additional modules:
L<Iterator>
=head1 SEE ALSO
I<Higher Order Perl>, Mark Jason Dominus, Morgan Kauffman 2005.
L<http://perl.plover.com/hop/>
=head1 THANKS
Much thanks to Will Coleda and Paul Lalli (and the RPI lily crowd in
general) for suggestions for the pre-release version.
=head1 AUTHOR / COPYRIGHT
Eric J. Roode, roode@cpan.org
Copyright (c) 2005 by Eric J. Roode. All Rights Reserved.
This module is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
To avoid my spam filter, please include "Perl", "module", or this
module's name in the message's subject line, and/or GPG-sign your
message.
=cut
=begin gpg
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (Cygwin)
iD8DBQFDC5UFY96i4h5M0egRApNiAJ9WwoZql+2DE+RsSA6koGLZPcbQZACfY248
VoKah+WAFOvk46vOcn+hL9Y=
=aOws
-----END PGP SIGNATURE-----
=end gpg

220
t/doc.t Normal file
View File

@ -0,0 +1,220 @@
use strict;
use Test::More tests => 33;
use Iterator::Util;
# Check that the documentation examples work.
my @vals;
## From the POD
# $evens (3);
{
my $evens;
@vals = ();
eval
{
$evens = imap { $_ * 2 } irange (0); # returns 0, 2, 4, ...
};
is ($@, q{}, q{$evens created fine});
eval
{
push @vals, $evens->value for (1..3);
};
is ($@, q{}, q{$evens executed fine});
is_deeply(\@vals, [0, 2, 4], q{$evens returns what I said it would});
}
# $squares (3)
{
my $squares;
@vals = ();
eval
{
$squares = imap { $_ * $_ } irange (7); # 49, 64, 81, 100, ...
};
is ($@, q{}, q{$squares created fine});
eval
{
push @vals, $squares->value for (1..4);
};
is ($@, q{}, q{$squares created fine});
is_deeply(\@vals, [49, 64, 81, 100], q{$squares returns what I said it would});
}
# $fives (3)
{
my $fives;
@vals = ();
eval
{
$fives = igrep { $_ % 5 == 0 } irange (0,10); # returns 0, 5, 10
};
is ($@, q{}, q{$fives created fine});
eval
{
push @vals, $fives->value while $fives->isnt_exhausted;
};
is ($@, q{}, q{$fives created fine});
is_deeply(\@vals, [0, 5, 10], q{$fives returns what I said it would});
}
# $small (3)
{
my $small;
@vals = ();
eval
{
$small = igrep { $_ < 10 } irange (8,12); # returns 8, 9
};
is ($@, q{}, q{$small created fine});
eval
{
push @vals, $small->value while $small->isnt_exhausted;
};
is ($@, q{}, q{$small executed fine});
is_deeply(\@vals, [8, 9], q{$small returns what I said it would});
}
# $iota5 (3)
{
my $iota5;
@vals = ();
eval
{
$iota5 = ihead 5, irange 1; # returns 1, 2, 3, 4, 5.
};
is ($@, q{}, q{$iota5 created fine});
eval
{
push @vals, $iota5->value while $iota5->isnt_exhausted;
};
is ($@, q{}, q{$iota5 executed fine});
is_deeply(\@vals, [1, 2, 3, 4, 5], q{$iota5 returns what I said it would});
}
# ipairwise (3)
{
my ($first, $second, $third);
@vals = ();
eval
{
no warnings 'once';
$first = irange 1; # 1, 2, 3, 4, ...
$second = irange 4, undef, 2; # 4, 6, 8, 10, ...
$third = ipairwise {$a * $b} $first, $second; # 4, 12, 24, 40, ...
};
is ($@, q{}, q{1, 2, 3 iterators created fine});
eval
{
push @vals, $third->value for (1..4);
};
is ($@, q{}, q{$third executed fine});
is_deeply(\@vals, [4, 12, 24, 40], q{$ithird returns what I said it would});
}
# $cdr (3)
{
my ($cdr);
@vals = ();
eval
{
my $iter = ilist (24, -1, 7, 8); # Bunch of random values
$cdr = iskip 1, $iter; # "pop" the first value
};
is ($@, q{}, q{$cdr iterators created fine});
eval
{
push @vals, $cdr->value while $cdr->isnt_exhausted;
};
is ($@, q{}, q{$cdr executed fine});
is_deeply(\@vals, [-1, 7, 8], q{$cdr returns what I said it would});
}
# skip_until (3)
{
my $iter;
@vals = ();
eval
{
$iter = iskip_until {$_ > 5} irange 1; # returns 6, 7, 8, 9, ...
};
is ($@, q{}, q{$iter iterators created fine});
eval
{
push @vals, $iter->value for (1..4);
};
is ($@, q{}, q{$iter executed fine});
is_deeply(\@vals, [6, 7, 8, 9], q{$iter returns what I said it would});
}
# imesh (3)
{
my $iter;
@vals = ();
eval
{
my $i1 = ilist ('a', 'b', 'c');
my $i2 = ilist (1, 2, 3);
my $i3 = ilist ('rock', 'paper', 'scissors');
$iter = imesh ($i1, $i2, $i3);
};
is ($@, q{}, q{imesh iterator created fine});
eval
{
# $iter will return, in turn, 'a', 1, 'rock', 'b', 2, 'paper', 'c',...
push @vals, $iter->value for (1..7);
};
is ($@, q{}, q{imesh executed fine});
is_deeply(\@vals, ['a', 1, 'rock', 'b', 2, 'paper', 'c'], q{imesh returns what I said it would});
}
# izip (3)
{
my $iter;
@vals = ();
eval
{
my $i1 = ilist ('a', 'b', 'c');
my $i2 = ilist (1, 2, 3);
my $i3 = ilist ('rock', 'paper', 'scissors');
$iter = izip ($i1, $i2, $i3);
};
is ($@, q{}, q{izip iterator created fine});
eval
{
# $iter will return, in turn, 'a', 1, 'rock', 'b', 2, 'paper', 'c',...
push @vals, $iter->value for (1..7);
};
is ($@, q{}, q{izip executed fine});
is_deeply(\@vals, ['a', 1, 'rock', 'b', 2, 'paper', 'c'], q{izip returns what I said it would});
}
# iuniq (3)
{
my $uniq;
@vals = ();
eval
{
my $iter = ilist (1, 2, 2, 3, 1, 4);
$uniq = iuniq ($iter); # returns 1, 2, 3, 4.
};
is ($@, q{}, q{iuniq iterator created fine});
eval
{
push @vals, $uniq->value while $uniq->isnt_exhausted;
};
is ($@, q{}, q{iuniq executed fine});
is_deeply(\@vals, [1, 2, 3, 4], q{iuniq returns what I said it would});
}

31
t/iappend.t Normal file
View File

@ -0,0 +1,31 @@
use strict;
use Test::More tests => 2;
use Iterator::Util;
# Check that iappend works as promised.
sub begins_with
{
my ($actual, $expected, $test_name) = @_;
$actual = substr($actual, 0, length $expected);
@_ = ($actual, $expected, $test_name);
goto &is;
}
my ($iter, @vals);
# iappend (2)
eval
{
my $it1 = irange 1,3;
my $it2 = irange 20,30,8;
my $it3 = irange 110, 100, -5;
$iter = iappend $it1, $it2, $it3;
push @vals, $iter->value while $iter->isnt_exhausted;
};
is $@, q{}, q{Created iappend iterator, no errors};
is_deeply (\@vals, [1, 2, 3, 20, 28, 110, 105, 100], q{iappend returned expected values});

57
t/iarray.t Normal file
View File

@ -0,0 +1,57 @@
use strict;
use Test::More tests => 6;
use Iterator::Util;
# Check that iarray works as promised.
sub begins_with
{
my ($actual, $expected, $test_name) = @_;
$actual = substr($actual, 0, length $expected);
@_ = ($actual, $expected, $test_name);
goto &is;
}
my ($iter, $x, @vals, @reported);
@vals = (1, 2, 'foo', [qw/a b c/]);
# basic iarray. (3)
eval
{
$iter = iarray \@vals;
};
is $@, q{}, q{Created iarray iterator, no errors};
@reported = ();
eval
{
push @reported, $iter->value while $iter->isnt_exhausted;
};
is $@, q{}, q{Executed array iterator, no errors};
is_deeply (\@reported, [1, 2, 'foo', [qw/a b c/]], q{iarray returned expected values});
# changing iarray. (3)
eval
{
$iter = iarray \@vals;
};
is $@, q{}, q{Created iarray iterator, no errors};
@reported = ();
eval
{
push @reported, $iter->value for (1..3);
# Change the underlying array:
push @vals, 'Mark Jason Dominus is God';
$vals[0] = '666';
push @reported, $iter->value while $iter->isnt_exhausted;
};
is $@, q{}, q{Executed array iterator, no errors};
is_deeply (\@reported, [1, 2, 'foo', [qw/a b c/], q{Mark Jason Dominus is God}],
q{iarray returned expected values});

144
t/ihead.t Normal file
View File

@ -0,0 +1,144 @@
use strict;
use Test::More tests => 29;
use Iterator::Util;
# Check that ihead works as promised.
sub begins_with
{
my ($actual, $expected, $test_name) = @_;
$actual = substr($actual, 0, length $expected);
@_ = ($actual, $expected, $test_name);
goto &is;
}
my ($iter, $x, $next, @vals);
# ihead (3)
eval
{
$iter = ihead 5, imap { $_ * $_ } irange 4;
};
$x = $@;
is $x, q{}, q{Created ihead iterator, no errors};
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is $x, q{}, q{Executed ihead iterator, no errors};
is_deeply (\@vals, [16, 25, 36, 49, 64], q{ihead returned expected values});
# ihead, zero (3)
eval
{
$iter = ihead 0, imap { $_ * $_ } irange 4;
};
$x = $@;
is $x, q{}, q{Created ihead iterator, no errors};
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is $x, q{}, q{Executed ihead iterator, no errors};
is_deeply (\@vals, [], q{ihead returned expected values});
# ihead, negative (3)
eval
{
$iter = ihead -77, imap { $_ * $_ } irange 4;
};
$x = $@;
is $x, q{}, q{Created ihead iterator, no errors};
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is $x, q{}, q{Executed ihead iterator, no errors};
is_deeply (\@vals, [], q{ihead returned expected values});
# ihead, parameter error (4)
eval
{
$iter = ihead -77, 4;
};
$x = $@;
isnt $x, q{}, q{Created ihead iterator, no errors};
ok (Iterator::X->caught(), q{ihead exception: proper base class});
ok (Iterator::X::Parameter_Error->caught(), q{ihead exception: proper specific class});
begins_with ($x, q{Second parameter for ihead must be an Iterator},
q{ihead exception formatted properly.});
# ihead (3)
eval
{
$iter = imap { $_ * $_ } irange 4;
@vals = ihead 5, $iter;
$next = $iter->value;
};
is $@, q{}, q{Called ihead, no errors};
is_deeply (\@vals, [16, 25, 36, 49, 64], q{ihead returned expected values});
cmp_ok ($next, '==', 81, q{Iterator advanced correctly});
# ihead, zero (3)
eval
{
$iter = imap { $_ * $_ } irange 4;
@vals = ihead 0, $iter;
$next = $iter->value;
};
is $@, q{}, q{Created ihead iterator, no errors};
is_deeply (\@vals, [], q{ihead returned expected values});
cmp_ok ($next, '==', 16, q{Iterator advanced correctly});
# ihead, negative (3)
eval
{
$iter = imap { $_ * $_ } irange 4;
@vals = ihead -64, $iter;
$next = $iter->value;
};
is $@, q{}, q{Created ihead iterator, no errors};
is_deeply (\@vals, [], q{ihead returned expected values});
cmp_ok ($next, '==', 16, q{Iterator advanced correctly});
# ihead, undef (3)
eval
{
$iter = imap { $_ * $_ } irange 4, 6;
@vals = ihead undef, $iter;
};
is $@, q{}, q{Created ihead iterator, no errors};
is_deeply (\@vals, [16, 25, 36], q{ihead returned expected values});
ok ($iter->is_exhausted, q{ihead exhausted the iterator});
# ihead, parameter error (4)
eval
{
$iter = ihead -77, 4;
};
$x = $@;
isnt $x, q{}, q{Created ihead iterator, no errors};
ok (Iterator::X->caught(), q{ihead exception: proper base class});
ok (Iterator::X::Parameter_Error->caught(), q{ihead exception: proper specific class});
begins_with ($x, q{Second parameter for ihead must be an Iterator},
q{ihead exception formatted properly.});

36
t/ilist.t Normal file
View File

@ -0,0 +1,36 @@
use strict;
use Test::More tests => 3;
use Iterator::Util;
# Check that ilist works as promised.
sub begins_with
{
my ($actual, $expected, $test_name) = @_;
$actual = substr($actual, 0, length $expected);
@_ = ($actual, $expected, $test_name);
goto &is;
}
my ($iter, $x, @vals);
@vals = (1, 2, 'foo', [qw/a b c/]);
# ilist (3)
eval
{
$iter = ilist @vals;
};
$x = $@;
is $x, q{}, q{Created ilist iterator, no errors};
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is $x, q{}, q{Executed ilist iterator, no errors};
is_deeply (\@vals, [1, 2, 'foo', [qw/a b c/]], q{ilist returned expected values});

72
t/imap.t Normal file
View File

@ -0,0 +1,72 @@
use strict;
use Test::More tests => 13;
use Iterator::Util;
# Check that imap function works (assumes irange works).
sub begins_with
{
my ($actual, $expected, $test_name) = @_;
$actual = substr($actual, 0, length $expected);
@_ = ($actual, $expected, $test_name);
goto &is;
}
my ($iter, $x, $worked, @vals);
## Parameter error (4)
eval
{
$iter = imap { $_ * 2} 'oops';
};
$x = $@;
isnt ($@, q{}, q{Wrong-type; exception thrown});
ok (Iterator::X->caught(), q{Wrong-type base exception type});
ok (Iterator::X::Parameter_Error->caught(), q{Wrong-type specific exception type});
begins_with ($x, q{Argument to imap must be an Iterator object},
q{Wrong-type exception formatted properly});
## run an irange through an imap. (1)
eval
{
$iter = imap { $_ * 2 } irange (0);
};
is ($@, q{}, q{Normal; no exception thrown});
# pull a few numbers out of the hat. (2)
@vals = ();
eval
{
push @vals, $iter->value() for (1..4);
};
is ($@, q{}, q{No exception when imapping});
is_deeply (\@vals, [0, 2, 4, 6], q{imap transformation returned expected result});
# Now do it with a finite irange (2)
@vals = ();
eval
{
$iter = imap {$_ * $_} irange (1, 4);
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{No exception when imapping.});
is_deeply (\@vals, [1, 4, 9, 16], q{Square imap returned expected results});
# Try pushing it further: (4)
eval
{
push @vals, $iter->value;
};
$x = $@;
isnt ($@, q{}, q{Imapped too far; exception thrown});
ok (Iterator::X->caught(), q{Too-far base exception type});
ok (Iterator::X::Exhausted->caught(), q{Too-far specific exception type});
begins_with ($x, q{Iterator is exhausted},
q{Too-far exception formatted properly});

33
t/ipairwise.t Normal file
View File

@ -0,0 +1,33 @@
use strict;
use Test::More tests => 2;
use Iterator::Util;
# Check that ipairwise works as promised.
sub begins_with
{
my ($actual, $expected, $test_name) = @_;
$actual = substr($actual, 0, length $expected);
@_ = ($actual, $expected, $test_name);
goto &is;
}
my ($iter, @vals);
# ipairwise (2)
eval
{
no warnings 'once';
my $first = irange 1; # 1, 2, 3, 4, ...
my $second = irange 4, undef, 2; # 4, 6, 8, 10, ...
my $third = ipairwise {$a * $b} $first, $second; # 4, 12, 24, 40, ...
push @vals, $third->value for (1..4)
};
is $@, q{}, q{Created ipairwise iterator, no errors};
is_deeply (\@vals, [4, 12, 24, 40], q{ipairwise returned expected values});

269
t/irange.t Normal file
View File

@ -0,0 +1,269 @@
use strict;
use Test::More tests => 42;
use Iterator::Util;
# Check that irange function works.
sub begins_with
{
my ($actual, $expected, $test_name) = @_;
$actual = substr($actual, 0, length $expected);
@_ = ($actual, $expected, $test_name);
goto &is;
}
my ($iter, $x, $worked, @vals);
## One-arg irange (infinite) (3)
eval
{
$iter = irange(52);
};
is $@, q{}, q{Created one-arg iterator; no exception};
# How do you test an infinite iterator?
# Well, let's run through a bunch of iterations, see if it pans out.
$worked = 1; # assume okay
eval
{
foreach my $test (52..151) # try a hundred values
{
if ($test != $iter->value || $iter->is_exhausted)
{
$worked = 0;
last;
}
}
};
is ($@, q{}, q{Looped over one-arg iterator; no exception});
ok ($worked, q{One-arg iterator gave expected values});
## Two-arg irange (start, end). (3)
eval
{
$iter = irange (4, 6);
};
is ($@, q{}, q{Created two-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked two-arg iterator until exhausted});
is_deeply (\@vals, [4, 5, 6], q{Two-arg iterator returned expected results});
## Two-arg irange (start, end), end < start. (3)
eval
{
$iter = irange (6, 4);
};
is ($@, q{}, q{Created two-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked two-arg iterator until exhausted});
is_deeply (\@vals, [], q{Two-arg iterator returned expected results});
## Two-arg irange (start, end), end == start. (3)
eval
{
$iter = irange (6, 6);
};
is ($@, q{}, q{Created two-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked two-arg iterator until exhausted});
is_deeply (\@vals, [6], q{Two-arg iterator returned expected results});
## Three-arg irange (start, end, step). (3)
eval
{
$iter = irange (28, 41, 7);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked three-arg iterator until exhausted});
is_deeply (\@vals, [28, 35], q{Three-arg iterator returned expected results});
## Three-arg irange (start, end, step). (3)
eval
{
$iter = irange (28, 42, 7);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked three-arg iterator until exhausted});
is_deeply (\@vals, [28, 35, 42], q{Three-arg iterator returned expected results});
## Three-arg irange (start, end, step). (3)
eval
{
$iter = irange (28, 43, 7);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked three-arg iterator until exhausted});
is_deeply (\@vals, [28, 35, 42], q{Three-arg iterator returned expected results});
## Three-arg irange (start, end, negative step). (3)
eval
{
$iter = irange (42, 29, -7);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked three-arg iterator until exhausted});
is_deeply (\@vals, [42, 35], q{Three-arg iterator returned expected results});
## Three-arg irange (start, end, negative step). (3)
eval
{
$iter = irange (42, 28, -7);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked three-arg iterator until exhausted});
is_deeply (\@vals, [42, 35, 28], q{Three-arg iterator returned expected results});
## Three-arg irange (start, end, negative step). (3)
eval
{
$iter = irange (42, 27, -7);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked three-arg iterator until exhausted});
is_deeply (\@vals, [42, 35, 28], q{Three-arg iterator returned expected results});
## Three-arg irange (start, end, zero step). (3)
eval
{
$iter = irange (28, 42, 0);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value for (0..9);
};
is ($@, q{}, q{Invoked three-arg (zero) iterator for a while});
is_deeply (\@vals, [28, 28, 28, 28, 28, 28, 28, 28, 28, 28], q{Three-arg iterator returned expected results});
## Three-arg irange (start, end, step) (1 iteration, give or take). (3)
eval
{
$iter = irange (28, 27, 7);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked three-arg terator until exhausted});
is_deeply (\@vals, [], q{Three-arg iterator returned expected results});
## Three-arg irange (start, end, step) (1 iteration, give or take). (3)
eval
{
$iter = irange (28, 28, 7);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked three-arg terator until exhausted});
is_deeply (\@vals, [28], q{Three-arg iterator returned expected results});
## Three-arg irange (start, end, step) (1 iteration, give or take). (3)
eval
{
$iter = irange (28, 34, 7);
};
is ($@, q{}, q{Created three-arg iterator; no exception});
@vals = ();
eval
{
push @vals, $iter->value while $iter->isnt_exhausted;
};
is ($@, q{}, q{Invoked three-arg terator until exhausted});
is_deeply (\@vals, [28], q{Three-arg iterator returned expected results});

40
t/iskip.t Normal file
View File

@ -0,0 +1,40 @@
use strict;
use Test::More tests => 4;
use Iterator::Util;
# Check that iskip works as promised.
sub begins_with
{
my ($actual, $expected, $test_name) = @_;
$actual = substr($actual, 0, length $expected);
@_ = ($actual, $expected, $test_name);
goto &is;
}
my ($iter, @vals);
# iskip (2)
@vals = ();
eval
{
$iter = iskip 5, irange 8;
push @vals, $iter->value for (1..4);
};
is $@, q{}, q{Created iskip iterator, no errors};
is_deeply (\@vals, [13, 14, 15, 16], q{iskip returned expected values.});
# iskip_until (2)
@vals = ();
eval
{
$iter = iskip_until {$_ % 5 == 0} irange 8;
push @vals, $iter->value for (1..4);
};
is $@, q{}, q{Created iskip_until iterator, no errors};
is_deeply (\@vals, [10, 11, 12, 13], q{iskip_until returned expected values.});