1 package DOM::Tiny::Collection;
7 use Scalar::Util 'blessed';
9 our $VERSION = '0.001';
13 return bless [@_], ref $class || $class;
16 sub TO_JSON { [@{shift()}] }
20 return $self->new(grep { defined && (ref || length) } @$self);
25 return @$self unless $cb;
27 $_->$cb($i++) for @$self;
32 my ($self, $cb) = (shift, shift);
33 return $self->[0] unless $cb;
34 return List::Util::first { $_ =~ $cb } @$self if ref $cb eq 'Regexp';
35 return List::Util::first { $_->$cb(@_) } @$self;
38 sub flatten { $_[0]->new(_flatten(@{$_[0]})) }
41 my ($self, $cb) = (shift, shift);
42 return $self->new(grep { $_ =~ $cb } @$self) if ref $cb eq 'Regexp';
43 return $self->new(grep { $_->$cb(@_) } @$self);
47 join $_[1] // '', map {"$_"} @{$_[0]};
50 sub last { shift->[-1] }
53 my ($self, $cb) = (shift, shift);
54 return $self->new(map { $_->$cb(@_) } @$self);
60 goto &List::Util::reduce;
63 sub reverse { $_[0]->new(reverse @{$_[0]}) }
65 sub shuffle { $_[0]->new(List::Util::shuffle @{$_[0]}) }
67 sub size { scalar @{$_[0]} }
71 return $self->new(@$self[@_]);
77 return $self->new(sort @$self) unless $cb;
82 local (*{"${caller}::a"}, *{"${caller}::b"}) = (\$a, \$b);
85 return $self->new(@sorted);
89 my ($self, $cb) = (shift, shift);
90 $_->$cb(@_) for $self;
94 sub to_array { [@{shift()}] }
97 my ($self, $cb) = (shift, shift);
99 return $self->new(grep { !$seen{$_->$cb(@_)}++ } @$self) if $cb;
100 return $self->new(grep { !$seen{$_}++ } @$self);
104 map { _ref($_) ? _flatten(@$_) : $_ } @_;
107 sub _ref { ref $_[0] eq 'ARRAY' || blessed $_[0] && $_[0]->isa(__PACKAGE__) }
115 DOM::Tiny::Collection - Collection
119 use DOM::Tiny::Collection;
121 # Manipulate collection
122 my $collection = DOM::Tiny::Collection->new(qw(just works));
123 unshift @$collection, 'it';
124 say $collection->join("\n");
127 $collection->map(sub { ucfirst })->shuffle->each(sub {
128 my ($word, $num) = @_;
134 L<DOM::Tiny::Collection> is an array-based container for collections of
135 L<DOM::Tiny> nodes or other items based on L<Mojo::Collection>.
137 # Access array directly to manipulate collection
138 my $collection = DOM::Tiny::Collection->new(1 .. 25);
139 $collection->[23] += 100;
140 say for @$collection;
144 L<DOM::Tiny::Collection> implements the following methods.
148 my $collection = DOM::Tiny::Collection->new(1, 2, 3);
150 Construct a new array-based L<DOM::Tiny::Collection> object.
154 my $array = $collection->TO_JSON;
156 Alias for L</"to_array">.
160 my $new = $collection->compact;
162 Create a new collection with all elements that are defined and not an empty
166 DOM::Tiny::Collection->new(0, 1, undef, 2, '', 3)->compact->join(', ');
170 my @elements = $collection->each;
171 $collection = $collection->each(sub {...});
173 Evaluate callback for each element in collection or return all elements as a
174 list if none has been provided. The element will be the first argument passed
175 to the callback and is also available as C<$_>.
177 # Make a numbered list
178 $collection->each(sub {
185 my $first = $collection->first;
186 my $first = $collection->first(qr/foo/);
187 my $first = $collection->first(sub {...});
188 my $first = $collection->first($method);
189 my $first = $collection->first($method, @args);
191 Evaluate regular expression/callback for, or call method on, each element in
192 collection and return the first one that matched the regular expression, or for
193 which the callback/method returned true. The element will be the first argument
194 passed to the callback and is also available as C<$_>.
197 my $first = $collection->first(sub { $_->$method(@args) });
199 # Find first value that contains the word "dom"
200 my $interesting = $collection->first(qr/dom/i);
202 # Find first value that is greater than 5
203 my $greater = $collection->first(sub { $_ > 5 });
207 my $new = $collection->flatten;
209 Flatten nested collections/arrays recursively and create a new collection with
212 # "1, 2, 3, 4, 5, 6, 7"
213 DOM::Tiny::Collection->new(1, [2, [3, 4], 5, [6]], 7)->flatten->join(', ');
217 my $new = $collection->grep(qr/foo/);
218 my $new = $collection->grep(sub {...});
219 my $new = $collection->grep($method);
220 my $new = $collection->grep($method, @args);
222 Evaluate regular expression/callback for, or call method on, each element in
223 collection and create a new collection with all elements that matched the
224 regular expression, or for which the callback/method returned true. The element
225 will be the first argument passed to the callback and is also available as
229 my $new = $collection->grep(sub { $_->$method(@args) });
231 # Find all values that contain the word "dom"
232 my $interesting = $collection->grep(qr/dom/i);
234 # Find all values that are greater than 5
235 my $greater = $collection->grep(sub { $_ > 5 });
239 my $stream = $collection->join;
240 my $stream = $collection->join("\n");
242 Turn collection into string.
244 # Join all values with commas
245 $collection->join(', ')->say;
249 my $last = $collection->last;
251 Return the last element in collection.
255 my $new = $collection->map(sub {...});
256 my $new = $collection->map($method);
257 my $new = $collection->map($method, @args);
259 Evaluate callback for, or call method on, each element in collection and create
260 a new collection from the results. The element will be the first argument
261 passed to the callback and is also available as C<$_>.
264 my $new = $collection->map(sub { $_->$method(@args) });
266 # Append the word "dom" to all values
267 my $domified = $collection->map(sub { $_ . 'dom' });
271 my $result = $collection->reduce(sub {...});
272 my $result = $collection->reduce(sub {...}, $initial);
274 Reduce elements in collection with callback, the first element will be used as
275 initial value if none has been provided.
277 # Calculate the sum of all values
278 my $sum = $collection->reduce(sub { $a + $b });
280 # Count how often each value occurs in collection
281 my $hash = $collection->reduce(sub { $a->{$b}++; $a }, {});
285 my $new = $collection->reverse;
287 Create a new collection with all elements in reverse order.
291 my $new = $collection->slice(4 .. 7);
293 Create a new collection with all selected elements.
296 DOM::Tiny::Collection->new('A', 'B', 'C', 'D', 'E')->slice(1, 2, 4)->join(' ');
300 my $new = $collection->shuffle;
302 Create a new collection with all elements in random order.
306 my $size = $collection->size;
308 Number of elements in collection.
312 my $new = $collection->sort;
313 my $new = $collection->sort(sub {...});
315 Sort elements based on return value of callback and create a new collection
318 # Sort values case-insensitive
319 my $case_insensitive = $collection->sort(sub { uc($a) cmp uc($b) });
323 $collection = $collection->tap(sub {...});
325 Equivalent to L<Mojo::Base/"tap">.
329 my $array = $collection->to_array;
331 Turn collection into array reference.
335 my $new = $collection->uniq;
336 my $new = $collection->uniq(sub {...});
337 my $new = $collection->uniq($method);
338 my $new = $collection->uniq($method, @args);
340 Create a new collection without duplicate elements, using the string
341 representation of either the elements or the return value of the
345 my $new = $collection->uniq(sub { $_->$method(@args) });
348 DOM::Tiny::Collection->new('foo', 'bar', 'bar', 'baz')->uniq->join(' ');
351 DOM::Tiny::Collection->new([1, 2], [2, 1], [3, 2])->uniq(sub{ $_->[1] })->to_array;
355 Report any issues on the public bugtracker.
359 Dan Book <dbook@cpan.org>
361 =head1 COPYRIGHT AND LICENSE
363 This software is Copyright (c) 2015 by Dan Book.
365 This is free software, licensed under:
367 The Artistic License 2.0 (GPL Compatible)