croak "no wheels specified" unless @_; - my @w = map { [ 1, ref eq 'ARRAY' ? @$_ : $_ ] } @_; + my @w = map { [ 1, ref eq 'CODE' ? $_->() : $_ ] } @_; my $done; #### sub odometer { die "no wheels specified" unless @_; my @w = map { [ $_, $_->() ] } @_; my $done; return sub { if ($done) { $done=0; return } my @cur = map { $_->[1] } @w; for ( my $i=$#w; $i>=0; $i-- ) { defined( $w[$i][1] = $w[$i][0]->() ) and last; $w[$i][1] = $w[$i][0]->(); $done=1 unless $i; } return wantarray ? @cur : join '', map {defined()?$_:''} @cur; }; } #### use Test::More; sub array_it { my ($i,@arr) = (0,@_); return sub { if ( $i>$#arr ) { $i=0; return } $arr[$i++] } } { my $odo = odometer( array_it('foo','bar'), array_it('-'), array_it(3..5) ); my @o; while (defined( my $x = $odo->() )) { push @o, $x } while (my @x = $odo->()) { push @o, \@x } is_deeply \@o, ["foo-3", "foo-4", "foo-5", "bar-3", "bar-4", "bar-5", ["foo","-","3"], ["foo","-","4"], ["foo","-","5"], ["bar","-","3"], ["bar","-","4"], ["bar","-","5"] ]; } { my $odo = odometer( array_it(qw/ a b c /), array_it(qw/ 1 2 /,undef,qw/ 3 4 /), ); my @o; while (defined( my $x = $odo->() )) { push @o, $x } is_deeply \@o, [qw/ a1 a2 b3 b4 c1 c2 /]; @o = (); while (defined( my $x = $odo->() )) { push @o, $x } is_deeply \@o, [qw/ a3 a4 b1 b2 c3 c4 /]; } done_testing;