File Coverage

blib/lib/List/oo.pm
Criterion Covered Total %
statement 83 87 95.4
branch 12 16 75.0
condition 2 3 66.6
subroutine 26 27 96.3
pod 20 20 100.0
total 143 153 93.4


line stmt bran cond sub pod time code
1             package List::oo;
2             $VERSION = v0.2.1;
3              
4 13     13   385361 use warnings;
  13         32  
  13         410  
5 13     13   77 use strict;
  13         26  
  13         469  
6              
7 13     13   78 use Carp;
  13         32  
  13         1172  
8              
9 13     13   7505 use List::oo::Extras;
  13         38  
  13         12430  
10              
11             require Exporter;
12             *{import} = \&Exporter::import;
13              
14             our @EXPORT_OK = qw(
15             L
16             Split
17             F
18             $a
19             $b
20             );
21              
22             # XXX now I need tags
23              
24             =encoding utf8
25              
26             =head1 NAME
27              
28             List::oo - object interface to list (array) methods
29              
30             =head1 SYNOPSIS
31              
32             Connecting multiple list I together "reads" from right to
33             left (starting with the data input way over on the right.)
34              
35             This module provides a chainable method interface to array objects,
36             which can be a bit more readable when multiple operations are involved.
37              
38             This
39              
40             print join(' ', map({"|$_|"} qw(a b c))), "\n";
41              
42             becomes:
43              
44             use List::oo qw(L);
45             print L(qw(a b c))->map(sub {"|$_|"})->join(' '), "\n";
46              
47             There is definitely some cost of execution speed. This is just an
48             experiment. Comments and suggestions welcome.
49              
50             =cut
51              
52             =head1 Constructors
53              
54             =head2 new
55              
56             $l = List::oo->new(@array);
57              
58             =cut
59              
60             sub new {
61 89     89 1 5517 my $caller = CORE::shift;
62 89   66     370 my $class = ref($caller) || $caller;
63 89         247 my $self = [@_];
64 89         205 bless($self, $class);
65 89         351 return($self);
66             } # end subroutine new definition
67             ########################################################################
68              
69             =head2 L
70              
71             $l = L(@array);
72              
73             =cut
74              
75             sub L {
76 40     40 1 61825 return(List::oo->new(@_));
77             } # end subroutine L definition
78             ########################################################################
79              
80             =head1 Strange Constructors
81              
82             This is only here because you so frequently need to start with a string
83             op and L(split(...)) is ugly.
84              
85             Aside: I'm not sure I really like this as an interface point. The need
86             to use qr// is at least a little annoying.
87              
88             =head2 Split
89              
90             my $l = Split(qr/\s+/, $string);
91              
92             =cut
93              
94             sub Split {
95 6     6 1 5946 my ($regex, $string) = @_;
96             ## warn "$regex, $string\n";
97 6 50       27 UNIVERSAL::isa($regex, 'Regexp') or
98             croak("First argument to Split must be a regular expression");
99 6         45 return(List::oo->new(split($regex, $string)));
100             } # end subroutine Split definition
101             ########################################################################
102              
103             =head1 Convenience Functions
104              
105             =head2 F
106              
107             Declare a subroutine.
108              
109             F{...};
110              
111             See also L, which lets you use C<λ{}> instead.
112              
113             =over
114              
115             =item About the C syntax
116              
117             Sadly, perl5 does not allow prototypes on methods. Thus, we cannot use
118             the undecorated block syntax as with
119              
120             map({...} @list);
121              
122             Rather, you must use the explicit C syntax
123              
124             $l->map(sub {...});
125              
126             Or, use the C or C<λ{}> shortcuts.
127              
128             use List::oo qw(F);
129             ...
130             $l->map(F{...});
131              
132             With L
133              
134             use lambda;
135             ...
136             $l->map(λ{...});
137              
138             (If the above doesn't render as the greek character lambda, your pod
139             viewer is not playing nice.)
140              
141             =back
142              
143             =cut
144              
145             sub F (&) {
146 3     3 1 25 my $sub = CORE::shift(@_);
147 3 50       9 @_ and croak;
148 3 100       28 UNIVERSAL::isa($sub, 'CODE') and return($sub);
149 1 50       45 eval($sub->isa('List::oo')) and croak 'not a method';
150 0         0 croak('why bother');
151             } # end subroutine F definition
152             ########################################################################
153              
154             =head1 List Methods
155              
156             These methods are mostly analogous to the perl builtins. Where the
157             builtin would return a list, we return a List::oo object. Where the
158             builtin returns a scalar or some data which was not the primary list
159             (e.g. C, C, C, etc.), you'll find some iI()
160             methods (the 'i' prefix is for 'inline'.)
161              
162             =head2 grep
163              
164             $l = $l->grep(sub {...});
165              
166             =cut
167              
168             sub grep {
169 2     2 1 23 my $self = CORE::shift;
170 2         3 my $sub = CORE::shift;
171 2         8 return($self->new(CORE::grep({$sub->($_)} @$self)));
  16         51  
172             } # end subroutine grep definition
173             ########################################################################
174              
175             =head2 map
176              
177             $l = $l->map(sub {...});
178              
179             =cut
180              
181             sub map {
182 15     15 1 48 my $self = CORE::shift;
183 15         20 my $sub = CORE::shift;
184 15         40 return($self->new(CORE::map({$sub->($_)} @$self)));
  106         383  
185             } # end subroutine map definition
186             ########################################################################
187              
188             =head2 reverse
189              
190             $l = $l->reverse;
191              
192             =cut
193              
194             sub reverse {
195 2     2 1 11 my $self = CORE::shift;
196 2         5 return($self->new(CORE::reverse(@$self)));
197             } # end subroutine reverse definition
198             ########################################################################
199              
200             =head2 dice
201              
202             Does things that can't be done with map.
203              
204             $l2 = $l->dice(sub {my @a = @_; ... return(@a);});
205              
206             Feeds @$l into sub, which should return a perl list. Puts the results
207             in a new List::oo object.
208              
209             The purpose is simply to allow you to write an unbroken chain when you
210             need to feed the entire list through some function which doesn't operate
211             per-element.
212              
213             Without this, you would have to break the chain of thought
214              
215             L(that_function($l->map(\&fx)->l))->map(\&fy);
216              
217             With dice, simply insert it where it is needed.
218              
219             $l->map(\&fx)->dice(sub {that_function(@_)})->map(\&fy);
220              
221             Note that in contrast to map() and grep() methods, dice() does not
222             define the $_ variable.
223              
224             What sort of functions need the whole list? Say you want to reverse
225             the front and back half of a list, or maybe break a list of 20 items
226             into 5 references of 4 items each. See the tests for examples.
227              
228             =cut
229              
230             sub dice {
231 4     4 1 10 my $self = CORE::shift;
232 4         9 my $sub = CORE::shift;
233 4         28 return($self->new($sub->(@$self)));
234             } # end subroutine dice definition
235             ########################################################################
236              
237             =head2 sort
238              
239             A lot like CORE::sort.
240              
241             $l->sort;
242              
243             $l->sort(sub {$a <=> $b});
244              
245             Unfortunately, we don't get the sort C<$a>/C<$b> package variable magic.
246             So, I set your package's $a and $b just like sort would. This means you
247             might get "used only once" warnings, but you can silence these with:
248              
249             use List::oo qw($a $b);
250              
251             The C<$a> and C<$b> imports have no other effect.
252              
253             =cut
254              
255             sub sort {
256 5     5 1 8 my $self = CORE::shift;
257 5         9 my $sub = CORE::shift;
258             # XXX should these be in-place methods or not?
259 5 100       16 if( $sub) {
260 3         9 my $caller = caller;
261 3         8 my ($ca, $cb) = map({eval('\\$'.$caller.'::'.$_)} qw(a b));
  6         409  
262 36         114 return($self->new(CORE::sort(
263             # sort sets my package vars, so I have to set them into
264             # caller's here to make this work
265 3         24 {($$ca, $$cb)=($a,$b); $sub->();}
  36         55  
266             @$self))
267             );
268             # THE OTHER OPTION {{{
269             # my @list = eval("package $caller; CORE::sort(\$sub \@\$self)");
270             # return($self->new(@list));
271             # }}}
272             }
273             else {
274 2         23 return($self->new(CORE::sort(@$self)));
275             }
276             } # end subroutine sort definition
277             ########################################################################
278              
279             =head2 splice
280              
281             Splices into @$l and returns the removed elements (or last element in
282             scalar context) ala CORE::splice.
283              
284             $l->splice($offset, $length, @list);
285              
286             With no replacement:
287              
288             $l->splice($offset, $length);
289              
290             Remove everything from $offset onward
291              
292             $l->splice($offset);
293              
294             Empties the list
295              
296             $l->splice;
297              
298             =cut
299              
300             sub splice {
301 3     3 1 6 my $self = CORE::shift;
302 3 100       15 if(@_ >= 3) {
    100          
    50          
303 1         3 my ($o, $l) = (CORE::shift(@_), CORE::shift(@_));
304 1         5 return CORE::splice(@$self, $o, $l, @_);
305             }
306             elsif(@_ == 2) {
307 1         11 return CORE::splice(@$self, $_[0], $_[1]);
308             }
309             elsif(@_ == 1) {
310 1         5 return CORE::splice(@$self, $_[0]);
311             }
312             else {
313 0         0 return CORE::splice(@$self);
314             }
315             } # end subroutine splice definition
316             ########################################################################
317              
318             =head1 Head and Tail Methods
319              
320             =head2 push
321              
322             Returns the new length of the list.
323              
324             $l->push(@stuff);
325              
326             =cut
327              
328             sub push {
329 1     1 1 2 my $self = CORE::shift;
330 1         3 CORE::push(@$self, @_);
331             } # end subroutine push definition
332             ########################################################################
333              
334             =head2 pop
335              
336             Removes and returns the last item.
337              
338             $l->pop;
339              
340             =cut
341              
342             sub pop {
343 2     2 1 475 my $self = shift;
344 2         6 pop(@$self);
345             } # end subroutine pop definition
346             ########################################################################
347              
348             =head2 shift
349              
350             Removes and returns the first item.
351              
352             $l->shift;
353              
354             =cut
355              
356             *{List::oo::shift} = sub { # declaring like that makes CORE::shift() not needed
357 2     2   518 my $self = CORE::shift;
358 2         6 CORE::shift(@$self);
359             }; # end subroutine shift definition
360             ########################################################################
361              
362             =head2 unshift
363              
364             Prepends @stuff to @$l and returns the new length of @$l.
365              
366             $l->unshift(@stuff);
367              
368             =cut
369              
370             sub unshift {
371 2     2 1 460 my $self = shift;
372 2         14 CORE::unshift(@$self, @_);
373             } # end subroutine unshift definition
374             ########################################################################
375              
376             =head1 Inlined Methods
377              
378             If you want to keep chaining calls together (and don't need to retrieve
379             the pop/shift/splice data.)
380              
381             =head2 ipush
382              
383             $l->map(sub {...})->ipush($val)->map(sub {...});
384              
385             =head2 ipop
386              
387             $l->map(sub {...})->ipop->map(sub {...});
388              
389             =head2 ishift
390              
391             $l->map(sub {...})->ishift->map(sub {...});
392              
393             =head2 iunshift
394              
395             $l->map(sub {...})->iunshift($val)->map(sub {...});
396              
397             =head2 isplice
398              
399             $l->map(sub {...})->isplice($offset, ...)->map(sub {...});
400              
401             =cut
402              
403             foreach my $method (qw(push pop shift unshift splice)) {
404 13     13   116 no strict 'refs';
  13         45  
  13         5298  
405             *{__PACKAGE__ . "::i$method"} = sub {
406 5     5   1514 my $self = CORE::shift;
407 5         23 $self->$method(@_);
408 5         12 return($self);
409             };
410             }
411              
412             =head2 wrap
413              
414             Add new values to the start and end.
415              
416             $l = $l->wrap($head,$tail);
417              
418             Is just:
419              
420             $l->iunshift($head)->ipush($tail);
421              
422             =cut
423              
424             sub wrap {
425 1     1 1 3 my $self = CORE::shift;
426 1         3 my ($head, $tail) = @_;
427 1         5 $self->unshift($head);
428 1         5 $self->push($tail);
429 1         3 return($self);
430             } # end subroutine wrap definition
431             ########################################################################
432              
433             =head1 Additions to List::MoreUtils
434              
435             The lack of prototypes means I can't do everything that List::MoreUtils
436             does in exactly the same way. I've chosen to make the bindings to
437             multi-list methods take only single lists and added mI() methods
438             here.
439              
440             =head2 mmesh
441              
442             Meshes @$l, @a, @b, @c, ...
443              
444             my $l = $l->mmesh(\@a, \@b, \@c, ...);
445              
446             =cut
447              
448             sub mmesh {
449 1     1 1 10 my $self = shift;
450 1         3 my (@lists) = @_;
451 1         8 return($self->new(&List::MoreUtils::mesh($self, @lists)));
452             } # end subroutine mmesh definition
453             ########################################################################
454              
455             =head2 meach_array
456              
457             Just the binding to List::MoreUtils::each_arrayref;
458              
459             my $iterator = $l->meach_array(\@a, \@b, \@c);
460              
461             =cut
462              
463             sub meach_array {
464 1     1 1 13 goto &List::MoreUtils::each_arrayref;
465             } # end subroutine meach_array definition
466             ########################################################################
467              
468             =head1 Give Me Back My List
469              
470             You can wrap the call chain in @{} or use one of the following methods.
471              
472             =head2 flatten
473              
474             If you really like to type.
475              
476             @list = $l->flatten;
477              
478             =head2 l
479              
480             The l is pretty flat and is the lowercase (less special) version of our
481             terse constructor L().
482              
483             @list = $l->l;
484              
485             =cut
486              
487             sub flatten {
488 2     2 1 3 my $self = CORE::shift;
489 2         11 return(@$self);
490             } # end subroutine l definition
491             ########################################################################
492 2     2 1 7 sub l {shift->flatten;}
493              
494             =head1 Scalar Result Methods
495              
496             These only work at the end of a chain.
497              
498             =head2 join
499              
500             $string = $l->join("\n");
501              
502             =cut
503              
504             sub join {
505 1     1 1 2 my $self = CORE::shift;
506 1         4 my $char = CORE::shift;
507 1         4 return(CORE::join($char, @$self));
508             } # end subroutine join definition
509             ########################################################################
510              
511             =head2 length
512              
513             Length of the list.
514              
515             $l->length;
516              
517             =cut
518              
519             sub length {
520 0     0 1   my $self = CORE::shift;
521 0           return(scalar(@$self));
522             } # end subroutine length definition
523             ########################################################################
524              
525             =head1 List::Util / List::MoreUtils
526              
527             The following method documentation is autogenerated along with the
528             wrappers of functions from List::Util and List::MoreUtils. The
529             supported usage is shown (in some cases, these methods only support a
530             subset of the function usage (due to the lack of method prototype
531             support.)
532              
533             The clusters of sigils (e.g. C) are included as a shorthand
534             reference. These sigils are what drive the code generation (see the
535             source of List::oo::Extras and the build_extras.pl tool in the source
536             repository for the dirty details.) The sigil on the left of the '='
537             represents the return value, the sigils on the right of the '='
538             represent what is passed to the wrapped function.
539              
540             l - a List::oo object (the $self when found on the right)
541             L - an array of List::oo objects
542             $ - a scalar
543             @ - an array
544             & - a subroutine reference (λ)
545              
546             See List::Util and List::MoreUtils for more info.
547              
548             INSERT_AUTODOC (if you find this in the .pod file, something went wrong)
549              
550             =head1 AUTHOR
551              
552             Eric Wilhelm @
553              
554             http://scratchcomputing.com/
555              
556             =over
557              
558             =item Thanks to
559              
560             Jim Keenan for contributions to the test suite.
561              
562             =back
563              
564             =head1 BUGS
565              
566             If you found this module on CPAN, please report any bugs or feature
567             requests through the web interface at L. I will be
568             notified, and then you'll automatically be notified of progress on your
569             bug as I make changes.
570              
571             If you pulled this development version from my /svn/, please contact me
572             directly.
573              
574             =head1 COPYRIGHT
575              
576             Copyright (C) 2006-2007 Eric L. Wilhelm, All Rights Reserved.
577              
578             =head1 NO WARRANTY
579              
580             Absolutely, positively NO WARRANTY, neither express or implied, is
581             offered with this software. You use this software at your own risk. In
582             case of loss, no person or entity owes you anything whatsoever. You
583             have been warned.
584              
585             =head1 LICENSE
586              
587             This program is free software; you can redistribute it and/or modify it
588             under the same terms as Perl itself.
589              
590             =head1 SEE ALSO
591              
592             EO::Array
593              
594             =cut
595              
596             # if 'no Carp;' would work...
597             delete($List::oo::{$_}) for(qw(carp croak confess));
598              
599             # these aren't methods either
600             #delete($List::oo::{$_}) for(qw(L F));
601              
602             1;
603             # vim:ts=2:sw=2:et:sta:encoding=utf8