File Coverage

blib/lib/Sub/Compose.pm
Criterion Covered Total %
statement 67 68 98.5
branch 13 14 92.8
condition n/a
subroutine 11 11 100.0
pod 2 2 100.0
total 93 95 97.8


line stmt bran cond sub pod time code
1             package Sub::Compose;
2              
3             $VERSION = '0.01';
4              
5 8     8   5543 use strict;
  8         15  
  8         379  
6              
7 8     8   10893 use Data::Dump::Streamer ();
  8         546634  
  8         278  
8 8     8   7661 use Sub::Name qw( subname );
  8         5288  
  8         8564  
9              
10             sub import {
11 7     7   80 my $pkg = caller;
12              
13 7         22 for (@_) {
14 8     8   58 no strict 'refs';
  8         15  
  8         4858  
15 10 100       45 if ( $_ eq 'compose' ) {
16 2         6 *{ "${pkg}::compose" } = \&compose;
  2         10  
17 2         7 next;
18             }
19 8 100       53 if ( $_ eq 'chain' ) {
20 1         2 *{ "${pkg}::chain" } = \&chain;
  1         4  
21 1         3 next;
22             }
23             }
24              
25 7         81 return;
26             }
27              
28             sub chain {
29 1     1 1 435 my (@subs) = @_;
30              
31             return subname chainer => sub {
32 1     1   337 foreach my $sub ( @subs ) {
33 3         20 @_ = $sub->( @_ );
34             }
35              
36 1         12 return @_;
37 1         10 };
38             }
39              
40             sub compose {
41 10     10 1 7324 my @subs = @_;
42              
43             #{my $i;print map { $i++ . ":$_\n" } Data::Dump::Streamer::Dump( @subs )->Out;}
44              
45 10         36 my @code = do {
46 55         51936 grep {
47 10         56 !/^;/
48             } Data::Dump::Streamer::Dump( @subs )->Out;
49             };
50              
51             #{my $i;print map { $i++ . " -> $_\n" } @code;}
52              
53 10         63 my %deparsed;
54             my @vars;
55 0         0 my @deparsed;
56 10         356 foreach my $i ( 0 .. $#code ) {
57 38         126 my @lines = split /\n/, $code[$i];
58            
59 38         179 my ($name) = $lines[0] =~ m{^ \$ (\S+) \s* = \s* (?:sub|\$)}x;
60              
61 38 100       124 unless ( $name ) {
62 15         22 push @vars, @lines;
63 15         31 next;
64             }
65              
66 23 100       62 if ( @lines == 1 ) {
67 6         33 my ($ref) = $lines[0] =~ m{ \$ (\S+) ; $}x;
68 6         53 ($deparsed{ $name } = $deparsed{ $ref }) =~ s/END_SUB_\d+/END_SUB_$i/g;
69             }
70             else {
71 17         31 shift @lines; pop @lines;
  17         28  
72              
73 17         27 local $_;
74 17         24 my $seen_return;
75 17         39 for (@lines) {
76 46 100       141 if (/return /) {
77 10         29 s/return /\@_ = /g;
78 10         23 $_ .= "goto END_SUB_$i;";
79 10         20 $seen_return++;
80             }
81             }
82 17 100       72 $lines[-1] = "\@_ = $lines[-1]" unless $seen_return;
83 17         41 push @lines, "END_SUB_$i:;\n";
84 17         68 $deparsed{ $name } = join "\n", @lines;
85             }
86 23         91 push @deparsed, $deparsed{ $name };
87             }
88              
89 8     8   58 my $sub = eval "{ @vars; sub { @deparsed; return wantarray ? \@_ : \$_[0] } }";
  8     7   15  
  8     4   804  
  7         37  
  7         15  
  7         501  
  4         25  
  4         8  
  4         310  
  10         1346  
90 10 50       47 die $@ if $@;
91 10         130 return subname composer => $sub;
92             }
93              
94             1;
95             __END__