File Coverage

blib/lib/Algorithm/GenerateSequence.pm
Criterion Covered Total %
statement 31 31 100.0
branch 8 8 100.0
condition 1 3 33.3
subroutine 6 6 100.0
pod 2 3 66.6
total 48 51 94.1


line stmt bran cond sub pod time code
1 1     1   843 use strict;
  1         2  
  1         44  
2             package Algorithm::GenerateSequence;
3 1     1   6 use vars qw( $VERSION );
  1         1  
  1         347  
4             $VERSION = '0.02';
5              
6             =head1 NAME
7              
8             Algorithm::GenerateSequence - a sequence generator
9              
10             =head1 SYNOPSIS
11              
12             my $gen = Algorithm::GenerateSequence->new(
13             [qw( one two three )], [qw( hey bee )],
14             );
15             print join(' ', $gen->next), "\n"; # one hey
16             print join(' ', $gen->next), "\n"; # one bee
17             print join(' ', $gen->next), "\n"; # two hey
18             print join(' ', $gen->next), "\n"; # two bee
19             ...
20              
21             =head1 DESCRIPTION
22              
23             Algorithm::GenerateSequence provides an iterator interface to a
24             sequence you define in terms of the symbols to use in each position.
25              
26             You may use a different amount of symbols in each position and the
27             module will iterate over them correctly. This might be useful in
28             identifying all the cards in a deck:
29              
30             my $deck = Algorithm::GenerateSequence->new(
31             [qw( Heart Diamond Spade Club )],
32             [qw( A 2 3 4 5 6 7 8 9 10 J Q K )],
33             );
34              
35             Or for a range of addresses to scan:
36              
37             my $scan = Algorithm::GenerateSequence->new(
38             [192], [168], [0..254], [1]
39             );
40              
41             =head1 METHODS
42              
43             =head2 new( @values );
44              
45             @values contains arrays of symbols which will be used to form the
46             sequence
47              
48             =cut
49              
50             sub new {
51 2     2 1 843 my $class = shift;
52              
53 2         5 my @values = @_;
54 2         7 my @counters = (0) x @values;
55 2         4 my ($started, $ended);
56              
57             bless sub {
58 19 100   19   431 return if $ended;
59              
60 18 100       39 if ($started++) {
61 16         22 my $max = $#counters;
62              
63             # mmm, long addition
64 16         19 do {
65 24         27 my $new = ++$counters[ $max ];
66             # check for overflow
67 24 100       25 goto DONE if $new % @{ $values[ $max ] };
  24         112  
68 10         25 $counters[ $max ] = 0;
69             } while --$max >= 0;
70             DONE:
71 16 100       34 if ($max < 0) {
72 2         2 $ended = 1;
73 2         9 return;
74             }
75             }
76              
77 16         20 my $i = 0;
78 16         23 return map { $values[ $i++ ][ $_ ] } @counters;
  44         152  
79 2   33     23 }, ref $class || $class;
80             }
81              
82             =head1 next
83              
84             returns a list containing the next value in the sequence, or false if
85             at the end of the sequence
86              
87             =cut
88              
89 14     14 0 464 sub next { $_[0]->() }
90              
91              
92             =head2 as_list
93              
94             return the remainder of the sequence as a list of array references
95              
96             =cut
97              
98             sub as_list {
99 1     1 1 2 my $self = shift;
100              
101 1         2 my @results;
102 1         4 while (my @next = $self->()) {
103 3         7 push @results, \@next;
104             }
105 1         7 return @results;
106             }
107              
108             1;
109             __END__