File Coverage

blib/lib/Algorithm/Dependency/Source.pm
Criterion Covered Total %
statement 47 54 87.0
branch 11 20 55.0
condition 6 12 50.0
subroutine 11 12 91.6
pod 5 5 100.0
total 80 103 77.6


line stmt bran cond sub pod time code
1             package Algorithm::Dependency::Source;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Algorithm::Dependency::Source - Implements a source of heirachy items
8              
9             =head1 DESCRIPTION
10              
11             The Algorithm::Dependency::Source class provides an abstract parent class for
12             implementing sources for the heirachy data the algorithm will use. For an
13             example of an implementation of this, see
14             L, which is bundled with the main
15             L package.
16              
17             =head1 METHODS
18              
19             =cut
20              
21 8     8   132 use 5.005;
  8         25  
  8         449  
22 8     8   84 use strict;
  8         23  
  8         254  
23 8     8   45 use Algorithm::Dependency ();
  8         15  
  8         166  
24 8     8   7493 use Params::Util qw{_SET};
  8         63763  
  8         893  
25              
26 8     8   87 use vars qw{$VERSION};
  8         17  
  8         496  
27             BEGIN {
28 8     8   8794 $VERSION = '1.110';
29             }
30              
31              
32              
33              
34              
35             #####################################################################
36             # Constructor
37              
38             =pod
39              
40             =head2 new @arguments
41              
42             Although you cannot directly use the C constructor for
43             C, it will work the same in all subclasses.
44              
45             The constructor takes zero or more subclass specific arguments to define the
46             location of the source of the items, and returns a new object. Alrough it
47             may check that the arguments you passed are valid, the source will usually
48             NOT actually load the items from the source, instead defering the loading
49             until you need to use the items.
50              
51             Returns a new object on success, or C on error.
52              
53             =cut
54              
55             sub new {
56 10     10 1 23 my $class = shift;
57              
58             # This can't be created directly, it must be through
59             # a SUPER::new call
60 10 50       49 if ( $class eq __PACKAGE__ ) {
61 0         0 die "Cannot directly instantiate Algorithm::Dependency::Source."
62             . " You must use a subclass";
63             }
64              
65             # Create the basic object
66 10         70 my $self = bless {
67             # Has the source been loaded
68             loaded => 0,
69              
70             # Indexes
71             items_hash => undef,
72             items_array => undef,
73             }, $class;
74              
75 10         85 $self;
76             }
77              
78             =pod
79              
80             =head2 load
81              
82             The C method is the public method used to actually load the items from
83             their storage location into the the source object. The method will
84             automatically called, as needed, in most circumstances. You would generally
85             only want to use C manually if you think there may be some uncertainty
86             that the source will load correctly, and want to check it will work.
87              
88             Returns true if the items are loaded successfully, or C on error.
89              
90             =cut
91              
92             sub load {
93 10     10 1 6036 my $self = shift;
94              
95             # If this is a reload, clean up in preperation
96 10 50       41 if ( $self->{loaded} ) {
97 0         0 $self->{loaded} = 0;
98 0         0 $self->{items_hash} = undef;
99 0         0 $self->{items_array} = undef;
100             }
101              
102             # Pass through to the real loader
103 10         42 my $items = $self->_load_item_list;
104 10 50       37 return $items unless $items;
105 10 50       358 unless ( _SET($items, 'Algorithm::Dependency::Item') ) {
106 0         0 die( ref($self) . "::_load_item_list did not return an Algorithm::Dependency::Item set" );
107             }
108              
109             # Add the items
110 10         457 foreach my $item ( @$items ) {
111             # Have we added this one already?
112 100         237 my $id = $item->id;
113 100 50       233 if ( $self->{items_hash}->{ $id } ) {
114             # Duplicate entry
115 0         0 return undef;
116             }
117              
118             # Add it
119 100         89 push @{ $self->{items_array} }, $item;
  100         162  
120 100         234 $self->{items_hash}->{$id} = $item;
121             }
122              
123 10         59 $self->{loaded} = 1;
124             }
125              
126             =pod
127              
128             =head2 item $name
129              
130             The C method fetches and returns the item object specified by the
131             name argument.
132              
133             Returns an L object on success, or C if
134             the named item does not exist in the source.
135              
136             =cut
137              
138             sub item {
139 1037     1037 1 1207 my $self = shift;
140 1037 50 33     6407 my $id = (defined $_[0] and ! ref $_[0] and $_[0] ne '') ? shift : return undef;
141 1037 50 33     2616 $self->{loaded} or $self->load or return undef;
142              
143             # Return the item (or undef)
144 1037         4252 $self->{items_hash}->{$id};
145             }
146              
147             =pod
148              
149             =head2 items
150              
151             The C method returns, as a list of objects, all of the items
152             contained in the source. The item objects will be returned in the same order
153             as that in the storage location.
154              
155             Returns a list of L objects on success, or
156             C on error.
157              
158             =cut
159              
160             sub items {
161 14     14 1 3749 my $self = shift;
162 14 50 66     74 $self->{loaded} or $self->load or return undef;
163 14         20 @{ $self->{items_array} };
  14         66  
164             }
165              
166             =pod
167              
168             =head2 missing_dependencies
169              
170             By default, we are leniant with missing dependencies if the item is neved
171             used. For systems where having a missing dependency can be very bad, the
172             C method checks all Items to make sure their
173             dependencies exist.
174              
175             If there are any missing dependencies, returns a reference to an array of
176             their ids. If there are no missing dependencies, returns 0. Returns
177             C on error.
178              
179             =cut
180              
181             sub missing_dependencies {
182 5     5 1 5464 my $self = shift;
183 5 50 66     37 $self->{loaded} or $self->load or return undef;
184            
185             # Merged the depends of all the items, and see if
186             # any are missing.
187 4         20 my %missing = map { $_ => 1 }
  34         80  
188 40         113 grep { ! $self->item($_) }
189 5         34 map { $_->depends }
190             $self->items;
191 5 100       67 %missing ? [ sort keys %missing ] : 0;
192             }
193              
194              
195              
196              
197              
198             #####################################################################
199             # Catch unimplemented methods in subclasses
200              
201             sub _load_item_list {
202 0     0     die "Class $_[0] failed to define the method _load_item_list";
203             }
204              
205             1;
206              
207             =pod
208              
209             =head1 EXTENDING
210              
211             C itself is a fairly thin module, and it
212             is intended that you will probably need to extend it to be able to
213             extract item data from whatever location you have stored them.
214              
215             This is usually a fairly simple two step process.
216              
217             =over 4
218              
219             =item Overload the C method.
220              
221             Assuming your subclass takes some form or argument on creation, you will
222             need to overload the C method to accept the arguments, validate them,
223             and store them in the source object.
224              
225             =item Define the method C<_load_item_list>.
226              
227             Leaving our parent's C method to take care of conflict, errors, and
228             whatever, the C<_load_item_list> method is used to simply create a list of
229             L objects from wherever you store the item,
230             and return them as a list.
231              
232             =back
233              
234             Having completed these two things, your subclass should be completed. For
235             an example of the code, have a look at the source for the simple subclass
236             L.
237              
238             =head1 SUPPORT
239              
240             For general comments, contact the author.
241              
242             To file a bug against this module, in a way you can keep track of, see the
243             CPAN bug tracking system.
244              
245             L
246              
247             =head1 AUTHOR
248              
249             Adam Kennedy Eadamk@cpan.orgE
250              
251             =head1 SEE ALSO
252              
253             L, L
254              
255             =head1 COPYRIGHT
256              
257             Copyright 2003 - 2009 Adam Kennedy.
258              
259             This program is free software; you can redistribute
260             it and/or modify it under the same terms as Perl itself.
261              
262             The full text of the license can be found in the
263             LICENSE file included with this module.
264              
265             =cut