File Coverage

blib/lib/Sub/Go.pm
Criterion Covered Total %
statement 81 93 87.1
branch 31 42 73.8
condition 10 12 83.3
subroutine 13 15 86.6
pod 4 7 57.1
total 139 169 82.2


line stmt bran cond sub pod time code
1             package Sub::Go;
2             BEGIN {
3 4     4   107059 $Sub::Go::VERSION = '0.01';
4             }
5 4     4   37 use strict;
  4         8  
  4         129  
6 4     4   52 use v5.10;
  4         13  
  4         198  
7 4     4   6250 use Exporter::Tidy default => [ qw/go yield skip stop/ ];
  4         82  
  4         72  
8 4     4   228 use Carp;
  4         8  
  4         398  
9 4     4   26 use Scalar::Util qw/blessed/;
  4         10  
  4         805  
10              
11             # get rid of this annoying message
12             my $old_warn_handler = $SIG{ __WARN__ };
13             $SIG{ __WARN__ } = sub {
14             if ( $_[ 0 ] !~ /^Useless use of smart match in void context/ ) {
15             goto &$old_warn_handler if $old_warn_handler;
16             warn( @_ );
17             }
18             };
19              
20 4     4   6831 use overload '~~' => \&over_go;
  4         4480  
  4         30  
21             #use overload '>>' => \&over_go_assign;
22              
23             sub over_go_assign {
24 0     0 0 0 $_[0]->{assign};
25 0         0 goto \&over_go;
26             }
27              
28             sub over_go {
29 43     43 0 61 my $_go_self = shift;
30 43         50 my $arg = shift;
31 43         55 my $place = shift;
32              
33 43 100       108 return unless defined $arg;
34 42         71 my $code = $_go_self->{ code };
35 42         63 my $ret = [];
36 42         72 $_go_self->{arg} = $arg;
37              
38             # input value processing
39 42 100 66     179 if ( ref $arg eq 'ARRAY' ) {
    100          
    50          
    50          
    100          
40 27         45 for ( @$arg ) {
41 115         227 my @r = $code->($_);
42 115 100       1853 last if ref $r[0] eq 'Sub::Go::Break';
43 110         208 push @$ret, @r;
44             }
45             }
46             elsif ( ref $arg eq 'HASH' ) {
47             # get the caller's $k and $v
48 6         8 my ( $caller_a, $caller_b ) = do {
49 6         10 my $pkg = caller();
50 4     4   737 no strict 'refs';
  4         8  
  4         4150  
51 6         8 \*{$pkg.'::a'}, \*{$pkg.'::b'};
  6         21  
  6         24  
52             };
53            
54             # iterate the hash
55 6         28 while ( my ( $k, $v ) = each %$arg ) {
56 9         31 local $_ = [$k,$v];
57 9         36 ( *$caller_a, *$caller_b ) = \( $k, $v );
58 9         25 push @$ret, $code->( $k, $v );
59             }
60             }
61             elsif ( ref $arg eq 'GLOB' ) {
62 0         0 while ( <$arg> ) {
63 0         0 my $r = $code->( $_ );
64 0 0       0 last if ref $r eq 'Sub::Go::Break';
65 0         0 push @$ret, $r;
66             }
67             }
68             elsif ( ref $arg eq 'CODE' ) {
69 0         0 for ( $arg->() ) {
70 0         0 my $r = $code->( $_ );
71 0 0       0 last if ref $r eq 'Sub::Go::Break';
72 0         0 push @$ret, $r;
73             }
74             }
75             elsif ( blessed $arg && $arg->can('next') ) {
76 1         5 while( local $_ = $arg->next ) {
77 3         25 push @$ret, $code->( $_ );
78             }
79             } else {
80 8         30 push @$ret, $code->( $arg ) for $arg;
81             }
82              
83             # chaining return value processing
84 42 100 100     874 if ( ref $_go_self->{rest} eq __PACKAGE__
    100 100        
    100          
    100          
85             && !$_go_self->{yielded}
86             && !$_go_self->{stop} )
87             {
88 9 100       23 if ( @$ret > 1 ) {
89 4 50       21 $_go_self->{by}
90             ? $_go_self->{rest}->{code}->( @$ret )
91             : $ret ~~ $_go_self->{rest};
92             }
93             else {
94             return $_go_self->{ by }
95 5 50       36 ? $_go_self->{rest}->{code}->( @$ret )
96             : $ret ~~ $_go_self->{rest};
97             }
98             }
99             elsif ( ref $_go_self->{rest} eq 'SCALAR' ) {
100 1         2 ${ $_go_self->{rest} } = $ret->[0];
  1         3  
101             }
102             elsif ( ref $_go_self->{rest} eq 'ARRAY' ) {
103 3         6 @{ $_go_self->{rest} } = @$ret;
  3         16  
104             }
105             elsif ( ref $_go_self->{rest} eq 'HASH' ) {
106 2         5 %{ $_go_self->{rest} } = @$ret;
  2         9  
107             }
108             else {
109 27 100 66     149 return @$ret > 1 ? $ret
110             : $ret->[0] // $ret;
111             }
112             }
113              
114             sub stop {
115 2     2 1 1013 require PadWalker;
116 2         1946 my $self_ref;
117 2         9 for ( 2 .. 3 ) {
118 2         35 my $h = PadWalker::peek_my( $_ );
119 2 50       1180 $self_ref = $h->{ '$_go_self' } and last;
120             }
121 2 50       9 !$self_ref and croak 'Misplaced yield. It can only be used in a go block.';
122 2         2 my $self = ${ $self_ref };
  2         4  
123 2         6 $self->{stop} = 1;
124 2         14 return bless {}, 'Sub::Go::Break';
125             }
126              
127             sub skip {
128 3     3 1 24 return bless {}, 'Sub::Go::Break';
129             }
130              
131             sub yield {
132 3     3 1 770 require PadWalker;
133 3         1621 my $self_ref;
134 3         7 for ( 2 .. 3 ) {
135 6         39 my $h = PadWalker::peek_my( $_ );
136 6 100       23 $self_ref = $h->{ '$_go_self' } and last;
137             }
138 3 50       8 !$self_ref and croak 'Misplaced yield. It can only be used in a go block.';
139 3         4 my $self = ${ $self_ref };
  3         4  
140 3         6 $self->{yielded} = 1;
141 3         8 $self->{rest}->{code}->( @_ );
142             }
143              
144             sub go(&;@) {
145 45     45 1 18585 my $code = shift;
146 45         52 my $rest = shift;
147            
148 45         395 return bless { code => $code, rest => $rest }, __PACKAGE__;
149             }
150              
151             sub by(&;@) {
152 0     0 0   my ( $code, $rest ) = @_;
153 0           return bless { code => $code, rest => $rest, by => 1 }, __PACKAGE__;
154             }
155              
156             1;
157              
158             =pod
159              
160             =head1 NAME
161              
162             Sub::Go - DWIM sub blocks for smart matching
163              
164             =head1 VERSION
165              
166             version 0.01
167              
168             =head1 SYNOPSIS
169              
170             use Sub::Go;
171              
172             [ 1, 2, 3 ] ~~ go { say $_ };
173             # 1
174             # 2
175             # 3
176              
177             # hashes with $a and $b
178              
179             %h ~~ go { say "key $a, value $b" };
180              
181             undef ~~ go {
182             # never gets called...
183             };
184              
185             '' ~~ go {
186             # ...but this does
187             };
188              
189             # in-place modify
190              
191             my @rs = ( { name=>'jack', age=>20 }, { name=>'joe', age=>45 } );
192             @rs ~~ go { $_->{name} = 'sue' };
193              
194             # filehandles
195              
196             open my $fh, '<', 'file.txt';
197             $fh ~~ go {
198             my $line = shift;
199             say ; # line by line
200             };
201              
202             # chaining
203             @arr ~~ go { s/$/one/ } go { s/$/two/ };
204              
205             # combine with signatures, or Method::Signatures
206             # for improved sweetness
207             use Method::Signatures;
208              
209             %h ~~ go func($x,$y) {
210             say $x * $y;
211             };
212              
213             =head1 DESCRIPTION
214              
215             In case you don't know, smart matching (C<~~>) data against a code block
216             will run the block once (for scalars) or, distributively, many times
217             for arrays and hashes:
218              
219             [1..10] ~~ sub { say shift };
220             @arr ~~ sub { say shift };
221             %h ~~ sub { ... };
222              
223             The motivation behind this module is to improve
224             the experience of using a code block with the smart match
225             operator.
226              
227             This module imports a sub called C into your package.
228             This sub returns an object that overloads the smart match operator.
229              
230             =head2 Benefits
231              
232             =head3 proper handling of hashes, with $a and $b for keys and values
233              
234             Smart matching sends only the keys, which may be useless
235             if your hash is anonymous.
236              
237             { foo=>1, bar=>2 } ~~ go {
238             say "key=$a, value=$b";
239             };
240              
241             =head3 context variables
242              
243             Load C<$_> with the current value for arrays and scalars.
244             Look for C<$a> and C<$b> for hash values.
245              
246             =head3 in-place modification of original values
247              
248             But only in the first C block of a chain (although this
249             may change soon).
250              
251             my @arr = qw/a b c/;
252             @arr ~~ go { s{$}{x} };
253             # now @arr is qw/ax bx cx/
254              
255             =head3 prevent the block from running on undef values
256              
257             We're tired of checking if defined is defined in loops.
258              
259             undef ~~ go { say "never runs" };
260             undef ~~ sub { say "but we do" };
261              
262             =head3 chaining of sub blocks
263              
264             So you can bind several blocks, one after the other,
265             in the opposite direction of C, C and friends.
266              
267             $arr ~~ go { } go { } go { };
268              
269             =head3 no warnings on the useless use of smart match operator in void context
270              
271             Annoying warning for funky syntax overloading modules like this one
272             or L. Perl should have better way around this warning.
273              
274             =head2 Pitfalls
275              
276             A smart match (and most overloaded operators)
277             can only return scalar values. So you can only expect
278             to get a scalar (value or arrayref) from your block chaining.
279              
280             =head1 FEATURES
281              
282             =head2 chaining
283              
284             You can chain C statements together, in the reverse direction
285             as you would with C or C.
286              
287             say 10 ~~ go { return $_[0] * 2 }
288             go { return $_[0] + 1 };
289             # 21
290              
291             The next C block in the chain gets the return value
292             from the previous block.
293              
294             [1..3] ~~ go { say "uno " . $_[0]; 100 + $_[0] }
295             go { say "due " . shift };
296              
297             # uno 1
298             # uno 2
299             # uno 3
300             # due 101
301             # due 102
302             # due 103
303              
304             To interleave two C blocks
305             use the C statement.
306              
307             [1..3] ~~ go { say "uno " . $_[0]; yield 100 + $_[0] } go { say "due " . shift };
308              
309             # uno 1
310             # due 101
311             # uno 2
312             # due 102
313             # uno 3
314             # due 103
315              
316             You can interrupt a C block with an special return
317             statement: C.
318            
319             [1..1000] ~~ go {
320             # after 100 this block won't execute anymore
321             return skip if $_[0] > 100;
322             } go {
323             # but this one will keep going up to the 1000th
324             };
325              
326             Or break the whole chain at a given point:
327              
328             [1..1000] ~~ go {
329             # after 100 this block won't execute anymore
330             return stop if $_[0] > 100;
331             } go {
332             # this one will run 100 times too
333             };
334              
335             =head2 return values
336              
337             Scalar is the only return value from a smart match expression,
338             and the same applies to C. You can only return scalars,
339             no arrays and hashes. So we return an arrayref if your go chain
340             returns more than one value.
341              
342             # scalar
343             my $value = 'hello' ~~ go { "$_[0] world" } # hello world
344            
345             # arrayref
346             my $arr = [10..19] go { shift }; # @arr == 1, $arr[0] == 10
347              
348             Just use C in this case, which is syntactically more sound anyway.
349              
350             So, there's an alternative implementation for returning values, by
351             chaining a reference to a variable, as such:
352              
353             my @squares;
354             @input ~~ go { $_ ** 2 } \@squares;
355            
356             my %hash = ( uno=>11, due=>22 );
357             my %out;
358             %hash ~~ go { "xxx$_[0]" => $_[1] } \%out;
359             # %out = ( xxxuno => 11, xxxdue => 22 )
360              
361             Now you have a C like interface the other way around.
362              
363             =head2 next iterators
364              
365             If you send the block an object which implements
366             a method called C, the method will be automatically called
367             and the return value fed to the block.
368              
369             # DBIx::Class resultset
370            
371             $resultset->search({ age=>100 }) ~~ go {
372             $_->name . " is centenary!";
373             };
374              
375             =head1 IMPORTS
376              
377             =head3 go CODE
378              
379             The main function here. Don't forget the semicolon at the end of the block.
380              
381             =head3 yield VALUE
382              
383             Iterate over into the next block in the chain.
384            
385             [qw/sue mike/] ~~ go { yield "world, $_" } go { say "hello " . shift };
386              
387             =head3 skip
388              
389             Tell the iterator to stop executing the current block and go
390             to the next, if any.
391            
392             return skip;
393              
394             =head3 stop
395              
396             Tell the iterator to stop executing all blocks.
397              
398             return stop;
399              
400             =head1 BUGS
401              
402             This is pre-alfa, out in the CPAN for a test-drive. There
403             are still inconsistencies in the syntax that need some
404             more thought, so expect things to change badly.
405              
406             L, a dependency, may segfault in perl 5.14.1.
407              
408             =head1 SEE ALSO
409              
410             L - has an C method that can be chained together
411              
412             L
413              
414             L
415              
416             =cut