Filename | /usr/lib/perl5/Template/Plugins.pm |
Statements | Executed 30 statements in 1.43ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 31µs | 31µs | _init | Template::Plugins::
1 | 1 | 1 | 30µs | 38µs | BEGIN@26 | Template::Plugins::
1 | 1 | 1 | 17µs | 62µs | BEGIN@29 | Template::Plugins::
1 | 1 | 1 | 16µs | 43µs | BEGIN@27 | Template::Plugins::
1 | 1 | 1 | 13µs | 99µs | BEGIN@28 | Template::Plugins::
0 | 0 | 0 | 0s | 0s | __ANON__[:239] | Template::Plugins::
0 | 0 | 0 | 0s | 0s | _dump | Template::Plugins::
0 | 0 | 0 | 0s | 0s | _load | Template::Plugins::
0 | 0 | 0 | 0s | 0s | fetch | Template::Plugins::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | #============================================================= -*-Perl-*- | ||||
2 | # | ||||
3 | # Template::Plugins | ||||
4 | # | ||||
5 | # DESCRIPTION | ||||
6 | # Plugin provider which handles the loading of plugin modules and | ||||
7 | # instantiation of plugin objects. | ||||
8 | # | ||||
9 | # AUTHORS | ||||
10 | # Andy Wardley <abw@wardley.org> | ||||
11 | # | ||||
12 | # COPYRIGHT | ||||
13 | # Copyright (C) 1996-2006 Andy Wardley. All Rights Reserved. | ||||
14 | # Copyright (C) 1998-2000 Canon Research Centre Europe Ltd. | ||||
15 | # | ||||
16 | # This module is free software; you can redistribute it and/or | ||||
17 | # modify it under the same terms as Perl itself. | ||||
18 | # | ||||
19 | # REVISION | ||||
20 | # $Id: Plugins.pm 1179 2008-12-09 19:29:21Z abw $ | ||||
21 | # | ||||
22 | #============================================================================ | ||||
23 | |||||
24 | package Template::Plugins; | ||||
25 | |||||
26 | 3 | 41µs | 2 | 46µs | # spent 38µs (30+8) within Template::Plugins::BEGIN@26 which was called:
# once (30µs+8µs) by Template::Config::load at line 26 # spent 38µs making 1 call to Template::Plugins::BEGIN@26
# spent 8µs making 1 call to strict::import |
27 | 3 | 36µs | 2 | 70µs | # spent 43µs (16+27) within Template::Plugins::BEGIN@27 which was called:
# once (16µs+27µs) by Template::Config::load at line 27 # spent 43µs making 1 call to Template::Plugins::BEGIN@27
# spent 27µs making 1 call to warnings::import |
28 | 3 | 37µs | 2 | 185µs | # spent 99µs (13+86) within Template::Plugins::BEGIN@28 which was called:
# once (13µs+86µs) by Template::Config::load at line 28 # spent 99µs making 1 call to Template::Plugins::BEGIN@28
# spent 86µs making 1 call to base::import |
29 | 3 | 1.24ms | 2 | 107µs | # spent 62µs (17+45) within Template::Plugins::BEGIN@29 which was called:
# once (17µs+45µs) by Template::Config::load at line 29 # spent 62µs making 1 call to Template::Plugins::BEGIN@29
# spent 45µs making 1 call to Exporter::import |
30 | |||||
31 | 1 | 900ns | our $VERSION = 2.77; | ||
32 | 1 | 1µs | our $DEBUG = 0 unless defined $DEBUG; | ||
33 | 1 | 600ns | our $PLUGIN_BASE = 'Template::Plugin'; | ||
34 | 1 | 27µs | our $STD_PLUGINS = { | ||
35 | 'assert' => 'Template::Plugin::Assert', | ||||
36 | 'autoformat' => 'Template::Plugin::Autoformat', | ||||
37 | 'cgi' => 'Template::Plugin::CGI', | ||||
38 | 'datafile' => 'Template::Plugin::Datafile', | ||||
39 | 'date' => 'Template::Plugin::Date', | ||||
40 | 'debug' => 'Template::Plugin::Debug', | ||||
41 | 'directory' => 'Template::Plugin::Directory', | ||||
42 | 'dbi' => 'Template::Plugin::DBI', | ||||
43 | 'dumper' => 'Template::Plugin::Dumper', | ||||
44 | 'file' => 'Template::Plugin::File', | ||||
45 | 'format' => 'Template::Plugin::Format', | ||||
46 | 'html' => 'Template::Plugin::HTML', | ||||
47 | 'image' => 'Template::Plugin::Image', | ||||
48 | 'iterator' => 'Template::Plugin::Iterator', | ||||
49 | 'latex' => 'Template::Plugin::Latex', | ||||
50 | 'pod' => 'Template::Plugin::Pod', | ||||
51 | 'scalar' => 'Template::Plugin::Scalar', | ||||
52 | 'table' => 'Template::Plugin::Table', | ||||
53 | 'url' => 'Template::Plugin::URL', | ||||
54 | 'view' => 'Template::Plugin::View', | ||||
55 | 'wrap' => 'Template::Plugin::Wrap', | ||||
56 | 'xml' => 'Template::Plugin::XML', | ||||
57 | 'xmlstyle' => 'Template::Plugin::XML::Style', | ||||
58 | }; | ||||
59 | |||||
60 | |||||
61 | #======================================================================== | ||||
62 | # -- PUBLIC METHODS -- | ||||
63 | #======================================================================== | ||||
64 | |||||
65 | #------------------------------------------------------------------------ | ||||
66 | # fetch($name, \@args, $context) | ||||
67 | # | ||||
68 | # General purpose method for requesting instantiation of a plugin | ||||
69 | # object. The name of the plugin is passed as the first parameter. | ||||
70 | # The internal FACTORY lookup table is consulted to retrieve the | ||||
71 | # appropriate factory object or class name. If undefined, the _load() | ||||
72 | # method is called to attempt to load the module and return a factory | ||||
73 | # class/object which is then cached for subsequent use. A reference | ||||
74 | # to the calling context should be passed as the third parameter. | ||||
75 | # This is passed to the _load() class method. The new() method is | ||||
76 | # then called against the factory class name or prototype object to | ||||
77 | # instantiate a new plugin object, passing any arguments specified by | ||||
78 | # list reference as the second parameter. e.g. where $factory is the | ||||
79 | # class name 'MyClass', the new() method is called as a class method, | ||||
80 | # $factory->new(...), equivalent to MyClass->new(...) . Where | ||||
81 | # $factory is a prototype object, the new() method is called as an | ||||
82 | # object method, $myobject->new(...). This latter approach allows | ||||
83 | # plugins to act as Singletons, cache shared data, etc. | ||||
84 | # | ||||
85 | # Returns a reference to a plugin, (undef, STATUS_DECLINE) to decline | ||||
86 | # the request or ($error, STATUS_ERROR) on error. | ||||
87 | #------------------------------------------------------------------------ | ||||
88 | |||||
89 | sub fetch { | ||||
90 | my ($self, $name, $args, $context) = @_; | ||||
91 | my ($factory, $plugin, $error); | ||||
92 | |||||
93 | $self->debug("fetch($name, ", | ||||
94 | defined $args ? ('[ ', join(', ', @$args), ' ]') : '<no args>', ', ', | ||||
95 | defined $context ? $context : '<no context>', | ||||
96 | ')') if $self->{ DEBUG }; | ||||
97 | |||||
98 | # NOTE: | ||||
99 | # the $context ref gets passed as the first parameter to all regular | ||||
100 | # plugins, but not to those loaded via LOAD_PERL; to hack around | ||||
101 | # this until we have a better implementation, we pass the $args | ||||
102 | # reference to _load() and let it unshift the first args in the | ||||
103 | # LOAD_PERL case | ||||
104 | |||||
105 | $args ||= [ ]; | ||||
106 | unshift @$args, $context; | ||||
107 | |||||
108 | $factory = $self->{ FACTORY }->{ $name } ||= do { | ||||
109 | ($factory, $error) = $self->_load($name, $context); | ||||
110 | return ($factory, $error) if $error; ## RETURN | ||||
111 | $factory; | ||||
112 | }; | ||||
113 | |||||
114 | # call the new() method on the factory object or class name | ||||
115 | eval { | ||||
116 | if (ref $factory eq 'CODE') { | ||||
117 | defined( $plugin = &$factory(@$args) ) | ||||
118 | || die "$name plugin failed\n"; | ||||
119 | } | ||||
120 | else { | ||||
121 | defined( $plugin = $factory->new(@$args) ) | ||||
122 | || die "$name plugin failed: ", $factory->error(), "\n"; | ||||
123 | } | ||||
124 | }; | ||||
125 | if ($error = $@) { | ||||
126 | # chomp $error; | ||||
127 | return $self->{ TOLERANT } | ||||
128 | ? (undef, Template::Constants::STATUS_DECLINED) | ||||
129 | : ($error, Template::Constants::STATUS_ERROR); | ||||
130 | } | ||||
131 | |||||
132 | return $plugin; | ||||
133 | } | ||||
134 | |||||
- - | |||||
137 | #======================================================================== | ||||
138 | # -- PRIVATE METHODS -- | ||||
139 | #======================================================================== | ||||
140 | |||||
141 | #------------------------------------------------------------------------ | ||||
142 | # _init(\%config) | ||||
143 | # | ||||
144 | # Private initialisation method. | ||||
145 | #------------------------------------------------------------------------ | ||||
146 | |||||
147 | # spent 31µs within Template::Plugins::_init which was called:
# once (31µs+0s) by Template::Base::new at line 65 of Template/Base.pm | ||||
148 | 1 | 2µs | my ($self, $params) = @_; | ||
149 | 1 | 4µs | my ($pbase, $plugins, $factory) = | ||
150 | @$params{ qw( PLUGIN_BASE PLUGINS PLUGIN_FACTORY ) }; | ||||
151 | |||||
152 | 1 | 900ns | $plugins ||= { }; | ||
153 | |||||
154 | # update PLUGIN_BASE to an array ref if necessary | ||||
155 | 1 | 700ns | $pbase = [ ] unless defined $pbase; | ||
156 | 1 | 1µs | $pbase = [ $pbase ] unless ref($pbase) eq 'ARRAY'; | ||
157 | |||||
158 | # add default plugin base (Template::Plugin) if set | ||||
159 | 1 | 1µs | push(@$pbase, $PLUGIN_BASE) if $PLUGIN_BASE; | ||
160 | |||||
161 | 1 | 1µs | $self->{ PLUGIN_BASE } = $pbase; | ||
162 | 1 | 12µs | $self->{ PLUGINS } = { %$STD_PLUGINS, %$plugins }; | ||
163 | 1 | 1µs | $self->{ TOLERANT } = $params->{ TOLERANT } || 0; | ||
164 | 1 | 800ns | $self->{ LOAD_PERL } = $params->{ LOAD_PERL } || 0; | ||
165 | 1 | 900ns | $self->{ FACTORY } = $factory || { }; | ||
166 | 1 | 1µs | $self->{ DEBUG } = ( $params->{ DEBUG } || 0 ) | ||
167 | & Template::Constants::DEBUG_PLUGINS; | ||||
168 | |||||
169 | 1 | 7µs | return $self; | ||
170 | } | ||||
171 | |||||
- - | |||||
174 | #------------------------------------------------------------------------ | ||||
175 | # _load($name, $context) | ||||
176 | # | ||||
177 | # Private method which attempts to load a plugin module and determine the | ||||
178 | # correct factory name or object by calling the load() class method in | ||||
179 | # the loaded module. | ||||
180 | #------------------------------------------------------------------------ | ||||
181 | |||||
182 | sub _load { | ||||
183 | my ($self, $name, $context) = @_; | ||||
184 | my ($factory, $module, $base, $pkg, $file, $ok, $error); | ||||
185 | |||||
186 | if ($module = $self->{ PLUGINS }->{ $name } || $self->{ PLUGINS }->{ lc $name }) { | ||||
187 | # plugin module name is explicitly stated in PLUGIN_NAME | ||||
188 | $pkg = $module; | ||||
189 | ($file = $module) =~ s|::|/|g; | ||||
190 | $file =~ s|::|/|g; | ||||
191 | $self->debug("loading $module.pm (PLUGIN_NAME)") | ||||
192 | if $self->{ DEBUG }; | ||||
193 | $ok = eval { require "$file.pm" }; | ||||
194 | $error = $@; | ||||
195 | } | ||||
196 | else { | ||||
197 | # try each of the PLUGIN_BASE values to build module name | ||||
198 | ($module = $name) =~ s/\./::/g; | ||||
199 | |||||
200 | foreach $base (@{ $self->{ PLUGIN_BASE } }) { | ||||
201 | $pkg = $base . '::' . $module; | ||||
202 | ($file = $pkg) =~ s|::|/|g; | ||||
203 | |||||
204 | $self->debug("loading $file.pm (PLUGIN_BASE)") | ||||
205 | if $self->{ DEBUG }; | ||||
206 | |||||
207 | $ok = eval { require "$file.pm" }; | ||||
208 | last unless $@; | ||||
209 | |||||
210 | $error .= "$@\n" | ||||
211 | unless ($@ =~ /^Can\'t locate $file\.pm/); | ||||
212 | } | ||||
213 | } | ||||
214 | |||||
215 | if ($ok) { | ||||
216 | $self->debug("calling $pkg->load()") if $self->{ DEBUG }; | ||||
217 | |||||
218 | $factory = eval { $pkg->load($context) }; | ||||
219 | $error = ''; | ||||
220 | if ($@ || ! $factory) { | ||||
221 | $error = $@ || 'load() returned a false value'; | ||||
222 | } | ||||
223 | } | ||||
224 | elsif ($self->{ LOAD_PERL }) { | ||||
225 | # fallback - is it a regular Perl module? | ||||
226 | ($file = $module) =~ s|::|/|g; | ||||
227 | eval { require "$file.pm" }; | ||||
228 | if ($@) { | ||||
229 | $error = $@; | ||||
230 | } | ||||
231 | else { | ||||
232 | # this is a regular Perl module so the new() constructor | ||||
233 | # isn't expecting a $context reference as the first argument; | ||||
234 | # so we construct a closure which removes it before calling | ||||
235 | # $module->new(@_); | ||||
236 | $factory = sub { | ||||
237 | shift; | ||||
238 | $module->new(@_); | ||||
239 | }; | ||||
240 | $error = ''; | ||||
241 | } | ||||
242 | } | ||||
243 | |||||
244 | if ($factory) { | ||||
245 | $self->debug("$name => $factory") if $self->{ DEBUG }; | ||||
246 | return $factory; | ||||
247 | } | ||||
248 | elsif ($error) { | ||||
249 | return $self->{ TOLERANT } | ||||
250 | ? (undef, Template::Constants::STATUS_DECLINED) | ||||
251 | : ($error, Template::Constants::STATUS_ERROR); | ||||
252 | } | ||||
253 | else { | ||||
254 | return (undef, Template::Constants::STATUS_DECLINED); | ||||
255 | } | ||||
256 | } | ||||
257 | |||||
258 | |||||
259 | #------------------------------------------------------------------------ | ||||
260 | # _dump() | ||||
261 | # | ||||
262 | # Debug method which constructs and returns text representing the current | ||||
263 | # state of the object. | ||||
264 | #------------------------------------------------------------------------ | ||||
265 | |||||
266 | sub _dump { | ||||
267 | my $self = shift; | ||||
268 | my $output = "[Template::Plugins] {\n"; | ||||
269 | my $format = " %-16s => %s\n"; | ||||
270 | my $key; | ||||
271 | |||||
272 | foreach $key (qw( TOLERANT LOAD_PERL )) { | ||||
273 | $output .= sprintf($format, $key, $self->{ $key }); | ||||
274 | } | ||||
275 | |||||
276 | local $" = ', '; | ||||
277 | my $fkeys = join(", ", keys %{$self->{ FACTORY }}); | ||||
278 | my $plugins = $self->{ PLUGINS }; | ||||
279 | $plugins = join('', map { | ||||
280 | sprintf(" $format", $_, $plugins->{ $_ }); | ||||
281 | } keys %$plugins); | ||||
282 | $plugins = "{\n$plugins }"; | ||||
283 | |||||
284 | $output .= sprintf($format, 'PLUGIN_BASE', "[ @{ $self->{ PLUGIN_BASE } } ]"); | ||||
285 | $output .= sprintf($format, 'PLUGINS', $plugins); | ||||
286 | $output .= sprintf($format, 'FACTORY', $fkeys); | ||||
287 | $output .= '}'; | ||||
288 | return $output; | ||||
289 | } | ||||
290 | |||||
291 | |||||
292 | 1 | 10µs | 1; | ||
293 | |||||
294 | __END__ |