File Coverage

blib/lib/Mail/Builder/List.pm
Criterion Covered Total %
statement 69 73 94.5
branch 22 30 73.3
condition 18 33 54.5
subroutine 13 14 92.8
pod 8 8 100.0
total 130 158 82.2


line stmt bran cond sub pod time code
1             # ============================================================================
2             package Mail::Builder::List;
3             # ============================================================================
4              
5 8     8   54 use namespace::autoclean;
  8         22  
  8         81  
6 8     8   814 use Moose;
  8         19  
  8         56  
7 8     8   38210 use Mail::Builder::TypeConstraints;
  8         17  
  8         166  
8              
9 8     8   37 use Carp;
  8         16  
  8         7915  
10              
11             our $VERSION = $Mail::Builder::VERSION;
12              
13             has 'type' => (
14             is => 'ro',
15             isa => 'Mail::Builder::Type::Class',
16             required => 1,
17             );
18              
19             has 'list' => (
20             is => 'rw',
21             isa => 'ArrayRef[Object]',
22             default => sub { return [] },
23             trigger => \&_check_list,
24             traits => ['Array'],
25             handles => {
26             length => 'count',
27             #all => 'elements',
28             },
29             );
30              
31             sub _check_list {
32 12     12   31 my ($self,$value) = @_;
33              
34 12         282 my $type = $self->type;
35              
36 12         30 foreach my $element (@$value) {
37 18 50 33     146 unless (blessed $element
38             && $element->isa($type)) {
39 0         0 croak("'$value' is not a '$type'");
40             }
41             }
42 12         273 return;
43             }
44              
45             around 'list' => sub {
46             my $orig = shift;
47             my $self = shift;
48              
49             my $result = $self->$orig(@_);
50              
51             return wantarray ? @{$result} : $result;
52             };
53              
54             around BUILDARGS => sub {
55             my $orig = shift;
56             my $class = shift;
57              
58             if (scalar @_ == 1
59             && ref($_[0]) eq '') {
60             return $class->$orig({ type => $_[0] });
61             } else {
62             return $class->$orig(@_);
63             }
64             };
65              
66              
67             __PACKAGE__->meta->make_immutable;
68              
69             sub _convert_item { ## no critic(RequireArgUnpacking)
70 12     12   37 my ($self) = shift;
71              
72 12 50       42 croak(qq[Params missing])
73             unless scalar @_;
74              
75 12         315 my $type = $self->type;
76              
77 12 100       56 if (blessed($_[0])) {
78 4 100       54 croak(qq[Invalid item added to list: Must be of $type])
79             unless ($_[0]->isa($type));
80 3         9 return $_[0];
81             } else {
82 8         222 my $object = $type->new(@_);
83 8 50 33     104 croak(qq[Could not create $type object])
      33        
84             unless (defined $object
85             && blessed $object
86             && $object->isa($type));
87              
88 8         26 return $object;
89             }
90             }
91              
92             sub convert {
93 1     1 1 4 my ($class,@elements) = @_;
94              
95 1 50 33     8 my $elements_ref = (scalar @elements == 1 && ref $elements[0] eq 'ARRAY') ?
96             $elements[0] : \@elements;
97              
98 1         34 return $class->new(
99             type => ref($elements_ref->[0]),
100             list => $elements_ref,
101             );
102             }
103              
104             sub join { ## no critic(ProhibitBuiltinHomonyms)
105 13     13 1 35 my ($self,$join_string) = @_;
106              
107             return CORE::join $join_string,
108 14         266 grep { $_ }
109 13         55 map { $_->serialize }
  14         51  
110             $self->list;
111             }
112              
113             sub contains {
114 16     16 1 37 my ($self,$compare) = @_;
115              
116 16 50       43 return 0
117             unless (defined $compare);
118              
119 16         62 foreach my $item ($self->list) {
120 24 100 100     108 return 1
121             if (blessed($compare) && $item == $compare);
122 23 100       72 return 1
123             if ($item->compare($compare));
124             }
125 13         45 return 0;
126             }
127              
128             sub reset { ## no critic(ProhibitBuiltinHomonyms)
129 1     1 1 3 my ($self) = @_;
130              
131 1         6 $self->list([]);
132 1         6 return 1;
133             }
134              
135             sub push { ## no critic(RequireArgUnpacking,ProhibitBuiltinHomonyms)
136 0     0 1 0 my ($self) = @_;
137 0         0 return $self->add(@_);
138             }
139              
140             sub remove {
141 3     3 1 8 my ($self,$remove) = @_;
142              
143 3         11 my $list = $self->list;
144              
145             # No params: take last param
146 3 100       9 unless (defined $remove) {
147 1         3 return pop @{$list};
  1         4  
148             # Element
149             } else {
150 2         5 my $new_list = [];
151 2         4 my $old_value;
152 2         3 my $index = 0;
153 2         5 foreach my $item (@{$list}) {
  2         5  
154 7 100 66     71 if (blessed($remove) && $item == $remove
      100        
      33        
      100        
155             || ($remove =~ /^\d+$/ && $index == $remove)
156             || $item->compare($remove)) {
157 2         6 $remove = $item;
158             } else {
159 5         10 CORE::push(@{$new_list},$item);
  5         8  
160             }
161 7         14 $index ++;
162             }
163 2         7 $self->list($new_list);
164              
165             # Return old value
166 2 50       52 return $remove
167             if defined $remove;
168             }
169 0         0 return;
170             }
171              
172             sub add { ## no critic(RequireArgUnpacking)
173 12     12 1 139 my ($self) = shift;
174              
175 12         45 my $item = $self->_convert_item(@_);
176              
177 11 100       39 unless ($self->contains($item)) {
178 10         18 CORE::push(@{$self->list}, $item);
  10         28  
179             }
180              
181 11         40 return $item;
182             }
183              
184              
185             sub item {
186 21     21 1 52 my ($self,$index) = @_;
187              
188 21 50 33     163 $index = 0
189             unless defined $index
190             && $index =~ m/^\d+$/;
191              
192             return
193 21 50 33     132 unless ($index =~ m/^\d+$/
194             && defined $self->list->[$index]);
195              
196 21         63 return $self->list->[$index];
197             }
198              
199             __PACKAGE__->meta->make_immutable;
200              
201             1;
202              
203             =encoding utf8
204              
205             =head1 NAME
206              
207             Mail::Builder::List - Helper module for handling various lists
208              
209             =head1 SYNOPSIS
210              
211             use Mail::Builder;
212            
213             # Create a list that accepts Mail::Builder::Address objects
214             my $list = Mail::Builder::List->new('Mail::Builder::Address');
215            
216             # Add aMail::Builder::Address object
217             $list->add($address_object);
218            
219             # Add an email (Unrecognized values will be passed to the constructor of
220             # the type class - Mail::Builder::Address)
221             $list->add('sasha.nein@psychonauts.org');
222            
223             # Add one more email (Unrecognized values will be passed to the constructor of
224             # the type class - Mail::Builder::Address)
225             $list->add({ email => 'raz.aquato@psychonauts.org', name => 'Razputin'} );
226            
227             # Remove email from list
228             $list->remove('raz.aquato@psychonauts.org');
229            
230             # Remove first element in list
231             $list->remove(1);
232            
233             # Reset list
234             $list->reset;
235            
236             # Add email
237             $list->add('milla.vodello@psychonauts.org','Milla Vodello');
238            
239             # Serialize email list
240             print $list->join(',');
241              
242             =head1 DESCRIPTION
243              
244             This is a helper module for handling various lists (e.g. recipient, attachment
245             lists). The class contains convinient array/list handling functions.
246              
247             =head1 METHODS
248              
249             =head2 Constructor
250              
251             =head3 new
252              
253             my $list = Mail::Builder::List->new(Class name);
254             OR
255             my $list = Mail::Builder::List->new({
256             type => Class name,
257             [ list => ArrayRef, ]
258             });
259              
260             This constructor takes the class name of the objects it should hold. It is
261             only possible to add objects of the given type. It is not possible to change
262             the assigned type later.
263              
264             =head3 convert
265              
266             my $list = Mail::Builder::List->convert(ArrayRef);
267              
268             Constructor that converts an array reference into a Mail::Builder::List
269             object. The list type is defined by the first element of the array.
270              
271             =head2 Public Methods
272              
273             =head3 length
274              
275             Returns the number of items in the list.
276              
277             =head3 add
278              
279             $obj->add(Object);
280             OR
281             $obj->add(Anything)
282              
283             Pushes a new item into the list. The methods either accepts an object or
284             any values. Values will be passed to the C<new> method in the
285             list type class.
286              
287             =head3 push
288              
289             Synonym for L<add>
290              
291             =head3 remove
292              
293             $obj->remove(Object)
294             OR
295             $obj->remove(Index)
296             OR
297             $obj->remove(Anything)
298             OR
299             $obj->remove()
300              
301             Removes the given element from the list. If no parameter is passed to the
302             method the last element from the list will be removed instead.
303              
304             =head3 reset
305              
306             Removes all elements from the list, leaving an empty list.
307              
308             =head3 item
309              
310             my $list_item = $obj->item(Index)
311              
312             Returns the list item with the given index.
313              
314             =head3 join
315              
316             my $list = $obj->join(String)
317              
318             Serializes all items in the list and joins them using the given string.
319              
320             =head3 contains
321              
322             $obj->contains(Object)
323             or
324             $obj->contains(Anything)
325              
326             Returns true if the given object is in the list. You can either pass an
327             object or scalar value. Uses the L<compare> method from the list type class.
328              
329             =head2 Accessors
330              
331             =head3 type
332              
333             Returns the class name which was initially passed to the constructor.
334              
335             =head3 list
336              
337             Raw list as list or array reference.
338              
339             =head1 AUTHOR
340              
341             MaroÅ¡ Kollár
342             CPAN ID: MAROS
343             maros [at] k-1.com
344             http://www.k-1.com
345              
346             =cut