File Coverage

blib/lib/Data/Package.pm
Criterion Covered Total %
statement 54 56 96.4
branch 14 18 77.7
condition 1 3 33.3
subroutine 12 12 100.0
pod 3 3 100.0
total 84 92 91.3


line stmt bran cond sub pod time code
1             package Data::Package;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Data::Package - Base class for packages that are purely data
8              
9             =head1 SYNOPSIS
10            
11             ### Using a Data::Package
12            
13             use Global::Config;
14            
15             # Get the data in the default or a prefered format
16             Global::Config->get;
17             Global::Config->get('Config::Tiny');
18            
19             # Can we get the data in a particular format?
20             Global::Config->provides('Config::Tiny');
21            
22             ### Creating a data package
23            
24             package Global::Config;
25            
26             use strict;
27             use base 'Data::Package';
28             use Config::Tiny ();
29            
30             # Load and return the data as a Config::Tiny object.
31             sub __as_Config_Tiny {
32             local $/;
33             Config::Tiny->read_string();
34             }
35            
36             1;
37            
38             __DATA__
39            
40             [section]
41             foo=1
42             bar=2
43              
44             =head1 INTRODUCTION
45              
46             In the CPAN, a variety of different mechanisms are used by a variety
47             of different authors in order to provide medium to large amounts of
48             data to support the functionality contained in theirs or other people's
49             modules.
50              
51             In this author's opinion these mechanisms are almost never clean
52             and elegant and are often quite ugly. One of the worst examples was a
53             module that converted the Arial font into a 2.7meg perl module.
54              
55             Why exactly the authors are having to resort to these measures is often
56             unclear, although I suspect it is primarily the ease with which modules
57             can be found (compared to data files). Regardless, one thing is very
58             clear.
59              
60             There is B obvious, easy and universal way in which to create and
61             deliver a "Data Product" via CPAN. A data product is a package in where
62             there is little or more likely B functionality or code, and all of
63             the "value" in the package is contained in the data itself.
64              
65             Within the global and unique namespace of perl, most of the packages
66             represent code in the form of APIs. However this does not mean that
67             code is the B thing that is capable of reserving a package name.
68              
69             =head1 DESCRIPTION
70              
71             C provides the core of what is hoped will be a highly
72             scalable and extendable API to create data packages and data products
73             that can be delivered via the CPAN (and thus anywhere else).
74              
75             It provides a minimal API that separates how the developer obtains the
76             data in their code from the methods by which the data is actually obtained,
77             installed, loaded, parsed and accessed.
78              
79             The intent is that the consumer of the data should not have to know or care
80             B the data is obtained, just that they are always able to obtain the
81             data when they want in the format they want.
82              
83             It also allows the author or provider of the data to assign the data to
84             a unique location within the perl namespace. The can then change or improve
85             the underlying install, storage and loading mechanisms without the need for
86             any code using that data to have to be changed.
87              
88             =head2 API Overview
89              
90             The core Data::Package API requires that only only two static methods
91             be defined, and probably only one matters if you wrote both the data
92             package, B code that is using it.
93              
94             In the simplest and (probably) most common case, where the data package
95             returns only a single known object type, you should only have to load
96             the module and then get the data from it.
97              
98             use My::Data::Package;
99            
100             $Data = My::Data::Package->get;
101              
102             For more complex cases where the data package is capable of providing the
103             data in several formats, you can use the C method to find out what
104             types of object the data package is capable of providing.
105              
106             @classes = My::Data::Package->provides;
107              
108             Your code will most likely simply be confirming that the data is available
109             in a particular format. Once you know you are able to get it in the format
110             that you want, you can simple do the following.
111              
112             $Data = My::Data::Package->get('Object::Type');
113              
114             =head1 STATUS
115              
116             The current implementation is considered to be a proof of concept only.
117              
118             It should work, and I do want to know about bugs, but it's a little
119             early to be relying on it yet for production work. It does not have
120             a sufficiently complete unit test library for starters.
121              
122             About half the implementation is done by pulling in functionality from
123             other dependant modules, which are not completely production-standard
124             themselves (in the case of L. For a proper production
125             grade version, we probably shouldn't have any dependencies.
126              
127             However, the API itself is stable and final, and you can write code
128             that uses this package safely, and any upgrades down the line should
129             not affect it.
130              
131             =head1 METHODS
132              
133             =cut
134              
135 3     3   26734 use 5.005;
  3         9  
  3         125  
136 3     3   16 use strict;
  3         5  
  3         105  
137 3     3   3329 use Class::Inspector ();
  3         14357  
  3         75  
138 3     3   3497 use Params::Util qw{ _CLASS };
  3         16631  
  3         247  
139 3     3   3608 use Params::Coerce ();
  3         9016  
  3         76  
140              
141 3     3   20 use vars qw{$VERSION};
  3         7  
  3         130  
142             BEGIN {
143 3     3   1007 $VERSION = '1.05';
144             }
145              
146              
147              
148              
149              
150             #####################################################################
151             # Constructor
152              
153             =pod
154              
155             =head2 new
156              
157             The C constructor is provided mainly as a convenience, and to let
158             you create handles to the data that can be passed around easily.
159              
160             Takes no arguments, and returns a new blessed object of the same class
161             that you called it for.
162              
163             =cut
164              
165             sub new {
166 13   33 13 1 63 my $class = ref($_[0]) || "$_[0]";
167 13         27 my $self = \$class;
168 13         70 bless $self, $class;
169             }
170              
171              
172              
173              
174              
175             #####################################################################
176             # Main Methods
177              
178             =pod
179              
180             =head2 provides [ $class ]
181              
182             The C method is used to find the list of formats the data
183             package is capable of providing the data in, although typically it
184             is just going to be one.
185              
186             When called without an argument, the method returns a list of all of
187             the classes that the data can be provides as instantiated objects of.
188              
189             In this first version, it is assumed you are providing the data as some
190             form of object.
191              
192             If provided an argument, the list will be filtered to list only those
193             that are of the object type you specificied. This can be used to either
194             limit the list, or check for a specific class you want.
195              
196             In both cases, the first class returned by C is the same that
197             will be returned by the C method when called with the same (or without
198             an) argument.
199              
200             And either way, the method returns the classes in list context, or the
201             number of classes in scalar context. This also lets you do things like:
202              
203             if ( Data::Thingy->provides('Big::Thing') ) {
204             die "Data::Thingy cannot provide a Big::Thing";
205             }
206              
207             =cut
208              
209             sub provides {
210 20 50   20 1 1554 my $class = ref $_[0] ? ref shift : shift;
211 20         644 my $want = _CLASS(shift);
212              
213             # Get the raw list of classes
214 20         159 my %seen = ();
215 32         89 my @provides = grep { ! $seen{$_}++ }
  32         139  
216 20         84 grep { defined $_ }
217             $class->_provides;
218              
219             # Return the full list unless we were given a filter
220 20 100       77 return @provides unless $want;
221              
222             # Filter for the class we want, loading as needed
223 16         21 my @filtered = ();
224 16         28 foreach my $p ( @provides ) {
225 28 100       102 if ( Class::Inspector->loaded($p) ) {
226              
227             } else {
228 7         880 eval "require $p;";
229 7 100       25618 if ( $@ ) {
230 6         11 next;
231             }
232             }
233 22 100       605 if ( $p->isa($want) ) {
234 14         38 push @filtered, $p;
235             }
236             }
237              
238 16         89 return @filtered;
239             }
240              
241             sub _provides {
242 20     20   29 my $class = shift;
243              
244             # If the class has a @PROVIDES array, we'll use that directly.
245 3     3   17 no strict 'refs';
  3         17  
  3         1693  
246 20 50       21 if ( defined @{"${class}::PROVIDES"} ) {
  20         134  
247 0         0 return @{"${class}::PROVIDES"};
  0         0  
248             }
249              
250             # Scan the class for __as_Foo_Bar methods
251 20 50       86 my $methods = Class::Inspector->methods($class)
252             or die "Error while looking for providor method in $class";
253              
254             # Filter to just provider methods and convert to classes
255 32         118 return map { s/^__as_//; s/_/::/g; $_ }
  32         69  
  32         100  
  162         313  
256 20         3941 grep { /^__as(?:_[^\W\d]\w*)+$/ } @$methods;
257             }
258              
259             =pod
260              
261             =head2 get [ $class ]
262              
263             The C method does whatever is necesary to access and load the data
264             product, and returns it as an object.
265              
266             If the data package is capable of providing the data in more than one
267             format, you can optionally provide an object of the class that you want
268             it in.
269              
270             Returns an object (possibly of a class you specify) or C if it
271             is unable to load the data, or it cannot provide the data in the format
272             that you have requested.
273              
274             =cut
275              
276             sub get {
277 14 50   14 1 15114 my $class = ref $_[0] ? ref shift : shift;
278              
279             # Given that they our subclass did not write it's own version
280             # of the ->get method, they must be using coercion provider
281             # methods.
282              
283             # So lets find what we need to deliver, and then call it.
284 14 100       60 my @classes = $class->provides(@_) or return undef;
285 13         21 my $want = shift @classes;
286              
287             # Leverage coerce to do the actual loading
288 13         66 Params::Coerce::_coerce( $want, $class->new );
289             }
290              
291             1;
292              
293             =pod
294              
295             =head1 SUPPORT
296              
297             Bugs should always be submitted via the CPAN bug tracker
298              
299             L
300              
301             For other issues, contact the maintainer
302              
303             =head1 AUTHOR
304              
305             Adam Kennedy Eadamk@cpan.orgE
306              
307             =head1 COPYRIGHT
308              
309             Copyright 2005-2007 Adam Kennedy.
310              
311             This program is free software; you can redistribute
312             it and/or modify it under the same terms as Perl itself.
313              
314             The full text of the license can be found in the
315             LICENSE file included with this module.
316              
317             =cut