File Coverage

blib/lib/Attribute/Generator.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Attribute::Generator;
2              
3 5     5   4459 use strict;
  5         11  
  5         346  
4 5     5   25 use warnings;
  5         12  
  5         236  
5             our $VERSION = '0.02';
6              
7 5     5   11412 use Attribute::Handlers;
  5         31172  
  5         37  
8 5     5   3267 use Coro::State 4.91;
  0            
  0            
9              
10             use base qw(Exporter);
11              
12             our @EXPORT = qw(yield);
13              
14             sub UNIVERSAL::Generator : ATTR(CODE) {
15             my($package, $symbol, $refent) = @_;
16             no warnings 'redefine';
17             *{$symbol} = sub { new Attribute::Generator::State $refent, @_ };
18             }
19              
20             our @stack = (Coro::State->new()); # Generator stack;
21              
22             sub yield {
23             $stack[-1]{_sent} = \@_;
24             pop(@stack)->transfer($stack[-1]);
25             my $sent = delete $stack[-1]{_sent} or return; # from send()
26             wantarray ? @$sent : $sent->[0];
27             }
28              
29             {
30             package Attribute::Generator::State;
31             use base qw(Coro::State);
32              
33             use overload (
34             '@{}' => '__list__',
35             '<>' => 'next',
36             );
37              
38             sub _run_generator {
39             eval {
40             &{+shift}; #execute the code
41             };
42              
43             $stack[-2]->throw($@) if $@;
44             while() {
45             pop(@stack)->transfer($stack[-1]);
46             delete $stack[-1]{_sent}; # clear send()ed.
47             }
48             }
49              
50             sub new {
51             shift->SUPER::new(\&_run_generator, @_)
52             }
53              
54             sub next {
55             my($self) = @_;
56             push @stack, $self;
57             $stack[-2]->transfer($self); # resume
58             my $ret = delete $self->{_sent} or return;
59             wantarray ? @$ret : $ret->[0];
60             }
61              
62             sub send {
63             shift->{_sent} = \@_;
64             }
65              
66             sub __list__ {
67             my($self) = @_;
68             my @ret;
69             while(my @tmp = $self->next) {
70             push @ret, @tmp;
71             }
72             \@ret;
73             }
74             }
75              
76             1;
77             __END__