File Coverage

blib/lib/EntityModel/Array.pm
Criterion Covered Total %
statement 68 142 47.8
branch 11 28 39.2
condition 2 4 50.0
subroutine 13 25 52.0
pod 19 19 100.0
total 113 218 51.8


line stmt bran cond sub pod time code
1             package EntityModel::Array;
2             $EntityModel::Array::VERSION = '0.016';
3 2     2   74132 use strict;
  2         4  
  2         88  
4 2     2   11 use warnings;
  2         3  
  2         74  
5              
6 2     2   1219 use parent qw(Mixin::Event::Dispatch);
  2         369  
  2         14  
7              
8 2     2   17516 use EntityModel::Log ':all';
  2         43468  
  2         498  
9              
10             =head1 NAME
11              
12             EntityModel::Array - wrapper object for dealing with arrayrefs
13              
14             =head1 VERSION
15              
16             Version 0.016
17              
18             =head1 DESCRIPTION
19              
20             Primarily intended as an abstract interface for use with L backend storage.
21              
22             =head1 METHODS
23              
24             =cut
25              
26             use overload
27             '@{}' => sub {
28 0     0   0 my $self = shift;
29 0         0 return $self->{data};
30             },
31 2     2   26 fallback => 1;
  2         5  
  2         26  
32              
33             =head2 new
34              
35             Instantiates with the given arrayref
36              
37             =cut
38              
39             sub new {
40 4     4 1 71 my ($class, $data, %opt) = @_;
41 4   100     45 bless {
42             %opt,
43             data => ($data || [ ]),
44             }, $class;
45             }
46              
47             =head2 count
48              
49             Returns the number of items in the arrayref if called
50             without parameters. This is the recommended usage.
51              
52             If passed a coderef, will call that coderef with the count,
53             and return $self instead.
54              
55             =cut
56              
57             sub count {
58 5     5 1 9 my $self = shift;
59 5         6 my $count = scalar @{$self->{data}};
  5         10  
60 5 50       13 if(@_) {
61 0         0 $_->($count) for @_;
62 0         0 return $self;
63             }
64 5         21 return $count;
65             }
66              
67             =head2 list
68              
69             Returns all items from the arrayref.
70              
71             =cut
72              
73             sub list {
74 1     1 1 3 my $self = shift;
75 1 50       9 return unless $self->{data};
76 1         2 return @{$self->{data}};
  1         9  
77             }
78              
79             =head2 push
80              
81             Push the requested value onto the end of the arrayref.
82              
83             =cut
84              
85             sub push : method {
86 5     5 1 609 my $self = shift;
87 5         9 push @{$self->{data}}, @_;
  5         19  
88 5         31 $self->invoke_event(push => @_);
89 5 50       126 if($self->{onchange}) {
90 5         7 foreach my $w (@{$self->{onchange}}) {
  5         13  
91 5         23 $w->(add => $_) foreach @_;
92             }
93             }
94 5         33 return $self;
95             }
96              
97             =head2 splice
98              
99             Support for the L operation.
100              
101             Takes an offset, length and zero or more items, splices those into the array,
102             invokes the C< splice > event, then returns $self.
103              
104             =cut
105              
106             sub splice : method {
107 0     0 1 0 my $self = shift;
108 0         0 my $offset = shift;
109 0         0 my $length = shift;
110 0         0 splice @{$self->{data}}, $offset, $length, @_;
  0         0  
111 0         0 $self->invoke_event(splice => $offset, $length, @_);
112 0         0 $self
113             }
114              
115             =head2 add_watch
116              
117             Add a coderef to be called when the array changes.
118              
119             =cut
120              
121             sub add_watch : method {
122 0     0 1 0 my $self = shift;
123 0   0     0 $self->{onchange} ||= [];
124 0         0 push @{$self->{onchange}}, @_;
  0         0  
125 0         0 return $self;
126             }
127              
128             =head2 remove_watch : method
129              
130             Removes a watch from this array.
131              
132             Returns $self.
133              
134             =cut
135              
136             sub remove_watch : method {
137 0     0 1 0 my $self = shift;
138 0 0       0 return $self unless $self->{onchange};
139 0         0 foreach my $code (@_) {
140 0         0 @{ $self->{onchange} } = grep { $_ != $code } @{ $self->{onchange} };
  0         0  
  0         0  
  0         0  
141             }
142 0         0 return $self;
143             }
144              
145             =head2 shift
146              
147             Shift the first value out of the arrayref.
148              
149             =cut
150              
151             sub shift : method {
152 0     0 1 0 my $self = shift;
153 0         0 my $v = shift(@{$self->{data}});
  0         0  
154 0         0 $self->invoke_event(shift => $v);
155 0 0       0 if($self->{onchange}) {
156 0         0 foreach my $w (@{$self->{onchange}}) {
  0         0  
157 0         0 $w->(drop => $v);
158             }
159             }
160 0         0 return $v;
161             }
162              
163             =head2 pop
164              
165             Pops the last value from the arrayref.
166              
167             =cut
168              
169             sub pop : method {
170 2     2 1 5 my $self = shift;
171 2         5 my $v = pop(@{$self->{data}});
  2         8  
172 2         187 $self->invoke_event(pop => $v);
173 2 50       49 if($self->{onchange}) {
174 2         4 foreach my $w (@{$self->{onchange}}) {
  2         6  
175 2         8 $w->(drop => $v);
176             }
177             }
178 2         13 return $v;
179             }
180              
181             =head2 unshift
182              
183             Unshifts a value onto the start of the arrayref.
184              
185             =cut
186              
187             sub unshift : method {
188 0     0 1 0 my $self = shift;
189 0         0 my $v = unshift @{$self->{data}}, @_;
  0         0  
190 0         0 $self->invoke_event(unshift => @_);
191 0 0       0 if($self->{onchange}) {
192 0         0 foreach my $w (@{$self->{onchange}}) {
  0         0  
193 0         0 $w->(add => $_) foreach @_;
194             }
195             }
196 0         0 return $self;
197             }
198              
199             =head2 join
200              
201             Joins the entries in the arrayref using the given value and returns as a scalar.
202              
203             =cut
204              
205             sub join : method {
206 4     4 1 8 my $self = shift;
207 4         7 my $sep = shift;
208 4         7 my $joined = join($sep, @{$self->{data}});
  4         15  
209 4 50       13 if(@_) {
210 0         0 $_->($joined) for @_;
211 0         0 return $self;
212             }
213 4         17 return $joined;
214             }
215              
216             =head2 each
217              
218             Perform coderef on each entry in the arrayref.
219              
220             =cut
221              
222             sub each : method {
223 0     0 1 0 my ($self, $code) = @_;
224 0         0 $code->($_) for @{$self->{data}};
  0         0  
225 0         0 return $self;
226             }
227              
228             =head2 first
229              
230             Returns the first entry in the arrayref.
231              
232             =cut
233              
234             sub first {
235 0     0 1 0 my $self = shift;
236 0 0       0 if(@_) {
237 0         0 $_->($self->{data}[0]) for @_;
238 0         0 return $self;
239             }
240 0         0 return $self->{data}[0];
241             }
242              
243             =head2 last
244              
245             Returns the last entry in the arrayref.
246              
247             =cut
248              
249             sub last {
250 0     0 1 0 my $self = shift;
251 0 0       0 if(@_) {
252 0         0 $_->($self->{data}[-1]) for @_;
253 0         0 return $self;
254             }
255 0         0 return $self->{data}[-1];
256             }
257              
258             =head2 grep
259              
260             Calls the coderef on each entry in the arrayref and returns the entries for which it returns true.
261              
262             =cut
263              
264             sub grep : method {
265 0     0 1 0 my ($self, $match) = @_;
266 0         0 return ref($self)->new([ grep { $match->($_) } @{$self->{data}} ]);
  0         0  
  0         0  
267             }
268              
269             =head2 remove
270              
271             Remove entries from the array.
272              
273             Avoid rebuilding the array in case we have weak refs, just splice out the values
274             indicated.
275              
276             =cut
277              
278             sub remove : method {
279 2     2 1 21 my ($self, $check) = @_;
280 2         3 my $idx = 0;
281 2         3 while($idx < scalar @{$self->{data}}) {
  11         30  
282 9         9 my $match;
283 9 100       19 if(ref $check eq 'CODE') {
284 4         13 $match = $check->($self->{data}->[$idx]);
285             } else {
286 5         7 $match = $self->{data}[$idx] eq $check;
287             }
288 9 100       34 if($match) {
289 2         2 my ($el) = splice @{$self->{data}}, $idx, 1;
  2         7  
290 2 50       9 if($self->{onchange}) {
291 0         0 foreach my $w (@{$self->{onchange}}) {
  0         0  
292 0         0 $w->(drop => $el);
293             }
294             }
295             } else {
296 7         7 ++$idx;
297             }
298             }
299 2         11 return $self;
300             }
301              
302             =head2 clear
303              
304             Empty the arrayref.
305              
306             =cut
307              
308             sub clear : method {
309 1     1 1 5 my $self = shift;
310 1 50       6 if($self->{onchange}) {
311 0         0 my @el = @{ $self->{data} };
  0         0  
312 0         0 foreach my $w (@{$self->{onchange}}) {
  0         0  
313 0         0 $w->(drop => $_) for @el;
314             }
315             }
316 1         3 $self->{data} = [ ];
317 1         6 return $self;
318             }
319              
320             =head2 arrayref
321              
322             Returns the arrayref directly.
323              
324             =cut
325              
326             sub arrayref {
327 0     0 1   my ($self) = @_;
328 0           return $self->{data};
329             }
330              
331             =head2 is_empty
332              
333             Returns true if there's nothing in the arrayref.
334              
335             =cut
336              
337             sub is_empty {
338 0     0 1   my $self = shift;
339 0           return !$self->count;
340             }
341              
342             1;
343              
344             __END__