| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#======================================================================== |
|
2
|
|
|
|
|
|
|
# |
|
3
|
|
|
|
|
|
|
# Badger::Factory |
|
4
|
|
|
|
|
|
|
# |
|
5
|
|
|
|
|
|
|
# DESCRIPTION |
|
6
|
|
|
|
|
|
|
# Factory module for loading and instantiating other modules. |
|
7
|
|
|
|
|
|
|
# |
|
8
|
|
|
|
|
|
|
# NOTE |
|
9
|
|
|
|
|
|
|
# This module has grown organically to fit a number of (possibly |
|
10
|
|
|
|
|
|
|
# conflicting) needs. It needs to be completely refactored, and |
|
11
|
|
|
|
|
|
|
# probably split into a number of different factory modules. The |
|
12
|
|
|
|
|
|
|
# TT3 code on which this was originally based had separate base class |
|
13
|
|
|
|
|
|
|
# factory modules for modules (that just got loaded), objects (that |
|
14
|
|
|
|
|
|
|
# got loaded and instantiated) and single objects (that got loaded, |
|
15
|
|
|
|
|
|
|
# created and cached). With hindsight, it was a mistake to try and |
|
16
|
|
|
|
|
|
|
# cram all that functionality into one module. It should be separated |
|
17
|
|
|
|
|
|
|
# into a base class module/API and a number of specialised subclasses. |
|
18
|
|
|
|
|
|
|
# |
|
19
|
|
|
|
|
|
|
# AUTHOR |
|
20
|
|
|
|
|
|
|
# Andy Wardley |
|
21
|
|
|
|
|
|
|
# |
|
22
|
|
|
|
|
|
|
#======================================================================== |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
package Badger::Factory; |
|
25
|
|
|
|
|
|
|
|
|
26
|
24
|
|
|
24
|
|
635
|
use Badger::Debug ':dump'; |
|
|
24
|
|
|
|
|
48
|
|
|
|
24
|
|
|
|
|
150
|
|
|
27
|
|
|
|
|
|
|
use Badger::Class |
|
28
|
24
|
|
|
|
|
373
|
version => 0.01, |
|
29
|
|
|
|
|
|
|
debug => 0, |
|
30
|
|
|
|
|
|
|
base => 'Badger::Prototype Badger::Exporter', |
|
31
|
|
|
|
|
|
|
import => 'class', |
|
32
|
|
|
|
|
|
|
utils => 'plural blessed textlike dotid camel_case', |
|
33
|
|
|
|
|
|
|
words => 'ITEM ITEMS ISA', |
|
34
|
|
|
|
|
|
|
constants => 'PKG ARRAY HASH REFS ONCE DEFAULT LOADED', |
|
35
|
|
|
|
|
|
|
constant => { |
|
36
|
|
|
|
|
|
|
OBJECT => 'object', |
|
37
|
|
|
|
|
|
|
FOUND => 'found', |
|
38
|
|
|
|
|
|
|
FOUND_REF => 'found_ref', |
|
39
|
|
|
|
|
|
|
PATH_SUFFIX => '_PATH', |
|
40
|
|
|
|
|
|
|
NAMES_SUFFIX => '_NAMES', |
|
41
|
|
|
|
|
|
|
DEFAULT_SUFFIX => '_DEFAULT', |
|
42
|
|
|
|
|
|
|
}, |
|
43
|
|
|
|
|
|
|
messages => { |
|
44
|
|
|
|
|
|
|
no_item => 'No item(s) specified for factory to manage', |
|
45
|
|
|
|
|
|
|
no_default => 'No default defined for %s factory', |
|
46
|
|
|
|
|
|
|
bad_ref => 'Invalid reference for %s factory item %s: %s', |
|
47
|
|
|
|
|
|
|
bad_method => qq{Can't locate object method "%s" via package "%s" at %s line %s}, |
|
48
|
24
|
|
|
24
|
|
176
|
}; |
|
|
24
|
|
|
|
|
65
|
|
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
our $RUNAWAY = 0; |
|
51
|
|
|
|
|
|
|
our $AUTOLOAD; |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
*init = \&init_factory; |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub init_factory { |
|
57
|
25
|
|
|
25
|
0
|
72
|
my ($self, $config) = @_; |
|
58
|
25
|
|
|
|
|
108
|
my $class = $self->class; |
|
59
|
25
|
|
|
|
|
73
|
my ($item, $items, $path, $map, $default); |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# 'item' and 'items' can be specified as config params or we look for |
|
62
|
|
|
|
|
|
|
# $ITEM and $ITEMS variables in the current package or those of any |
|
63
|
|
|
|
|
|
|
# base classes. NOTE: $ITEM and $ITEMS must be in the same package |
|
64
|
25
|
100
|
|
|
|
100
|
unless ($item = $config->{ item }) { |
|
65
|
24
|
|
|
|
|
196
|
foreach my $pkg ($class->heritage) { |
|
66
|
24
|
|
|
24
|
|
181
|
no strict REFS; |
|
|
24
|
|
|
|
|
58
|
|
|
|
24
|
|
|
|
|
999
|
|
|
67
|
24
|
|
|
24
|
|
138
|
no warnings ONCE; |
|
|
24
|
|
|
|
|
50
|
|
|
|
24
|
|
|
|
|
26400
|
|
|
68
|
|
|
|
|
|
|
|
|
69
|
24
|
50
|
|
|
|
56
|
if (defined ($item = ${ $pkg.PKG.ITEM })) { |
|
|
24
|
|
|
|
|
79
|
|
|
70
|
24
|
|
|
|
|
66
|
$items = ${ $pkg.PKG.ITEMS }; |
|
|
24
|
|
|
|
|
63
|
|
|
71
|
24
|
|
|
|
|
69
|
last; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
} |
|
75
|
25
|
50
|
|
|
|
76
|
return $self->error_msg('no_item') |
|
76
|
|
|
|
|
|
|
unless $item; |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# use 'items' in config, or grokked from $ITEMS, or guess plural |
|
79
|
25
|
|
33
|
|
|
197
|
$items = $config->{ items } || $items || plural($item); |
|
80
|
|
|
|
|
|
|
|
|
81
|
25
|
|
|
|
|
62
|
my $ipath = $item.PATH_SUFFIX; |
|
82
|
25
|
|
|
|
|
57
|
my $inames = $item.NAMES_SUFFIX; |
|
83
|
25
|
|
|
|
|
64
|
my $idefault = $item.DEFAULT_SUFFIX; |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# Merge all XXXX_PATH package vars with any 'xxxx_path' or 'path' config |
|
86
|
|
|
|
|
|
|
# items. Ditto for XXXX_NAME / 'xxxx_name' / 'aka' and XXXXS/ 'xxxxs' |
|
87
|
|
|
|
|
|
|
|
|
88
|
25
|
|
|
|
|
140
|
my @path = @$config{ path => lc $ipath }; |
|
89
|
25
|
|
|
|
|
72
|
my @names = @$config{ names => lc $inames }; |
|
90
|
|
|
|
|
|
|
|
|
91
|
25
|
|
|
|
|
175
|
$self->{ path } = $class->list_vars(uc $ipath, @path); |
|
92
|
25
|
|
|
|
|
187
|
$self->{ names } = $class->hash_vars(uc $inames, @names); |
|
93
|
25
|
|
|
|
|
137
|
$self->{ $items } = $class->hash_vars(uc $items, $config->{ $items }); |
|
94
|
25
|
|
|
|
|
76
|
$self->{ items } = $items; |
|
95
|
25
|
|
|
|
|
61
|
$self->{ item } = $item; |
|
96
|
25
|
|
|
|
|
72
|
$self->{ loaded } = { }; |
|
97
|
|
|
|
|
|
|
$self->{ no_cache } = defined $config->{ no_cache } # quick hack |
|
98
|
|
|
|
|
|
|
? $config->{ no_cache } |
|
99
|
25
|
50
|
50
|
|
|
205
|
: $class->any_var('NO_CACHE') || 0; |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# see if a 'xxxx_default' or 'default' configuration option is specified |
|
102
|
|
|
|
|
|
|
# or look for the first XXXX_DEFAULT or DEFAULT package variable. |
|
103
|
|
|
|
|
|
|
$default = $config->{ $idefault } |
|
104
|
|
|
|
|
|
|
|| $config->{ default } |
|
105
|
25
|
|
33
|
|
|
395
|
|| $class->any_var_in( uc $idefault, uc DEFAULT ); |
|
106
|
25
|
50
|
|
|
|
84
|
if ($default) { |
|
107
|
0
|
|
|
|
|
0
|
$self->debug("Setting default to $default") if DEBUG; |
|
108
|
0
|
|
|
|
|
0
|
$self->{ default } = $self->{ names }->{ default } = $default; |
|
109
|
|
|
|
|
|
|
} |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
$self->debug( |
|
112
|
|
|
|
|
|
|
"Initialised $item/$items factory\n", |
|
113
|
|
|
|
|
|
|
" Path: ", $self->dump_data($self->{ path }), "\n", |
|
114
|
|
|
|
|
|
|
"Names: ", $self->dump_data($self->{ names }) |
|
115
|
25
|
|
|
|
|
40
|
) if DEBUG; |
|
116
|
|
|
|
|
|
|
|
|
117
|
25
|
|
|
|
|
100
|
return $self; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub path { |
|
121
|
46
|
|
|
46
|
1
|
119
|
my $self = shift->prototype; |
|
122
|
|
|
|
|
|
|
return @_ |
|
123
|
|
|
|
|
|
|
? ($self->{ path } = ref $_[0] eq ARRAY ? shift : [ @_ ]) |
|
124
|
46
|
0
|
|
|
|
138
|
: $self->{ path }; |
|
|
|
50
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
} |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub default { |
|
128
|
1
|
|
|
1
|
1
|
3
|
my $self = shift->prototype; |
|
129
|
|
|
|
|
|
|
return @_ |
|
130
|
|
|
|
|
|
|
? ($self->{ default } = $self->{ names }->{ default } = shift) |
|
131
|
1
|
50
|
|
|
|
7
|
: $self->{ default }; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub items { |
|
135
|
0
|
|
|
0
|
1
|
0
|
my $self = shift->prototype; |
|
136
|
0
|
|
|
|
|
0
|
my $items = $self->{ $self->{ items } }; |
|
137
|
0
|
0
|
|
|
|
0
|
if (@_) { |
|
138
|
0
|
0
|
|
|
|
0
|
my $args = ref $_[0] eq HASH ? shift : { @_ }; |
|
139
|
0
|
|
|
|
|
0
|
@$items{ keys %$args } = values %$args; |
|
140
|
|
|
|
|
|
|
} |
|
141
|
0
|
|
|
|
|
0
|
return $items; |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub item { |
|
145
|
85
|
100
|
|
85
|
1
|
196
|
my $self = shift; $self = $self->prototype unless ref $self; |
|
|
85
|
|
|
|
|
240
|
|
|
146
|
85
|
|
|
|
|
243
|
my ($type, @args) = $self->type_args(@_); |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# In most cases we're expecting $type to be a name (e.g. Table) which we |
|
149
|
|
|
|
|
|
|
# lookup in the items hash, or tack onto one of the module bases in the |
|
150
|
|
|
|
|
|
|
# path (e.g. Template::Plugin) to create a full module name which we load |
|
151
|
|
|
|
|
|
|
# and instantiate (e.g. Template::Plugin::Table). However, the name might |
|
152
|
|
|
|
|
|
|
# be explicitly mapped to a reference of some kind, or the $type passed |
|
153
|
|
|
|
|
|
|
# in could already be a reference (e.g. Template::TT2::Filters allow the |
|
154
|
|
|
|
|
|
|
# first argument to be a code ref or object which implements the required |
|
155
|
|
|
|
|
|
|
# filtering behaviour). In which case, we bypass any name-based lookup |
|
156
|
|
|
|
|
|
|
# and skip straight onto the "look what I found!" phase |
|
157
|
|
|
|
|
|
|
|
|
158
|
85
|
100
|
|
|
|
264
|
return $self->found($type, $type, \@args) |
|
159
|
|
|
|
|
|
|
unless textlike $type; |
|
160
|
|
|
|
|
|
|
|
|
161
|
83
|
|
|
|
|
149
|
$type = $type . ''; # auto-stringify any textlike objects |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# OK, so $type is a string. We'll also create a canonical version of the |
|
164
|
|
|
|
|
|
|
# name (lower case dotted) to provide a case/syntax insensitve fallback |
|
165
|
|
|
|
|
|
|
# (e.g. so "foo.bar" can match against "Foo.Bar", "Foo::Bar" and so on) |
|
166
|
|
|
|
|
|
|
|
|
167
|
83
|
|
|
|
|
199
|
my $items = $self->{ $self->{ items } }; |
|
168
|
83
|
|
|
|
|
204
|
my $canon = dotid $type; |
|
169
|
|
|
|
|
|
|
|
|
170
|
83
|
|
|
|
|
109
|
$self->debug("Looking for '$type' or '$canon' in $self->{ items }") if DEBUG; |
|
171
|
|
|
|
|
|
|
# $self->debug("types: ", $self->dump_data($self->{ types })) if DEBUG; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# false but defined entry indicates the item is not found |
|
174
|
|
|
|
|
|
|
return $self->not_found($type, \@args) |
|
175
|
|
|
|
|
|
|
if exists $items->{ $type } |
|
176
|
83
|
50
|
66
|
|
|
345
|
&& not $items->{ $type }; |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
my $item = $items->{ $type } |
|
179
|
83
|
|
100
|
|
|
433
|
|| $items->{ $canon } |
|
180
|
|
|
|
|
|
|
# TODO: this needs to be defined-or, like // |
|
181
|
|
|
|
|
|
|
# Plugins can return an empty string to indicate that they |
|
182
|
|
|
|
|
|
|
# do nothing. |
|
183
|
|
|
|
|
|
|
# HMMM.... or does it? |
|
184
|
|
|
|
|
|
|
|| $self->find($type, \@args) |
|
185
|
|
|
|
|
|
|
# || $self->default($type, \@args) |
|
186
|
|
|
|
|
|
|
|| return $self->not_found($type, \@args); |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
$items->{ $type } = $item |
|
189
|
81
|
50
|
|
|
|
271
|
unless $self->{ no_cache }; |
|
190
|
|
|
|
|
|
|
|
|
191
|
81
|
|
|
|
|
276
|
return $self->found($type, $item, \@args); |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub type_args { |
|
195
|
|
|
|
|
|
|
# Simple method to grok $type and @args from argument list. The only |
|
196
|
|
|
|
|
|
|
# processing it does is to set $type to 'default' if it is undefined or |
|
197
|
|
|
|
|
|
|
# false. Subclasses can re-define this to insert their own type mapping or |
|
198
|
|
|
|
|
|
|
# argument munging, e.g. to inject values into the configuration params |
|
199
|
|
|
|
|
|
|
# for an object |
|
200
|
65
|
|
|
65
|
1
|
89
|
shift; |
|
201
|
65
|
|
100
|
|
|
153
|
my $type = shift || DEFAULT; |
|
202
|
65
|
|
|
|
|
87
|
my @args; |
|
203
|
|
|
|
|
|
|
|
|
204
|
65
|
50
|
|
|
|
122
|
if (ref $type eq HASH) { |
|
205
|
0
|
|
|
|
|
0
|
@args = ($type, @_); |
|
206
|
0
|
|
0
|
|
|
0
|
$type = $type->{ type } || DEFAULT; |
|
207
|
|
|
|
|
|
|
} |
|
208
|
|
|
|
|
|
|
else { |
|
209
|
65
|
|
|
|
|
131
|
@args = @_; |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
65
|
|
|
|
|
145
|
return ($type, @args); |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub find { |
|
216
|
46
|
|
|
46
|
1
|
80
|
my $self = shift; |
|
217
|
46
|
|
|
|
|
74
|
my $type = shift; |
|
218
|
46
|
|
|
|
|
145
|
my $bases = $self->path; |
|
219
|
46
|
|
|
|
|
65
|
my $module; |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# run the type through the type map to handle any unusual capitalisation, |
|
222
|
|
|
|
|
|
|
# spelling, aliases, etc. |
|
223
|
46
|
|
66
|
|
|
175
|
$type = $self->{ names }->{ $type } || $type; |
|
224
|
|
|
|
|
|
|
|
|
225
|
46
|
|
|
|
|
86
|
foreach my $base (@$bases) { |
|
226
|
54
|
100
|
|
|
|
157
|
return $module |
|
227
|
|
|
|
|
|
|
if $module = $self->load( $self->module_names($base, $type) ); |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
2
|
|
|
|
|
36
|
return undef; |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub load { |
|
234
|
54
|
|
|
54
|
1
|
89
|
my $self = shift; |
|
235
|
54
|
|
|
|
|
92
|
my $loaded = $self->{ loaded }; |
|
236
|
|
|
|
|
|
|
|
|
237
|
54
|
|
|
|
|
99
|
foreach my $module (@_) { |
|
238
|
|
|
|
|
|
|
# see if we've previously loaded a module with this name (true |
|
239
|
|
|
|
|
|
|
# value) or failed to load a module (defined but false value) |
|
240
|
|
|
|
|
|
|
|
|
241
|
64
|
100
|
|
|
|
217
|
if ($loaded->{ $module }) { |
|
|
|
50
|
|
|
|
|
|
|
242
|
12
|
|
|
|
|
15
|
$self->debug("$module has been previously loaded") if DEBUG; |
|
243
|
12
|
|
|
|
|
59
|
return $module; |
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
elsif (defined $loaded->{ $module }) { |
|
246
|
0
|
|
|
|
|
0
|
next; |
|
247
|
|
|
|
|
|
|
} |
|
248
|
|
|
|
|
|
|
|
|
249
|
24
|
|
|
24
|
|
186
|
no strict REFS; |
|
|
24
|
|
|
|
|
62
|
|
|
|
24
|
|
|
|
|
27140
|
|
|
250
|
52
|
|
|
|
|
73
|
$self->debug("attempting to load $module") if DEBUG; |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# Some filesystems are case-insensitive (like Apple's HFS), so an |
|
253
|
|
|
|
|
|
|
# attempt to load Badger::Example::foo may succeed, when the correct |
|
254
|
|
|
|
|
|
|
# package name is actually Badger::Example::Foo. We double-check |
|
255
|
|
|
|
|
|
|
# by looking for $VERSION or @ISA. This is a bit dodgy because we might be |
|
256
|
|
|
|
|
|
|
# loading something that has no ISA. Need to cross-check with |
|
257
|
|
|
|
|
|
|
# what's going on in Badger::Class _autoload() |
|
258
|
|
|
|
|
|
|
|
|
259
|
52
|
|
|
|
|
63
|
my $loadname; |
|
260
|
52
|
100
|
|
|
|
139
|
if ( ($loadname = class($module)->maybe_load) ) { |
|
261
|
32
|
|
|
|
|
48
|
$self->debug("loaded $module") if DEBUG; |
|
262
|
32
|
|
|
|
|
77
|
$loaded->{ $module } = $loadname; |
|
263
|
32
|
|
|
|
|
250
|
return $module |
|
264
|
|
|
|
|
|
|
} |
|
265
|
|
|
|
|
|
|
|
|
266
|
20
|
|
|
|
|
41
|
$self->debug("failed to load $module") if DEBUG; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
10
|
|
|
|
|
32
|
return undef; |
|
270
|
|
|
|
|
|
|
} |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
sub found { |
|
274
|
83
|
|
|
83
|
1
|
1503
|
my ($self, $type, $item, $args) = @_; |
|
275
|
|
|
|
|
|
|
|
|
276
|
83
|
100
|
|
|
|
229
|
if (ref $item) { |
|
277
|
|
|
|
|
|
|
# if it's a reference we found then forward it onto the appropriate |
|
278
|
|
|
|
|
|
|
# method, e.g found_array(), found_hash(), found_code(). Fall back |
|
279
|
|
|
|
|
|
|
# on found_ref() |
|
280
|
29
|
100
|
|
|
|
135
|
my $iref = blessed($item) |
|
281
|
|
|
|
|
|
|
? OBJECT |
|
282
|
|
|
|
|
|
|
: lc ref $item; |
|
283
|
|
|
|
|
|
|
|
|
284
|
29
|
|
|
|
|
49
|
$self->debug( |
|
285
|
|
|
|
|
|
|
"Looking for handler methods: ", |
|
286
|
|
|
|
|
|
|
FOUND,'_'.$iref, "() or ", |
|
287
|
|
|
|
|
|
|
FOUND_REF, "()" |
|
288
|
|
|
|
|
|
|
) if DEBUG; |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
my $method |
|
291
|
|
|
|
|
|
|
= $self->can(FOUND . '_' . $iref) |
|
292
|
|
|
|
|
|
|
|| $self->can(FOUND_REF) |
|
293
|
29
|
|
50
|
|
|
104
|
|| return $self->error_msg( bad_ref => $self->{ item }, $type, $iref ); |
|
294
|
|
|
|
|
|
|
|
|
295
|
29
|
|
|
|
|
95
|
$item = $method->($self, $type, $item, $args); |
|
296
|
|
|
|
|
|
|
} |
|
297
|
|
|
|
|
|
|
else { |
|
298
|
|
|
|
|
|
|
# otherwise it's the name of a module |
|
299
|
54
|
|
|
|
|
222
|
$item = $self->found_module($type, $item, $args); |
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# NOTE: an item can be defined but false, e.g. a Template::Plugin which |
|
303
|
|
|
|
|
|
|
# return '' from its new() method to indicate it does nothing objecty |
|
304
|
83
|
50
|
|
|
|
194
|
return unless defined $item; |
|
305
|
|
|
|
|
|
|
|
|
306
|
83
|
|
|
|
|
97
|
$self->debug("Found result: $type => $item") if DEBUG; |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# TODO: what about caching result? Do we always leave that to subclasses? |
|
309
|
83
|
|
|
|
|
219
|
return $self->result($type, $item, $args); |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub found_module { |
|
313
|
|
|
|
|
|
|
# This method is called when a module name is found, either by being |
|
314
|
|
|
|
|
|
|
# predefined in the factory entry table, or loaded on demand from disk. |
|
315
|
|
|
|
|
|
|
# It ensures the module is loaded and and instantiates an object from the |
|
316
|
|
|
|
|
|
|
# class name |
|
317
|
54
|
|
|
54
|
1
|
118
|
my ($self, $type, $module, $args) = @_; |
|
318
|
54
|
|
|
|
|
63
|
$self->debug("Found module: $type => $module") if DEBUG; |
|
319
|
54
|
|
66
|
|
|
235
|
$self->{ loaded }->{ $module } ||= class($module)->load; |
|
320
|
54
|
|
|
|
|
188
|
return $self->construct($type, $module, $args); |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub found_array { |
|
324
|
|
|
|
|
|
|
# This method is called when an ARRAY reference is found. We assume that |
|
325
|
|
|
|
|
|
|
# the first item is the module name (which needs to be loaded) and the |
|
326
|
|
|
|
|
|
|
# second item is the class name (which needs to be instantiated). |
|
327
|
4
|
|
|
4
|
1
|
13
|
my ($self, $type, $item, $args) = @_; |
|
328
|
4
|
|
|
|
|
11
|
my ($module, $class) = @$item; |
|
329
|
4
|
|
66
|
|
|
34
|
$self->{ loaded }->{ $module } ||= class($module)->load; |
|
330
|
4
|
|
|
|
|
30
|
return $self->construct($type, $class, $args); |
|
331
|
|
|
|
|
|
|
} |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub not_found { |
|
334
|
2
|
|
|
2
|
1
|
7
|
my ($self, $type, @args) = @_; |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
return $type eq DEFAULT |
|
337
|
|
|
|
|
|
|
? $self->error_msg( no_default => $self->{ item } ) |
|
338
|
2
|
100
|
|
|
|
21
|
: $self->error_msg( not_found => $self->{ item }, $type ); |
|
339
|
|
|
|
|
|
|
} |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
sub construct { |
|
342
|
59
|
|
|
59
|
1
|
140
|
my ($self, $type, $class, $args) = @_; |
|
343
|
59
|
|
|
|
|
71
|
$self->debug("constructing class: $type => $class") if DEBUG; |
|
344
|
59
|
|
|
|
|
276
|
return $class->new(@$args); |
|
345
|
|
|
|
|
|
|
} |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
sub module_names { |
|
348
|
54
|
|
|
54
|
1
|
78
|
my $self = shift; |
|
349
|
|
|
|
|
|
|
my @bits = |
|
350
|
119
|
|
|
|
|
263
|
map { camel_case($_) } |
|
351
|
54
|
|
|
|
|
99
|
map { split /[\.]+/ } @_; |
|
|
108
|
|
|
|
|
305
|
|
|
352
|
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
return ( |
|
354
|
54
|
|
|
|
|
117
|
join( PKG, map { ucfirst $_ } @bits ), |
|
|
119
|
|
|
|
|
407
|
|
|
355
|
|
|
|
|
|
|
join( PKG, @bits ) |
|
356
|
|
|
|
|
|
|
); |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
sub can { |
|
361
|
35
|
|
|
35
|
1
|
78
|
my ($self, $name) = @_; |
|
362
|
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# upgrade class methods to calls on prototype |
|
364
|
35
|
50
|
|
|
|
79
|
$self = $self->prototype unless ref $self; |
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# NOTE: this method can get called before we've called init_factory() |
|
367
|
|
|
|
|
|
|
# to define the item/items members, so we tread carefully. |
|
368
|
35
|
50
|
33
|
|
|
257
|
if ($self->{ item } && $self->{ item } eq $name) { |
|
|
|
50
|
33
|
|
|
|
|
|
369
|
0
|
|
|
|
|
0
|
return $self->SUPER::can('item'); |
|
370
|
|
|
|
|
|
|
} |
|
371
|
|
|
|
|
|
|
elsif ($self->{ items } && $self->{ items } eq $name) { |
|
372
|
0
|
|
|
|
|
0
|
return $self->SUPER::can('items'); |
|
373
|
|
|
|
|
|
|
} |
|
374
|
|
|
|
|
|
|
else { |
|
375
|
35
|
|
|
|
|
285
|
return $self->SUPER::can($name); |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
} |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
sub result { |
|
380
|
33
|
|
|
33
|
1
|
182
|
$_[2]; |
|
381
|
|
|
|
|
|
|
} |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub AUTOLOAD { |
|
384
|
12
|
|
|
12
|
|
108
|
my ($self, @args) = @_; |
|
385
|
12
|
|
|
|
|
101
|
my ($name) = ($AUTOLOAD =~ /([^:]+)$/ ); |
|
386
|
12
|
100
|
|
|
|
346
|
return if $name eq 'DESTROY'; |
|
387
|
|
|
|
|
|
|
|
|
388
|
7
|
|
|
|
|
14
|
$self->debug("AUTOLOAD $name") if DEBUG; |
|
389
|
|
|
|
|
|
|
|
|
390
|
7
|
|
|
|
|
17
|
local $RUNAWAY = $RUNAWAY; |
|
391
|
7
|
50
|
|
|
|
21
|
$self->error("AUTOLOAD went runaway on $name") |
|
392
|
|
|
|
|
|
|
if ++$RUNAWAY > 10; |
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# upgrade class methods to calls on prototype |
|
395
|
7
|
100
|
|
|
|
74
|
$self = $self->prototype unless ref $self; |
|
396
|
|
|
|
|
|
|
|
|
397
|
7
|
|
|
|
|
13
|
$self->debug("factory item: $self->{ item }") if DEBUG; |
|
398
|
|
|
|
|
|
|
|
|
399
|
7
|
100
|
|
|
|
57
|
if ($name eq $self->{ item }) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
400
|
6
|
|
|
|
|
27
|
$self->class->method( $name => $self->can('item') ); |
|
401
|
|
|
|
|
|
|
} |
|
402
|
|
|
|
|
|
|
elsif ($name eq $self->{ items }) { |
|
403
|
0
|
|
|
|
|
0
|
$self->class->method( $name => $self->can('items') ) |
|
404
|
|
|
|
|
|
|
} |
|
405
|
|
|
|
|
|
|
elsif (my $item = $self->try( item => $name, @args )) { |
|
406
|
0
|
|
|
|
|
0
|
return $item; |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
else { |
|
409
|
1
|
|
|
|
|
5
|
my ($pkg, $file, $line) = caller; |
|
410
|
1
|
|
33
|
|
|
10
|
my $class = ref $self || $self; |
|
411
|
1
|
|
|
|
|
8
|
die $self->message( bad_method => $name, $class, $file, $line ), "\n"; |
|
412
|
|
|
|
|
|
|
} |
|
413
|
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
# should be installed now |
|
415
|
6
|
|
|
|
|
24
|
$self->$name(@args); |
|
416
|
|
|
|
|
|
|
} |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
1; |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
__END__ |