File Coverage

blib/lib/Whatever.pm
Criterion Covered Total %
statement 54 59 91.5
branch 11 16 68.7
condition 6 6 100.0
subroutine 25 29 86.2
pod n/a
total 96 110 87.2


line stmt bran cond sub pod time code
1             package Whatever;
2 2     2   51651 use warnings;
  2         5  
  2         62  
3 2     2   9 use strict;
  2         3  
  2         55  
4 2     2   9 use Carp ();
  2         6  
  2         1140  
5            
6             sub star (&) {
7             my $code = shift;
8             bless sub :lvalue {
9             goto &$code if @_ < 2;
10             my $star = $code;
11             {$star = $star->(shift);
12             @_ and ref $star eq 'Whatever' ? redo
13             : Carp::croak 'too many arguments for Whatever'}
14             $star
15             }
16             }
17 8         69 use overload fallback => 1,
18             (# infix
19             map {
20 6 50       347 my $code = /atan2/ ? sub {atan2 $_[0], $_[1]}
21 58 100       3254 : eval "sub {\$_[0] $_ \$_[1]}" or die $@;
    50          
22             $_ => sub {
23 688     688   9493 my ($self, $flip) = @_[0, 2];
24 688         758 my $arg2 = \$_[1];
25             star {
26 1061 100   1061   2569 $code->($flip ? ($$arg2, &$self)
27             : (&$self, $$arg2))
28             }
29 688         2211 }
30 58         261 } qw (+ - * / % ** << >> x . & | ^ < <= > >= == != lt le gt
31             ge eq ne <=> cmp atan2), $^V >= 5.010 ? '~~' : ()
32             ),
33             (# prefix
34             map {
35 12 50       653 my $code = eval "sub {$_ \$_[0]}" or die $@;
36             ($_ eq '-' ? 'neg' : $_) => sub {
37 2     2   5 my $self = $_[0];
38 12     12   21 star {$code->(&$self)}
39 2         9 }
40 6 100       37 } qw (- ! ~)
41             ),
42             (# functions
43             map {
44 36     36   130 my $code = eval "sub {$_(\$_[0])}" or die $@;
45             $_ => sub {
46 1     1   7754 my $self = $_[0];
47 1     1   5 star {$code->(&$self)}
48 1         21 }
49 12         77 } qw (cos sin exp abs log sqrt)
50             ),
51 36         146 '@{}' => sub {tie my @ret => 'Whatever::ARRAY', shift; \@ret},
52 2 50   2   1650 '%{}' => sub {tie my %ret => 'Whatever::HASH', shift; \%ret};
  2     26   943  
  2         59  
  26         90  
  26         116  
53            
54             {
55             my $star = star sub :lvalue {@_ ? $_[0] : $_};
56             my $arg = star sub :lvalue {$_[0]};
57             my $it = star sub :lvalue {$_};
58 90     90   48170 ** = sub :lvalue {my $x = $star};
59 0     0   0 *@ = sub {$arg};
60 7     7   1481 *_ = sub {$it};
61             ** = \$star;
62             }
63             eval {Internals::SvREADONLY($*, 1)}
64             or warn 'Whatever could not set $* readonly: '.$@;
65            
66             my $av_push = eval {
67             require Array::RefElem;
68             \&Array::RefElem::av_push
69             };
70             sub AUTOLOAD {
71 17     17   70 my $self = shift;
72 17         21 my $args = \@_;
73 17         29 my $method = substr our $AUTOLOAD, 2 + length __PACKAGE__;
74             star {
75 28 50   28   45 if ($av_push) {
76             $av_push->(\@_, $_)
77 0         0 for scalar &$self, @$args, @_ = ();
78             } else {
79 28         41 @_ = (scalar &$self, @$args)
80             }
81 28         76 goto &{$_[0]->can($method)}
  28         92  
82             }
83 17     0   65 } sub DESTROY {}
  0         0  
84            
85             {package
86             Whatever::ARRAY;
87 36     36   82 sub TIEARRAY {bless \\pop}
88             sub FETCH {
89 37     37   119 my ($self, $key) = @_;
90             Whatever::star sub :lvalue {
91 38   100 38   78 (&$$$self ||= [])->[$key - ($key > 2**30 and 2**31-1)]
      100        
92             }
93 37         147 }
94 3     3   10 sub FETCHSIZE {2**31-1}
95 1     1   169 sub AUTOLOAD {Carp::croak our $AUTOLOAD . " unsupported"}
96 0     0   0 sub DESTROY {}
97             }
98             {package
99             Whatever::HASH;
100 26     26   62 sub TIEHASH {bless \\pop}
101             sub FETCH {
102 25     25   40 my ($self, $key) = @_;
103 30   100 30   65 Whatever::star sub :lvalue {(&$$$self ||= {})->{$key}}
104 25         85 }
105 1     1   103 sub AUTOLOAD {Carp::croak our $AUTOLOAD . " unsupported"}
106 0     0     sub DESTROY {}
107             }
108             delete $Whatever::{star};
109             our $VERSION = '0.23';
110            
111             =head1 NAME
112            
113             Whatever - a perl6ish whatever-star for perl5
114            
115             =head1 VERSION
116            
117             Version 0.23
118            
119             =head1 SYNOPSIS
120            
121             this module provides a whatever-star C< * > term for perl 5. since this
122             module is B a source filter, the name C< &* > or C< $* > is as close as
123             it's going to get.
124            
125             use Whatever;
126            
127             my $greet = 'hello, ' . &* . '!';
128            
129             say $greet->('world'); # prints 'hello, world!'
130            
131             what was:
132            
133             my $result = $someobj->map(sub{$_ * 2});
134            
135             can now be:
136            
137             my $result = $someobj->map(&* * 2);
138            
139             =head1 EXPORT
140            
141             &* the whatever-star
142             $* the whatever-star ($* is deprecated in 5.10+, so I'm taking it)
143             &@ the gets-val-from-@_-star
144             &_ the gets-val-from-$_-star
145            
146             like all punctuation variables, the whatever terms are global across all
147             packages after this module is loaded.
148            
149             =head1 SUBROUTINES
150            
151             the C< &* > and C< $* > stars are the most generic terms, which return their
152             expression as a coderef that will take its argument from C< $_[0] > if it is
153             available, or C< $_ > otherwise. this allows the terms to dwim in most contexts.
154             think of the whatever star as C< sub {@_ ? $_[0] : $_} >
155            
156             the C< &@ > term always uses C< $_[0]>, while the C< &_ > always uses C< $_ >
157            
158             beyond where they get their eventual argument from, all of the whatever terms
159             behave the same way. each is a I overloaded object that will bind to
160             the operators and variables that it interacts with. at all times the whatever
161             star is a coderef that will perform the actions it has accumulated when passed
162             a value to act on.
163            
164             a few more examples are probably in order:
165            
166             =over 4
167            
168             =item hello world
169            
170             my $greet = "hello, $*!"; # the $* term interpolates in strings
171             say $greet->('world'); # prints 'hello, world!'
172            
173             say "hello, $*!"->('world');
174            
175             =item simple operations
176            
177             my $inc = $* + 1;
178             say $inc->(5); # prints 6
179            
180             my $inc_x2 = $inc * 2; # whatever code continues to capture operations
181             say $inc_x2->(5); # prints 12
182            
183             my $inc_inc = $inc->($inc); # and is fine with recursion
184             say $inc_inc->(5); # prints 7
185            
186             my $repeat = &* x &*;
187             my $line = $repeat->('-');
188             my $hr = $line . "\n";
189            
190             print $hr->(80); # prints ('-' x 80)."\n"
191            
192             =item with object oriented code
193            
194             assuming this simple C< Array > implementation:
195            
196             {package Array;
197             sub new {shift; bless [@_]}
198             sub map {new Array map $_[1]() => @{$_[0]}}
199             sub grep {new Array grep $_[1]() => @{$_[0]}}
200             sub str {join ' ' => @{$_[0]}}
201             }
202             my $array = new Array 1 .. 10;
203            
204             say $array->map(&_ * 2)->str; # '2 4 6 8 10 12 14 16 18 20'
205             say $array->map(&_ * 2)->map(&_ + 1)->str; # '3 5 7 9 11 13 15 17 19 21'
206             say $array->map(&_ * 2 + 1)->str; # '3 5 7 9 11 13 15 17 19 21'
207            
208             =item method calls
209            
210             my $str = &*->str;
211             say $str->($array); # prints '1 2 3 4 5 6 7 8 9 10'
212            
213             my $multi_call = &*->map(&_ * 2 + 1)->grep(&_ % 5)->str;
214            
215             say $multi_call->($array); # prints '3 7 9 11 13 17 19 21'
216            
217             $some_obj->map(&*->some_method(...));
218            
219             arguments of method calls are copied by alias if L is installed.
220             this provides closure like behavior. otherwise, the values are fixed to
221             whatever they were at the time of declaration.
222            
223             =item multiple whatever stars
224            
225             when working with subs created by combining multiple stars, you can bind
226             multiple values at once by passing multiple arguments.
227            
228             my $join3 = &* . &* . &*;
229            
230             say $join3->(1)(2)(3); # prints '123'
231             say $join3->(1 .. 3); # prints '123'
232            
233             my $indent = $join3->(' ', ' ');
234            
235             say $indent->('xyz'); # prints ' xyz'
236            
237             =item arrays and hashes
238            
239             you can dereference a whatever star as an array or hash (of course the star
240             expects to be passed a suitable reference):
241            
242             my $first = &*->[0];
243             my $bob = &*->{bob};
244            
245             say $first->([3 .. 5]); # prints '3'
246             say $bob->({bob => 5}); # prints '5'
247            
248             the subroutine returned by the star is a valid lvalue (can be assigned to).
249             multi-level calls and calls that would normally autovivify behave as expected.
250            
251             &*->[0][0]{x}(my $array) = 4;
252            
253             say $$array[0][0]{x}; # prints '4'
254            
255             =item variables
256            
257             the stars lazily bind to variables, which allows the variable to get its value
258             after the star is defined, and to change its value between calls. this is
259             analogous to an anonymous sub closing over a variable
260            
261             my $future;
262             my $delorean = $future . (' ' . $* . '!');
263             # works like: sub {$future . (' ' . $_[0] . '!')};
264            
265             $future = 1.21;
266             say $delorean->('gigawatts'); # prints "1.21 gigawatts!"
267            
268             $future = &*;
269             say $delorean->('folks')->("that's all"); # prints "that's all folks!"
270            
271             =back
272            
273             =head1 AUTHOR
274            
275             Eric Strom, C<< >>
276            
277             =head1 BUGS
278            
279             this module is new, there are probably some.
280            
281             please report any bugs or feature requests to C,
282             or through the web interface at
283             L. I will be
284             notified, and then you'll automatically be notified of progress on your bug as
285             I make changes.
286            
287             =head1 ACKNOWLEDGEMENTS
288            
289             those behind the perl6 whatever-star
290            
291             =head1 LICENSE AND COPYRIGHT
292            
293             copyright 2010 Eric Strom.
294            
295             this program is free software; you can redistribute it and/or modify it
296             under the terms of either: the GNU General Public License as published
297             by the Free Software Foundation; or the Artistic License.
298            
299             see http://dev.perl.org/licenses/ for more information.
300            
301             =cut
302            
303             __PACKAGE__ if 'first require';