File Coverage

blib/lib/Best.pm
Criterion Covered Total %
statement 125 140 89.2
branch 45 52 86.5
condition 12 15 80.0
subroutine 18 20 90.0
pod 1 7 14.2
total 201 234 85.9


line stmt bran cond sub pod time code
1             package Best;
2              
3 20     20   645281 use 5.006;
  20         79  
  20         920  
4              
5 20     20   115 use warnings;
  20         38  
  20         626  
6 20     20   130 use strict;
  20         58  
  20         1427  
7              
8             our $VERSION = '0.15';
9              
10             our %WHICH;
11              
12             # !! is more idiomatic, but messes up vim's hilighter :(
13 20     20   109 use constant TRACE => ! ! $ENV{TRACE_BEST};
  20         33  
  20         2270  
14 20   33 20   109 use constant DEBUG => ! ! ($ENV{DEBUG_BEST} || $ENV{TRACE_BEST});
  20         36  
  20         1604  
15              
16             =head1 NAME
17              
18             Best - Load modules with fallback
19              
20             =head1 SYNOPSIS
21              
22             # Load the best available YAML module with default imports
23             use Best qw/YAML::Syck YAML/;
24             use Best [ qw/YAML::Syck YAML/ ]; # also works
25              
26             # Load a YAML module and import some symbols
27             use Best [ [ qw/YAML::Syck YAML/ ], qw/DumpFile LoadFile/ ];
28              
29             # And fancier stuff...
30              
31             # Load a new enough YAML module
32             use Best qw/YAML 0.58 YAML::Syck/;
33             use Best [ qw/YAML 0.58 YAML::Syck/ ];
34             use Best [ [ 'YAML' => { version => '0.58' },
35             'YAML::Syck' ] ];
36              
37             # Don't load too-new YAML module and import DumpFile
38             use Best [ [ 'YAML' => { ok => sub { YAML->VERSION <= 0.23 } },
39             'YAML::Syck', ],
40             qw/DumpFile/ ];
41              
42             # Use the best Carp module w/ different parameter lists
43             use Best [ [ 'Carp::Clan' => { args => [] },
44             'Carp' ],
45             qw/croak confess carp cluck/ ];
46              
47             # Choose alternate implementations
48             use Best [ [ 'My::Memoize' => { if => sub { $] <= 5.006 } },
49             'Memoize' ],
50             qw/memoize/ ];
51              
52             # Load a CGI module but import nothing
53             use Best [ [ qw/CGI::Simple CGI/ ], [] ]; # akin to 'use CGI ()'
54              
55             =head1 DESCRIPTION
56              
57             Often there are several possible providers of some functionality your
58             program needs, but you don't know which is available at the run site. For
59             example, one of the modules may be implemented with XS, or not in the
60             core Perl distribution and thus not necessarily installed.
61              
62             B attempts to load modules from a list, stopping at the first
63             successful load and failing only if no alternative was found.
64              
65             =head1 FUNCTIONS
66              
67             Most of the functionality B provides is on the C line;
68             there is only one callable functions as such (see C below)
69              
70             If the arguments are either a simple list or a reference to a simple list,
71             the elements are taken to be module names and are loaded in order with
72             their default import function called. Any exported symbols are installed
73             in the caller package.
74              
75              
76             use Best qw/A Simple List/;
77             use Best [ qw/A Simple List/ ];
78              
79             =head2 IMPORT LISTS
80              
81             If the arguments are a listref with a listref as its first element,
82             this interior list is treated as the specification of modules to attempt
83             loading, in order; the rest of the arguments are treated as options to
84             pass on to the loaded module's import function.
85              
86             use Best [ [ qw/A Simple List/ ],
87             qw/Argument list goes here/ ];
88             use Best [ [ qw/A Simple List/ ],
89             [ qw/Argument list goes here/ ] ];
90              
91             To specify a null import (C), pass a zero-element
92             listref as the argument list. In the pathological case where you really
93             want to load a module and pass it C<[]> as an argument, specify C<[
94             [] ]> as the argument list to B.
95              
96             # use Module ();
97             use Best [ [ 'Module' ], [] ];
98              
99             # use Module ( [] );
100             use Best [ [ 'Module' ], [[]] ];
101              
102             To customize the import list for a module, use the C parameter
103             in a hash reference following the module's name.
104              
105             # use Carp::Clan;
106             # use Carp qw/carp croak confess cluck/;
107             use Best [ [ 'Carp::Clan' => { args => [] },
108             'Carp' ],
109             qw/carp croak confess cluck/ ];
110              
111             =head2 MINIMUM VERSIONS
112              
113             You can specify a minimum version for a module by following the module
114             name with something that looks like a number or by a hash reference
115             with a C key.
116              
117             use Best [ [ YAML => '0.58',
118             'YAML::Syck' ] ];
119              
120             use Best [ [ YAML => { version => '0.58' },
121             'YAML::Syck' ] ];
122              
123             =head2 PRE-VALIDATION
124              
125             use Best Module => { if => CODEREF };
126              
127             You may prevent B from attempting to load a module by providing
128             a function as a parameter to C. The module will only be loaded if
129             your function returns a true value.
130              
131             =head2 POST-VALIDATION
132              
133             use Best Module => { ok => CODEREF };
134              
135             You may prevent B from settling on a successfully loaded module
136             by providing a function as a parameter to C. B will follow
137             all of its normal rules to attempt to load your module but can be told
138             to continue retrying if your function returns false.
139              
140             =head2 ARBITRARY CODE
141              
142             A code reference may be substituted for module names. It will be
143             called instead of attempting to load a module. You may do anything you
144             wish in this code. It will be skipped if your code throws an exception
145             or returns false.
146              
147             use Best [ sub {
148             # Decline
149             return;
150             },
151             sub {
152             # Oops!
153             die 'Some error';
154             },
155             'Bad::Module',
156             sub {
157             # Ok!
158             return 1;
159             }, ];
160              
161             =cut
162              
163             # See if dereferencing it throws an error. This is meant to allow
164             # overloaded things to pretend to be array/hashes/coderefs. It also
165             # allows blessed array/hashes/coderefs to pass.
166 20     20   43354 use overload ();
  20         38515  
  20         929  
167              
168             sub does_arrayref {
169 64     64 0 2094 my($thing) = @_;
170 64 100       215 return if not defined $thing;
171            
172             # This does not share the void context hash dereferencing bug
173             # (see C) but I'm being consistent about the
174             # style of returning a value.
175 20     20   137 no warnings;
  20         37  
  20         1820  
176 56         83 return eval { return 1 + @{ $thing } };
  56         72  
  56         594  
177             }
178              
179             sub does_hashref {
180 52     52 0 2680 my($thing) = @_;
181 52 100       149 return if not defined $thing;
182            
183             # There is a bug in 5.8 where void context %{...} doesn't
184             # evaluate. This was originally coded to check $@ but given the
185             # bug, it's not reliable. The fix is to use the value of the
186             # dereference.
187 20     20   95 no warnings;
  20         38  
  20         7790  
188 41         53 return eval { return 1 + %{ $thing } };
  41         58  
  41         312  
189             }
190              
191             sub does_coderef {
192 47     47 0 3028 my($thing) = @_;
193 47   100     165 return overload::Method($thing, '&{}') ||
194             overload::StrVal($thing) =~ /CODE\(0x[\da-f]+\)\z/;
195             }
196              
197             sub looks_like_version {
198 56     56 0 2662 my($version) = @_;
199            
200 56   100     833 return defined $version &&
201             $version =~ /\Av?\d+(?:\.[\d_]+)?\z/;
202             }
203              
204             sub assert {
205             # We'll pretend to be Carp::Assert here.
206 0 0   0 0 0 return 1 if shift @_;
207              
208 0         0 require Carp;
209 0 0       0 Carp::confess(@_ ? @_ : "Something's wrong!");
210             }
211              
212             sub diag {
213             # This output is safe to inline for Test::Harness.
214 0     0 0 0 my($msg) = join '', @_;
215 0         0 my ($package, $file, $line) = caller;
216 0         0 $msg =~ s/^/# /gm;
217 0         0 $msg =~ s/(?
218 0         0 print "# $file on line $line\n$msg";
219 0         0 return 1;
220             }
221              
222             BEGIN {
223 20     20   26865 TRACE and do {
224             require Data::Dumper;
225             Data::Dumper->import('Dumper');
226             };
227             }
228              
229             sub import {
230 19     19   660531 my $caller = caller;
231 19         48 shift @_; # "Best"
232 19 100       145 return unless @_;
233              
234             # Unflatten the module list.
235             #
236             # @_ = [ module arrayref, args arrayref ];
237 18         34 TRACE and diag(Dumper(@_));
238 18 100       74 if (not does_arrayref($_[0])) {
    100          
239             # use Best qw/a b/;
240 3         6 TRACE and diag('Totally flattened module list');
241 3         13 @_ = [[@_]];
242             }
243             elsif (not does_arrayref($_[0][0])) {
244             # use Best [qw/a b/];
245 2         5 TRACE and diag('Semi-flattened module list');
246 2         7 @_ = [@_];
247             }
248             else {
249 13         23 TRACE and diag('Unflattened module list');
250             }
251            
252             # Unflatten the import list.
253             #
254 18         34 TRACE and diag(Dumper(@{$_[0]}));
255 18         30 DEBUG and assert(@{$_[0]} > 0);
256 18 100 100     30 if (@{$_[0]} == 1) {
  18 100       70  
  10         57  
257             # [ module-arrayref, undef ]
258 8         21 $_[0][1] = undef;
259             }
260             elsif (@{$_[0]} == 2 && does_arrayref($_[0][1])) {
261             # [ module-arrayref, args-arrayref ]
262             }
263             else {
264             # [ module-arrayref, LIST ] -> [ module-arrayref, args-arrayref ]
265 6         8 $_[0][1] = [ splice @{$_[0]}, 1 ];
  6         33  
266             }
267            
268 18         33 TRACE and diag(Dumper(@_));
269 18         30 DEBUG and assert(does_arrayref($_[0]));
270 18         29 my @params = @{ shift @_ };
  18         51  
271 18         35 DEBUG and assert(0 == @_);
272              
273            
274             # Promote sugared and param-less modules to have specs:
275             # Module|Code
276             # or Module|Code => VERSION
277             # or Module|Code => HASHREF
278             #
279             # becomes:
280             # [ Module|Code => HASHREF ]
281 18         27 DEBUG and assert(does_arrayref($params[0]));
282 18         21 my @modules = @{ shift @params };
  18         54  
283 18         30 DEBUG and assert(1 == @params);
284 18         77 for (my $i = 0; $i <= $#modules; ++$i) {
285 47         107 my ($module, $param) = @modules[ $i, 1+$i ];
286            
287 47 100       111 if (looks_like_version($param)) {
    100          
288 2         6 $param = { version => $param };
289 2         5 splice @modules, 1+$i, 1;
290             }
291             elsif (does_hashref($param)) {
292 16         39 splice @modules, 1+$i, 1;
293             }
294             else {
295 29         201 $param = {};
296             }
297              
298 47         74 DEBUG and assert(does_hashref($param));
299 47         245 $modules[$i] = [ $module, $param ];
300             }
301              
302 18 50       103 do { require Carp; Carp::croak('What modules shall I load?') }
  0         0  
  0         0  
303             unless @modules;
304              
305              
306             # Unpack the import arguments.
307 18         41 my ($has_args, @args, $no_import);
308 18         47 TRACE and diag(Dumper(@params));
309 18         42 DEBUG and do {
310             assert(1 == @params);
311             assert(!defined $params[0] ||
312             does_arrayref($params[0]));
313             };
314 18 100       135 if (not does_arrayref($params[0])) {
315 8         13 TRACE and diag('no import');
316 8         10 DEBUG and assert(!defined, $params[0]);
317 8         34 shift @params;
318             }
319             else {
320 10         27 $has_args = 1;
321 10         14 @args = @{ shift @params };
  10         105  
322             # valid only if $has_args
323 10         14 DEBUG and diag("has_args => $has_args, \@args => [@args]");
324             $no_import = !@args ||
325 10   66     146 @args == 1 && does_arrayref($args[0]) && @{ $args[0] } == 0; # use Mod ()
326             }
327              
328             #::YY({mod=>$modules,has=>$has_args, arg=>\@args, noimport=>$no_import});
329              
330             # If we do not assume the loaded modules use Exporter, the only
331             # alternative to eval-"" here is to enter a dummy package here and then
332             # scan it and rexport symbols found in it. That is not necessarily
333             # better, because the callee may be picky about its caller. We are in
334             # compile time, and we do need to trust our caller anyway, so what the
335             # hell, let's eval away.
336 18         34 my @errors;
337 18         52 my $first_module = $modules[0][0];
338             MODULE:
339 18         56 for my $thing_to_try (@modules) {
340 46         117 my ($mod, $spec) = @$thing_to_try;
341 46 100       149 if (my $precondition = $spec->{if}) {
342 2 50       6 next MODULE unless $precondition->();
343             }
344 44 100       129 my $version = defined $spec->{version} ? $spec->{version} : '';
345 44 100       212 my $loadargs = $no_import ? '()' :
    100          
    100          
346             $spec->{args} ? '@{$spec->{args}}' :
347             $has_args ? '@args' :
348             '';
349              
350             # Load the module/code
351 44         57 TRACE and diag("Trying $mod");
352 44         56 my $retval;
353 44 100       108 if (does_coderef($mod)) {
354 2         47 $retval = $mod->();
355 2 100       32 eval { die "$mod returned false" if not $retval };
  2         19  
356             }
357             else {
358 42         1774 my $src = qq{
359             package $caller;
360             use $mod $version $loadargs;
361             };
362 42         106 TRACE and diag($src);
363 42     17   3524 $retval = eval $src;
  17     16   240  
  5     9   1922  
  3         27  
  16         189  
  16         7004  
  16         111  
  9         77  
  9         28993  
  9         57  
364             }
365              
366 44 100       7508 if ($@) {
    100          
367 25         77 push @errors, $@;
368 25         86 next MODULE;
369             }
370             elsif (my $postcondition = $spec->{ok}) {
371 2 100       20 next MODULE unless $postcondition->();
372             }
373            
374 18         39 TRACE and diag( "Loaded $mod\n" );
375 18         179 $WHICH{$caller}{$first_module} =
376             $WHICH{__latest}{$first_module} = $mod;
377 18         36663 return $retval;
378             }
379 0         0 require Carp;
380 0         0 Carp::croak('No viable module found: ' . map { "$_\n" } @errors);
  0         0  
381             }
382              
383             =over 4
384              
385             =item which
386              
387             In some cases--for example, class methods in OO modules--you want to know
388             which module B has successfully loaded. Call C<< Best->which >>
389             with the I in your list of module alternatives; the return value
390             is a string containing the name of the loaded module.
391              
392             =back
393              
394             =cut
395              
396             sub which {
397 2     2 1 6046 my($class, $mod) = @_;
398 2         5 my $caller = caller;
399 2 100       16 return $WHICH{$caller}{$mod} if defined $WHICH{$caller}{$mod};
400 1 50       11 return $WHICH{__latest}{$mod} if defined $WHICH{__latest}{$mod};
401 0         0 return;
402             }
403              
404             =head1 DEPLOYMENT ISSUES
405              
406             If you want to use B because you aren't sure your target machine has
407             some modules installed, you may wonder what might warrant the assumption
408             that C would be available, since it isn't a core module itself.
409              
410             One solution is to use L to inline C in your
411             source code. If you don't know this module, check it out -- after you
412             learn what it does, you may decide you don't need B at all! (If your
413             fallback list includes XS modules, though, you may need to stick with us.)
414              
415             C is pure Perl and a single module with a convenient license, so
416             you can also just drop it in your project's C directory.
417              
418             =head1 SEE ALSO
419              
420             =over 4
421              
422             =item L
423              
424             =item L
425              
426             =item L
427              
428             =back
429              
430             =head1 AUTHORS
431              
432             Gaal Yahas, C<< >>
433              
434             Joshua ben Jore, C<< >> has made some significant
435             contributions.
436              
437             =head1 DIAGNOSTICS
438              
439             =over
440              
441             =item What modules shall I load?
442              
443             C wasn't given a list of modules to load.
444              
445             =item No viable module found: %s
446              
447             None of the module alternatives loaded.
448              
449             =item Something's wrong!
450              
451             An assertion failed. This means that either there is a bug in the data
452             you fed to B or a bug in B.
453              
454             =back
455              
456             The code is scattered with assertions and debugging output that can be
457             enabled by putting a true value in the environment variables
458             C and C.
459              
460             Enabling C also enables the debugging code.
461              
462             =head1 BUGS
463              
464             Please report any bugs or feature requests to
465             C, or through the web interface at
466             L.
467             I will be notified, and then you'll automatically be notified of progress on
468             your bug as I make changes.
469              
470             =head1 SUPPORT
471              
472             You can find documentation for this module with the perldoc command.
473              
474             perldoc Best
475              
476             You can also contact the maintainer at the address above or look for information at:
477              
478             =over 4
479              
480             =item * AnnoCPAN: Annotated CPAN documentation
481              
482             L
483              
484             =item * CPAN Ratings
485              
486             L
487              
488             =item * RT: CPAN's request tracker
489              
490             L
491              
492             =item * Search CPAN
493              
494             L
495              
496             =item * Source repository
497              
498             L
499              
500             =back
501              
502             =head1 COPYRIGHT (The "MIT (X11)" License)
503              
504             Copyright (C) 2006-2012 Gaal Yahas
505              
506             This program is distributed under the MIT (X11) License:
507             L
508              
509             Permission is hereby granted, free of charge, to any person
510             obtaining a copy of this software and associated documentation
511             files (the "Software"), to deal in the Software without
512             restriction, including without limitation the rights to use,
513             copy, modify, merge, publish, distribute, sublicense, and/or sell
514             copies of the Software, and to permit persons to whom the
515             Software is furnished to do so, subject to the following
516             conditions:
517              
518             The above copyright notice and this permission notice shall be
519             included in all copies or substantial portions of the Software.
520              
521             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
522             EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
523             OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
524             NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
525             HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
526             WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
527             FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
528             OTHER DEALINGS IN THE SOFTWARE.
529              
530             =cut
531              
532             # These are my favorite debugging tools. Share and enjoy.
533             #sub ::Y { require YAML::Syck; YAML::Syck::Dump(@_) }
534             #sub ::YY { require Carp; Carp::confess(::Y(@_)) }
535              
536             "You'll never see me"; # End of Best