File Coverage

lib/LocalOverride.pm
Criterion Covered Total %
statement 38 38 100.0
branch 14 14 100.0
condition 2 3 66.6
subroutine 7 7 100.0
pod 0 1 0.0
total 61 63 96.8


line stmt bran cond sub pod time code
1             package LocalOverride;
2              
3 3     3   58966 use strict;
  3         8  
  3         99  
4 3     3   15 use warnings;
  3         6  
  3         87  
5              
6 3     3   2546 use PerlIO::scalar;
  3         1310  
  3         270  
7              
8             our $VERSION = 1.000000;
9              
10             our $base_namespace = '';
11             our $core_only = 0;
12             our $local_prefix = 'Local';
13              
14 3     3   1212 BEGIN { unshift @INC, \&require_local }
15              
16             my %already_seen;
17              
18             sub require_local {
19             # Exit immediately if we're not processing overrides
20 36 100   36 0 242233 return if $core_only;
21              
22 28         51 my (undef, $filename) = @_;
23              
24             # Keep track of what files we've already seen to avoid infinite loops
25 28 100       8496 return if exists $already_seen{$filename};
26 10         25 $already_seen{$filename}++;
27              
28             # We only want to check overrides in $base_namespace
29 10 100       434 return unless $filename =~ /^$base_namespace/;
30              
31             # OK, that all passed, so we can load up the actual files
32             # Get the original version first, then overlay the local version
33 9         80 require $filename;
34              
35 9         5824 my $local_file = $filename;
36 9 100       29 if ($base_namespace) {
37 2         31 $local_file =~ s[^$base_namespace][${base_namespace}/$local_prefix];
38             } else {
39             # Empty base namespace is probably a bad idea, but it should be
40             # handled anyhow
41 7         22 $local_file = $local_prefix . '/' . $local_file;
42             }
43 9         32 $already_seen{$local_file}++;
44             # Failure to load local version is not fatal, since it may not exist
45 9         15 eval { require $local_file };
  9         79  
46              
47 9         1299 open my $fh, '<', \'1';
48 9         368 return $fh;
49             }
50              
51             sub import {
52 4     4   870 my (undef, %opts) = @_;
53              
54 4 100       18 if ($opts{base_namespace}) {
55 1         1 $base_namespace = $opts{base_namespace};
56 1         3 delete $opts{base_namespace};
57             }
58              
59 4 100       16 if ($opts{core_only}) {
60 1         1 $core_only = $opts{core_only};
61 1         2 delete $opts{core_only};
62             }
63              
64 4 100       16 if ($opts{local_prefix}) {
65 1         2 $local_prefix = $opts{local_prefix};
66 1         1 delete $opts{local_prefix};
67             }
68              
69 4         3645 warn "LocalOverride loaded with unrecognized option $_\n" for keys %opts;
70             }
71              
72             sub unimport {
73 1   66 1   3005 @INC = grep { !(ref $_ && $_ == \&require_local) } @INC;
  11         59  
74             }
75              
76             1;
77              
78              
79              
80             =pod
81              
82             =head1 NAME
83              
84             LocalOverride - Transparently override subs with those in local module versions
85              
86             =head1 VERSION
87              
88             version 1.000
89              
90             =head1 SYNOPSIS
91              
92             use LocalOverride;
93              
94             # Load Foo, followed by Local::Foo
95             use Foo;
96              
97             Or
98              
99             use LocalOverride ( base_namespace => 'MyApp', local_prefix => 'Custom' );
100              
101             # Just load Moose, since it's not in MyApp::*
102             use Moose;
103              
104             # Load MyApp::Base, followed by MyApp::Custom::Base
105             use MyApp::Base
106              
107             =head1 DESCRIPTION
108              
109             When this module is loaded and you C or C another module, it
110             will automatically check for whether any local modules are present which
111             override code from the module being loaded. By default, these override
112             modules are placed in the file system at a location corresponding to
113             C, however their code should be within the
114             same package as the original module:
115              
116             In /path/to/libs/Foo.pm:
117              
118             package Foo;
119              
120             sub bar { ... }
121             sub baz { ... }
122              
123              
124             In /path/to/libs/Local/Foo.pm:
125              
126             package Foo; # Not Local::Foo!
127              
128             sub bar { ... } # Replaces the original sub Foo::bar
129              
130             This is, obviously, a very extreme approach and one which should be used
131             only after due consideration, as it can create bugs which are very difficult
132             to debug if not used carefully.
133              
134             If warnings are enabled, this will generate warnings about any redefined
135             subroutines. You will typically want to include
136              
137             no warnings 'redefine';
138              
139             in your override modules to prevent this.
140              
141             =head1 CONFIGURATION
142              
143             The following configuration settings can be used to enable/disable loading of
144             local override modules or customize where they are located. They can be set
145             either by including them as parameters to C or by setting
146             C<$LocalOverride::[option]>.
147              
148             Note that, because C is processed at compile-time, any changes made using
149             the latter method must be made within a C block if they are intended to
150             affect modules that you C. This is not necessary for modules you
151             C, as C is processed within the normal flow of the program.
152              
153             =head2 base_namespace
154              
155             B ''
156              
157             Local overrides will only be loaded for modules which fall within the base
158             namespace. For example, if C<$base_namespace> is set to 'Foo', then an
159             override module will be loaded for C, but not for C or C.
160              
161             If C<$base_namespace> is set, overrides will be searched for within that
162             namespace, such as C (I C) in the
163             previous paragraph's example case.
164              
165             The default setting, an empty string, will attempt to load local overrides
166             for I modules. Setting C<$base_namespace> is recommended in order to
167             avoid this.
168              
169             =head2 core_only
170              
171             B 0
172              
173             If this is set to a true value, then local override processing will be
174             disabled.
175              
176             This module can also be disabled with C if you prefer to
177             unload it more completely.
178              
179             =head2 local_prefix
180              
181             B 'Local'
182              
183             The local prefix defines the namespace (within C<$base_namespace>) used for
184             local override definitions.
185              
186             =head1 AUTHOR
187              
188             Dave Sherohman
189              
190             =head1 COPYRIGHT AND LICENSE
191              
192             This software is copyright (c) 2010 by Lund University Library Head Office.
193              
194             This is free software; you can redistribute it and/or modify it under
195             the same terms as the Perl 5 programming language system itself.
196              
197             =cut
198              
199              
200             __END__