Attribute-Generator

 view release on metacpan or  search on metacpan

lib/Attribute/Generator.pm  view on Meta::CPAN

package Attribute::Generator;

use strict;
use warnings;
our $VERSION = '0.02';

use Attribute::Handlers;
use Coro::State 4.91;

use base qw(Exporter);

our @EXPORT = qw(yield);

sub UNIVERSAL::Generator : ATTR(CODE) {
    my($package, $symbol, $refent) = @_;
    no warnings 'redefine';
    *{$symbol} = sub { new Attribute::Generator::State $refent, @_ };
}

our @stack = (Coro::State->new()); # Generator stack;

sub yield {
    $stack[-1]{_sent} = \@_;
    pop(@stack)->transfer($stack[-1]);
    my $sent = delete $stack[-1]{_sent} or return; # from send()
    wantarray ? @$sent : $sent->[0];
}

{
    package Attribute::Generator::State;
    use base qw(Coro::State);

    use overload (
        '@{}' => '__list__',
        '<>'  => 'next',
    );

    sub _run_generator {
        eval {
            &{+shift}; #execute the code
        };

        $stack[-2]->throw($@) if $@;
        while() {
            pop(@stack)->transfer($stack[-1]);
            delete $stack[-1]{_sent}; # clear send()ed.
        }
    }

    sub new {
        shift->SUPER::new(\&_run_generator, @_)
    }

    sub next {
        my($self) = @_;
        push @stack, $self;
        $stack[-2]->transfer($self); # resume
        my $ret = delete $self->{_sent} or return;
        wantarray ? @$ret : $ret->[0];
    }

    sub send {
        shift->{_sent} = \@_;
    }

    sub __list__ {
        my($self) = @_;
        my @ret;
        while(my @tmp = $self->next) {
            push @ret, @tmp;
        }
        \@ret;
    }
}

1;
__END__

=head1 NAME

Attribute::Generator - Python like generator powered by Coro

=head1 SYNOPSIS

  use Attribute::Generator;
  
  sub fizzbuzz :Generator {
    my($i, $end) = @_;
    do {
      yield (($i % 3 ? '':'Fizz').($i % 5 ? '':'Buzz') || $i)
    } while $i++ < $end;
  }
  
  my $generator = fizzbuzz(1, 100);
  
  while(defined (my $val = $generator->next())) {
    print "$val\n";
  }

  while(<$generator>) {
    print "$_\n";
  }

=head1 DESCRIPTION

Attribute::Generator realizes Python like generators using the power of L<Coro>
module. This module provides C<:Generator> CODE attribute which declares
generator subroutines, and exports C<yield> function which is like C<yield> in
Python.

=head1 FUNCTIONS



( run in 1.309 second using v1.01-cache-2.11-cpan-98e64b0badf )