File Coverage

blib/lib/List/Rubyish.pm
Criterion Covered Total %
statement 21 211 9.9
branch 0 96 0.0
condition 0 24 0.0
subroutine 7 59 11.8
pod 34 39 87.1
total 62 429 14.4


line stmt bran cond sub pod time code
1             package List::Rubyish;
2 1     1   4 use strict;
  1         2  
  1         31  
3 1     1   11 use warnings;
  1         1  
  1         31  
4 1     1   24 use 5.008001;
  1         7  
  1         201  
5             use overload
6             '<<' => sub {
7 0     0   0 my($self, $add) = @_;
8 0 0 0     0 $add = [ $add ] unless ref($add) eq 'ARRAY' || ref($add) eq ref($self);
9 0         0 $self->push(@$add);
10             },
11             '>>' => sub {
12 0     0   0 my($self, $add) = @_;
13 0 0       0 if (ref($self) eq ref($add)) {
    0          
14 0         0 my $tmp = $self; $self = $add; $add = $tmp;
  0         0  
  0         0  
15             } elsif (ref($add) ne 'ARRAY') {
16 0         0 $add = [ $add ];
17             }
18 0         0 $self->unshift(@$add);
19             },
20             '+' => sub {
21 0     0   0 my($self, $add, $flag) = @_;
22 0 0 0     0 $add = [ $add ] unless ref($add) eq 'ARRAY' || ref($add) eq ref($self);
23 0         0 $self->add($add, $flag);
24             },
25 1     1   1543 fallback => 1;
  1         1023  
  1         11  
26              
27             our $VERSION = '0.03';
28              
29 1     1   109 use Carp qw/croak/;
  1         36  
  1         64  
30 1     1   4 use List::Util ();
  1         2  
  1         13  
31 1     1   887 use List::MoreUtils ();
  1         1225  
  1         2238  
32              
33             sub new {
34 0     0 0   my $class = shift;
35 0 0         $class = ref $class if ref $class;
36 0 0 0       my $array = @_ > 0 ? (@_ == 1 && ref($_[0]) eq 'ARRAY') ? shift : [ @_ ] : [];
    0          
37 0           bless $array, $class;
38             }
39              
40             sub push {
41 0     0 1   my $self = shift;
42 0           push @$self, @_;
43 0           $self;
44             }
45              
46             sub unshift {
47 0     0 1   my $self = shift;
48 0           unshift @$self, @_;
49 0           $self;
50             }
51              
52             sub shift {
53 0     0 1   shift @{$_[0]};
  0            
54             }
55              
56             sub pop {
57 0     0 1   pop @{$_[0]};
  0            
58             }
59              
60             sub first {
61 0     0 1   my ($self, $num) = @_;
62 0 0         if (defined $num) {
63 0           return $self->slice(0, $num - 1);
64             } else {
65 0           return $self->[0];
66             }
67             }
68              
69             sub last {
70 0     0 1   my ($self, $num) = @_;
71 0 0         if (defined $num) {
72 0           return $self->slice($self->_last_index - $num + 1, $self->_last_index);
73             } else {
74 0           return $self->[-1];
75             }
76             }
77              
78             sub slice {
79 0     0 1   my $self = CORE::shift;
80 0           my ($start, $end) = @_;
81 0           my $last = $#{$self};
  0            
82 0 0 0       if (defined $end) {
    0 0        
83 0 0 0       if ($start == 0 && $last <= $end) {
84 0           return $self;
85             } else {
86 0 0         $end = $last if $last < $end;
87 0           return $self->new([ @$self[ $start .. $end ] ]);
88             }
89             } elsif (defined $start && 0 < $start && $last <= $start) {
90 0           return $self->new([]);
91             } else {
92 0           return $self;
93             }
94             }
95              
96             sub dump {
97 0     0 1   my $self = CORE::shift;
98 0           require Data::Dumper;
99 0           Data::Dumper->new([ $self->to_a ])->Purity(1)->Terse(1)->Dump;
100             }
101              
102             sub zip {
103 0     0 1   my $self = CORE::shift;
104 0           my $array = \@_;
105 0           my $index = 0;
106             $self->collect(sub {
107 0     0     my $ary = $self->new([$_]);
108 0           $ary->push($_->[$index]) for @$array;
109 0           $index++;
110 0           $ary;
111 0           });
112             }
113              
114             sub delete {
115 0     0 1   my ($self, $value, $code) = @_;
116 0           my $found = 0;
117 0 0         if (ref $value eq 'CODE') {
118 0 0         do { my $item = $self->shift; $value->($item) ? $found = 1 : $self->push($item) } for (0..$self->_last_index);
  0            
  0            
119             } else {
120 0 0         do { my $item = $self->shift; $item eq $value ? $found = 1 : $self->push($item) } for (0..$self->_last_index);
  0            
  0            
121             }
122             $found ? $value
123 0 0         : ref $code eq 'CODE' ? do { local $_ = $value; return $code->($_) }
  0 0          
  0            
124             : return ;
125             }
126              
127             sub delete_at {
128 0     0 1   my ($self, $pos) = @_;
129 0           my $last_index = $self->_last_index;
130 0 0         return if $pos > $last_index ;
131 0           my $result;
132             $_ == $pos ? $result = $self->shift
133 0 0         : $self->push($self->shift) for 0..$last_index;
134 0           return $result;
135             }
136              
137             sub delete_if {
138 0     0 1   my ($self, $code) = @_;
139 0 0         croak "Argument must be a code" unless ref $code eq 'CODE';
140 0           my $last_index = $self->_last_index;
141 0           for (0..$last_index) {
142 0           my $item = $self->shift;
143 0           local $_ = $item;
144 0 0         $self->push($item) unless $code->($_);
145             }
146 0           return $self;
147             }
148              
149             sub reject {
150 0     0 0   my ($self, $code) = @_;
151 0           return $self->dup->delete_if($code);
152             }
153              
154             sub inject {
155 0     0 1   my ($self, $result, $code) = @_;
156 0 0         croak "Argument must be a code" unless ref $code eq 'CODE';
157 0           $result = $code->($result, $_) for @{$self->dup};
  0            
158 0           return $result;
159             }
160              
161             sub join {
162 0     0 1   my ($self, $delimiter) = @_;
163 0           join $delimiter, @$self;
164             }
165              
166             sub each_index {
167 0     0 1   my ($self, $code) = @_;
168 0           $self->new([ 0..$self->_last_index ])->each($code);
169             }
170              
171             sub _last_index {
172 0     0     my $self = CORE::shift;
173 0 0         $self->length ? $self->length - 1 : 0;
174             };
175              
176             sub concat {
177 0     0 1   my ($self, $array) = @_;
178 0           $self->push(@$array);
179 0           $self;
180             }
181              
182             *append = \&concat;
183              
184             sub prepend {
185 0     0 1   my ($self, $array) = @_;
186 0           $self->unshift(@$array);
187 0           $self;
188             }
189              
190             sub _append_undestructive {
191 0     0     my ($self, $array) = @_;
192 0           $self->dup->push(@$array);
193             }
194              
195             sub _prepend_undestructive {
196 0     0     my ($self, $array) = @_;
197 0           $self->dup->unshift(@$array);
198             }
199              
200             sub add {
201 0     0 0   my ($self, $array, $bool) = @_;
202 0 0         $bool ? $self->_prepend_undestructive($array)
203             : $self->_append_undestructive($array);
204             }
205              
206             sub each {
207 0     0 1   my ($self, $code) = @_;
208 0 0         croak "Argument must be a code" unless ref $code eq 'CODE';
209 0           $code->($_) for @{$self->dup};
  0            
210 0           $self;
211             }
212              
213             sub collect {
214 0     0 1   my ($self, $code) = @_;
215 0 0         croak "Argument must be a code" unless ref $code eq 'CODE';
216 0           my @collected = CORE::map &$code, @{$self->dup};
  0            
217 0 0         wantarray ? @collected : $self->new(\@collected);
218             }
219              
220             *map = \&collect;
221              
222             sub grep {
223 0     0 1   my ($self, $code) = @_;
224 0 0         $code or return;
225 0           my @grepped;
226 0 0         if (!ref($code)) {
    0          
227 0           for (@$self) {
228 0 0         if (ref($_) eq 'HASH') {
229 0 0         CORE::push @grepped, $_ if $_->{$code};
230             } else {
231 0 0         CORE::push @grepped, $_ if $_->$code;
232             }
233             }
234             } elsif (ref $code eq 'CODE') {
235 0           @grepped = CORE::grep &$code, @$self;
236             } else {
237 0           croak "Invalid code";
238             }
239 0 0         wantarray ? @grepped : $self->new(\@grepped);
240             }
241              
242             sub find {
243 0     0 1   my ($self, $cond) = @_;
244             my $code = (ref $cond and ref $cond eq 'CODE')
245             ? $cond
246 0 0 0 0     : sub { $_ eq $cond };
  0            
247              
248 0 0         for (@$self) { &$code and return $_ }
  0            
249 0           return;
250             }
251              
252             *detect = \&find;
253              
254             sub select {
255 0     0 1   my ($self, $code) = @_;
256 0 0         croak "Argument must be a code" unless ref $code eq 'CODE';
257 0 0         return $self unless $self->size;
258 0           my $last_index = $self->_last_index;
259 0           my $new = $self->dup;
260 0           for (0..$last_index) {
261 0           my $item = $new->shift;
262 0           local $_ = $item;
263 0 0         $new->push($item) if $code->($_);
264             }
265 0           return $new;
266             }
267              
268             *find_all = \&select;
269              
270             sub index_of {
271 0     0 1   my ($self, $target) = @_;
272 0 0   0     my $code = (ref $target eq 'CODE') ? $target : sub { CORE::shift eq $target };
  0            
273              
274 0           for (my $i = 0; $i < $self->length; $i++) {
275 0 0         $code->($self->[$i]) and return $i;
276             }
277 0           return;
278             }
279              
280             sub sort {
281 0     0 1   my ($self, $code) = @_;
282 0 0         my @sorted = $code ? CORE::sort { $code->($a, $b) } @$self : CORE::sort @$self;
  0            
283 0 0         wantarray ? @sorted : $self->new(\@sorted);
284             }
285              
286             sub sort_by {
287 0     0 1   my ($self, $code, $cmp) = @_;
288              
289 0           my @sorted = $cmp ?
290 0           CORE::map { $_->[1] } CORE::sort { $cmp->($a->[0], $b->[0]) } CORE::map { [$code->($_), $_] } @$self :
  0            
  0            
291 0 0         CORE::map { $_->[1] } CORE::sort { $a->[0] <=> $b->[0] } CORE::map { [$code->($_), $_] } @$self;
  0            
  0            
292              
293 0 0         wantarray ? @sorted : $self->new(\@sorted);
294             }
295              
296             sub compact {
297 0     0 1   CORE::shift->grep(sub { defined });
  0     0      
298             }
299              
300             sub length {
301 0     0 1   scalar @{$_[0]};
  0            
302             }
303              
304             *size = \&length;
305              
306             sub flatten {
307 0     0 1   my $self = CORE::shift;
308 0     0     $self->collect(sub { _flatten($_) });
  0            
309             }
310              
311             sub _flatten {
312 0     0     my $element = CORE::shift;
313 0           (ref $element and ref $element eq 'ARRAY')
314 0 0 0       ? CORE::map { _flatten($_) } @$element
315             : $element;
316             }
317              
318             sub is_empty {
319 0     0 1   !$_[0]->length;
320             }
321              
322             sub uniq {
323 0     0 1   my $self = CORE::shift;
324 0           $self->new([ List::MoreUtils::uniq(@$self) ]);
325             }
326              
327             sub reduce {
328 0     0 1   my ($self, $code) = @_;
329 0 0         croak "Argument must be a code" unless ref $code eq 'CODE';
330 0     0     List::Util::reduce { $code->($a, $b) } @$self;
  0            
331             }
332              
333             sub to_a {
334 0     0 0   my @unblessed = @{$_[0]};
  0            
335 0           \@unblessed;
336             }
337              
338             sub as_list { # for Template::Iterator
339 0     0 0   CORE::shift;
340             }
341              
342             sub dup {
343 0     0 1   __PACKAGE__->new($_[0]->to_a);
344             }
345              
346             sub reverse {
347 0     0 1   my $self = CORE::shift;
348 0           $self->new([ reverse @$self ]);
349             }
350              
351             sub sum {
352 0     0 1   List::Util::sum @{$_[0]};
  0            
353             }
354              
355             1;
356              
357             __END__