File Coverage

blib/lib/Module/Optional.pm
Criterion Covered Total %
statement 49 52 94.2
branch 6 10 60.0
condition n/a
subroutine 12 12 100.0
pod n/a
total 67 74 90.5


line stmt bran cond sub pod time code
1             package Module::Optional;
2 5     5   94942 use strict;
  5         12  
  5         193  
3 5     5   54 use warnings;
  5         10  
  5         227  
4              
5             BEGIN {
6 5     5   38 use vars qw ($VERSION $AUTOLOAD);
  5         13  
  5         307  
7 5     5   238 $VERSION = 0.03;
8             }
9              
10             =head1 NAME
11              
12             Module::Optional - Breaking module dependency chains
13              
14             =head1 SYNOPSIS
15              
16             use Bar::Dummy qw();
17             use Module::Optional Bar;
18              
19             =head1 ABSTRACT
20              
21             This module provides a way of using a module which may or may not be installed
22             on the target machine. If the module is available it behaves as a straight
23             use. If the module is not available, subs are repointed to their equivalents
24             in a dummy namespace.
25              
26             =head1 DESCRIPTION
27              
28             Suppose you are the developer of module C, which uses functionality
29             from the highly controversial module C. You actually quite like C,
30             and want to reuse its functionality in your C module. But, many people
31             will refuse to install C as it needs C. Maybe C is failing
32             tests or is misbehaving on some platforms.
33              
34             Making C an optional module will allow users to run C that don't
35             have C installed. For L users, this involves changing
36             the status of the C dependency from C to C.
37              
38             To use this module, you need to set up a namespace C. The
39             recommended way of doing this is to ship lib/Bar/Dummy.pm with your module.
40             This could be shipped as a standalone module. A dummy module for
41             C is shipped with Module::Optional, as this was the
42             original motivation for the module. If there are other common candidates
43             for dummying, petition me, and I'll include them in the Module::Optional
44             distribution.
45              
46             =head2 Using an optional module
47              
48             Place the lines of code in the following order:
49              
50             use Bar::Dummy qw();
51             use Module::Optional qw(Bar quux wibble wobble);
52              
53             Always set up the dummy module first, but don't import anything - this
54             is to avoid warnings about redefined subroutines if the real Bar is
55             installed on the target machine. Module::Optional will do the importing:
56             quux wibble and wobble from the real Bar if it exists, or from Bar::Dummy
57             if it doesn't.
58              
59             =head2 Asking for a module version
60              
61             If you need a version of the module or later, this can be done thus:
62              
63             use Bar::Dummy qw();
64             use Module::Optional qw(Bar 0.07 quux wibble wobble);
65              
66             If version 0.07 or later of Bar is not available, the dummy is used.
67              
68             =head2 Suppressing the module
69              
70             You will probably be developing your module on a platform that does have
71             Bar installed (I hope). However, you need to be able to tell what happens
72             on systems without Bar. To do this, run the following (example is Unix):
73              
74             MODULE_OPTIONAL_SKIP=1 make test
75              
76             You also want to do this in tests for the dummy module that you are
77             providing. (You are providing tests for this module?) This can easily be
78             done with a begin block at the top of the test:
79              
80             BEGIN {
81             local $ENV{MODULE_OPTIONAL_SKIP} = 1;
82             use Module::Optional qw(Params::Validate);
83             }
84              
85             =head2 Writing a ::Dummy Module
86              
87             You provide a namespace suffixed with ::Dummy containing subs corresponding
88             to all the subs and method calls for the optional module. You should also
89             provide the same exports as the module itself performs.
90              
91             Adhere strictly to any prototypes in the optional module.
92              
93             An example of a dummy module is Params::Validate::Dummy, provided in
94             this distribution.
95              
96             =head1 INTERNALS
97              
98             Module::Optional performs two types of redirection for the missing module.
99             Firstly via @ISA inheritance - Foo::Bar inherits from Foo::Bar::Dummy.
100              
101             Secondly, an AUTOLOAD method is added to Foo::Bar, which will catch calls
102             to subs in this namespace.
103              
104             =head1 BUGS
105              
106             Please report bugs to rt.cpan.org by posting to
107             bugs-module-optional@rt.cpan.org or visiting
108             https://rt.cpan.org/Public/Dist/Display.html?Name=Module-Optional.
109              
110             =head1 AUTHOR
111              
112             Ivor Williams
113             ivorw-mod-opt at xemaps.com
114              
115             =head1 COPYRIGHT
116              
117             This program is free software; you can redistribute
118             it and/or modify it under the same terms as Perl itself.
119              
120             The full text of the license can be found in the
121             LICENSE file included with this module.
122              
123             =head1 SEE ALSO
124              
125             L, L, L.
126              
127             =cut
128              
129 5     5   26 use Carp;
  5         22  
  5         1114  
130              
131             sub import {
132 4     4   33 my $this = shift;
133 4 50       24 my $module = shift or croak "Module name not passed";
134 4         13 my $calling_pkg = (caller())[0];
135 4         8 local $"=' ';
136 4         37 my $evs = <
137              
138             package $calling_pkg;
139             use $module qw(@_);
140             EVAL
141              
142 4         21 $evs =~ s/\sqw\(\)//; # @EXPORT for empty arg list
143 3 100   3   3629 eval ($ENV{MODULE_OPTIONAL_SKIP} ? "'poo" : $evs);
  2         17433  
  2         248  
  4         224  
144 4 100       32 if ($@) {
145             # warn "Eval failed: $@";
146 5     5   28 no strict 'refs';
  5         16  
  5         1535  
147              
148 3         5 push @{$module.'::ISA'},$module.'::Dummy';
  3         54  
149 3         8 *{"${module}::AUTOLOAD"} = \&_autoload;
  3         18  
150 3         56 $evs =~ s/$module/${module}::Dummy/;
151 3         12 $evs =~ s/qw\(\d\S+\s/qw(/;
152 2     2   498 eval $evs;
  1         1  
  1         41  
  3         196  
153             }
154             # else {
155             # warn "eval successful: $evs";
156             # }
157             }
158              
159             sub _autoload {
160 1     1   896 my ($mod,$func) = $AUTOLOAD =~ /(.+)::(\w+)$/;
161 1         3 my $dummy_mod = "${mod}::Dummy";
162 1         5 my $dummy_sub = "${dummy_mod}::$func";
163              
164 1 50       14 if (!$dummy_mod->can($func)) {
165 0 0       0 croak "No sub $func default for optional module $mod"
166             unless $dummy_mod->can('AUTOLOAD');
167 5     5   30 no strict 'refs';
  5         8  
  5         296  
168              
169 0         0 goto &{"${dummy_mod}::AUTOLOAD"};
  0         0  
170             }
171              
172 5     5   27 no strict 'refs';
  5         10  
  5         322  
173 1         7 *$AUTOLOAD = \&$dummy_sub;
174 1         5 goto &$AUTOLOAD;
175             }
176             1; #this line is important and will help the module return a true value
177             __END__