The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Class::Iterator;


# Copyright (c) 2003 Robert Silve
# All rights reserved.
# This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl itself. 


require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(imap igrep);

use Carp;

our $VERSION = "0.3";

sub new {
    my $proto = shift;
    my $class = ref($proto) || $proto;
    my $self  = {};
    bless ($self, $class);
    $self->generator(shift || sub { return sub { return } });
    $self->init;
    return $self;
}

sub init {
    my $self = shift;
    $self->iterator($self->generator->())
}


sub next {
    my $self = shift;
    return $self->iterator->();
}

sub generator {
    my $self = shift;
    my $arg = shift;
    if ($arg) {
	$self->{_generator} = $arg;
    } else {
	return $self->{_generator};
    }

}

sub iterator {
    my $self = shift;
    my $arg = shift;
    if ($arg) {
	$self->{_iterator} = $arg;
    } else {
	return $self->{_iterator};
    }

}

sub AUTOLOAD {
    my ($self) = @_;
    my ($pack, $meth) =($AUTOLOAD =~ /^(.*)::(.*)$/);
    my @auth = qw(generator iterator);
    my %auth = map { $_ => 1 } @auth;
    unless ($auth{$meth}) {
	croak "Unknow method $meth";
    }
    
    my $code = sub {
	my $self = shift;
	my $arg = shift;
	if ($arg) {
	    $self->{"_$meth"} = $arg;
	} else {
	    return $self->{"_$meth"};
	}
    };
    
    *$AUTOLOAD = $code;
    goto &$AUTOLOAD;
	    
}

sub _imap {
    my ($rule, $generator) = @_;
    my $it = $generator->();
    return sub {
	return sub {
	    local $_ = $it->();
	    return unless defined $_;
	    return $rule->();
	}
    }
    
}

sub imap (&$) {
    my ($rule, $self) = @_;
    return $self->new(_imap($rule, $self->generator));
}


sub _igrep {
    my ($rule, $it) = @_;
#    my $it = $generator->();
    return sub {
	return sub {
	    while ( defined(my $v = $it->()) ) {
		local $_ = $v;
		return $_ if $rule->();
	    }
	    return;
	}
    }
    
}


sub igrep (&$) {
    my ($rule, $self) = @_;
    return $self->new(_igrep($rule, $self->iterator));
}



1;


__END__


# Below is stub documentation for your module. You better edit it!

=head1 NAME

Class::Iterator - Iterator class

=head1 SYNOPSIS

  use Class::Iterator;
  my $it = Class::Iterator->new(\&closure_generator);

  while (my $v = $it->next) { print "value : $v\n" }
  
  # use map like
  my $it2 = imap { ...some code with $_...} $it
  while (my $v = $it->next) { print "value : $v\n" }

  # use grep like
  my $it3 = igrep { ...some code with $_...} $it
  while (my $v = $it->next) { print "value : $v\n" }


=head1 DESCRIPTION

Class::Iterator is a generic iterator object class. It use a closure an wrap 
into an object interface.

=over 4

=item new(\&closure_generator)

This is the constructor. The argument is a sub which look like
  sub closure_generator {
    my $private_data;
    return sub {
      # do something with $private_data
      # and return it
      return $private_data
    }
}

=item next

calling this method make one iteration. 

=item $o = imap { ... } $it

This a creator. It create a new iterator from an existant
iterator in the manner of map.

=item $o = igrep { ... } $it

This a creator. It create a new iterator from an existant
iterator in the manner of grep.


=back

=head1 CREDITS

Marc Jason Dominius's YAPC::EU 2003 classes.
Ken Olstad 

=head1 AUTHOR

Robert Silve <robert@silve.net>

=cut