line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Class::MakeMethods::Template; |
2
|
|
|
|
|
|
|
|
3
|
93
|
|
|
93
|
|
1740
|
use strict; |
|
93
|
|
|
|
|
173
|
|
|
93
|
|
|
|
|
7215
|
|
4
|
93
|
|
|
93
|
|
530
|
use Carp; |
|
93
|
|
|
|
|
206
|
|
|
93
|
|
|
|
|
9147
|
|
5
|
|
|
|
|
|
|
|
6
|
93
|
|
|
93
|
|
69616
|
use Class::MakeMethods '-isasubclass'; |
|
93
|
|
|
|
|
238
|
|
|
93
|
|
|
|
|
787
|
|
7
|
|
|
|
|
|
|
|
8
|
93
|
|
|
93
|
|
515
|
use vars qw( $VERSION ); |
|
93
|
|
|
|
|
180
|
|
|
93
|
|
|
|
|
9051
|
|
9
|
|
|
|
|
|
|
$VERSION = 1.008; |
10
|
|
|
|
|
|
|
|
11
|
2083
|
|
|
2083
|
|
5882
|
sub _diagnostic { &Class::MakeMethods::_diagnostic } |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
######################################################################## |
14
|
|
|
|
|
|
|
### TEMPLATE LOOKUP AND CACHING: named_method(), _definition() |
15
|
|
|
|
|
|
|
######################################################################## |
16
|
|
|
|
|
|
|
|
17
|
93
|
|
|
93
|
|
648
|
use vars qw( %TemplateCache ); |
|
93
|
|
|
|
|
188
|
|
|
93
|
|
|
|
|
529082
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# @results = $class->named_method( $name, @arguments ); |
20
|
|
|
|
|
|
|
sub named_method { |
21
|
5279
|
|
|
5279
|
0
|
7510
|
my $class = shift; |
22
|
5279
|
|
|
|
|
18676
|
my $name = shift; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Support direct access to cached Template information |
25
|
5279
|
100
|
|
|
|
22333
|
if (exists $TemplateCache{"$class\::$name"}) { |
26
|
4531
|
|
|
|
|
39430
|
return $TemplateCache{"$class\::$name"}; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
748
|
|
|
|
|
4183
|
my @results = $class->$name( @_ ); |
30
|
|
|
|
|
|
|
|
31
|
748
|
100
|
100
|
|
|
8241
|
if ( scalar @results == 1 and ref $results[0] eq 'HASH' ) { |
32
|
|
|
|
|
|
|
# If this is a hash-definition format, cache the results for speed. |
33
|
739
|
|
|
|
|
1597
|
my $def = $results[0]; |
34
|
739
|
|
|
|
|
2762
|
$TemplateCache{"$class\::$name"} = $def; |
35
|
739
|
|
|
|
|
3760
|
_expand_definition($class, $name, $def); |
36
|
739
|
|
|
|
|
12622
|
return $def; |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
9
|
50
|
|
|
|
49
|
return wantarray ? @results : $results[0]; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# $mm_def = _definition( $class, $target ); |
43
|
|
|
|
|
|
|
sub _definition { |
44
|
5059
|
|
|
5059
|
|
7873
|
my ($class, $target) = @_; |
45
|
|
|
|
|
|
|
|
46
|
5059
|
|
|
|
|
11698
|
while ( ! ref $target ) { |
47
|
5059
|
|
|
|
|
19619
|
$target =~ s/\s.*//; |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# If method name contains a colon or double colon, call the method on the |
50
|
|
|
|
|
|
|
# indicated class. |
51
|
5059
|
50
|
|
|
|
38258
|
my $call_class = ( ( $target =~ s/^(.*)\:{1,2}// ) |
52
|
|
|
|
|
|
|
? Class::MakeMethods::_find_subclass($class, $1) : $class ); |
53
|
5059
|
|
|
|
|
18555
|
$target = $call_class->named_method( $target ); |
54
|
|
|
|
|
|
|
} |
55
|
5059
|
50
|
66
|
|
|
24188
|
_diagnostic('mmdef_not_interpretable', $target) |
56
|
|
|
|
|
|
|
unless ( ref($target) eq 'HASH' or ref($target) eq __PACKAGE__ ); |
57
|
|
|
|
|
|
|
|
58
|
5059
|
|
|
|
|
11754
|
return $target; |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
######################################################################## |
62
|
|
|
|
|
|
|
### TEMPLATE INTERNALS: _expand_definition() |
63
|
|
|
|
|
|
|
######################################################################## |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub _expand_definition { |
66
|
739
|
|
|
739
|
|
1410
|
my ($class, $name, $mm_def) = @_; |
67
|
|
|
|
|
|
|
|
68
|
739
|
50
|
|
|
|
1925
|
return $mm_def if $mm_def->{'-parsed'}; |
69
|
|
|
|
|
|
|
|
70
|
739
|
|
|
|
|
1431
|
$mm_def->{'template_class'} = $class; |
71
|
739
|
|
|
|
|
1327
|
$mm_def->{'template_name'} = $name; |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# Allow definitions to import values from each other. |
74
|
739
|
|
|
|
|
879
|
my $importer; |
75
|
739
|
|
|
|
|
2296
|
foreach $importer ( qw( interface params behavior code_expr modifier ) ) { |
76
|
3695
|
|
100
|
|
|
22611
|
my $rules = $mm_def->{$importer}->{'-import'} || $mm_def->{'-import'}; |
77
|
3695
|
50
|
|
|
|
14974
|
my @rules = ( ref $rules eq 'HASH' ? %$rules : ref $rules eq 'ARRAY' ? @$rules : () ); |
|
|
100
|
|
|
|
|
|
78
|
3695
|
100
|
|
|
|
36914
|
unshift @rules, '::' . $class . ':generic' => '*' if $class->can('generic'); |
79
|
3695
|
|
|
|
|
13101
|
while ( |
80
|
|
|
|
|
|
|
my ($source, $names) = splice @rules, 0, 2 |
81
|
|
|
|
|
|
|
) { |
82
|
5059
|
|
|
|
|
12392
|
my $mmi = _definition($class, $source); |
83
|
5059
|
100
|
|
|
|
10907
|
foreach ( ( $names eq '*' ) ? keys %{ $mmi->{$importer} } |
|
4772
|
100
|
|
|
|
24799
|
|
|
11
|
|
|
|
|
33
|
|
84
|
|
|
|
|
|
|
: ( ref $names ) ? @{ $names } : ( $names ) ) { |
85
|
21961
|
|
|
|
|
43945
|
my $current = $mm_def->{$importer}{$_}; |
86
|
21961
|
|
|
|
|
35901
|
my $import = $mmi->{$importer}{$_}; |
87
|
21961
|
100
|
|
|
|
49222
|
if ( ! $current ) { |
|
|
100
|
|
|
|
|
|
88
|
15231
|
|
|
|
|
56612
|
$mm_def->{$importer}{$_} = $import; |
89
|
|
|
|
|
|
|
} elsif ( ref($current) eq 'ARRAY' ) { |
90
|
168
|
50
|
|
|
|
1280
|
my @imports = ref($import) ? @$import : $import; |
91
|
168
|
|
|
|
|
411
|
foreach my $imp ( @imports ) { |
92
|
1554
|
100
|
|
|
|
2197
|
push @$current, $imp unless ( grep { $_ eq $imp } @$current ); |
|
15414
|
|
|
|
|
28459
|
|
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
} |
97
|
3695
|
|
|
|
|
11694
|
delete $mm_def->{$importer}->{'-import'}; |
98
|
|
|
|
|
|
|
} |
99
|
739
|
|
|
|
|
1502
|
delete $mm_def->{'-import'}; |
100
|
|
|
|
|
|
|
|
101
|
739
|
50
|
|
|
|
2074
|
_describe_definition( $mm_def ) if $Class::MakeMethods::CONTEXT{Debug}; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
|
104
|
739
|
|
|
|
|
2514
|
$mm_def->{'-parsed'} = "$_[1]"; |
105
|
|
|
|
|
|
|
|
106
|
739
|
|
|
|
|
2657
|
bless $mm_def, __PACKAGE__; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub _describe_definition { |
110
|
0
|
|
|
0
|
|
0
|
my $mm_def = shift; |
111
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
0
|
my $def_type = "$mm_def->{template_class}:$mm_def->{template_name}"; |
113
|
0
|
|
|
|
|
0
|
warn "----\nMethods info for $def_type:\n"; |
114
|
0
|
0
|
|
|
|
0
|
if ( $mm_def->{interface} ) { |
115
|
0
|
|
|
|
|
0
|
warn join '', "Templates: \n", map { |
116
|
0
|
|
|
|
|
0
|
" $_: " . _describe_value($mm_def->{interface}{$_}) . "\n" |
117
|
0
|
|
|
|
|
0
|
} keys %{$mm_def->{interface}}; |
118
|
|
|
|
|
|
|
} |
119
|
0
|
0
|
|
|
|
0
|
if ( $mm_def->{modifier} ) { |
120
|
0
|
|
|
|
|
0
|
warn join '', "Modifiers: \n", map { |
121
|
0
|
|
|
|
|
0
|
" $_: " . _describe_value($mm_def->{modifier}{$_}) . "\n" |
122
|
0
|
|
|
|
|
0
|
} keys %{$mm_def->{modifier}}; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub _describe_value { |
127
|
0
|
|
|
0
|
|
0
|
my $value = $_[0]; |
128
|
0
|
0
|
|
|
|
0
|
ref($value) eq 'ARRAY' ? join(', ', @$value) : |
|
|
0
|
|
|
|
|
|
129
|
|
|
|
|
|
|
ref($value) eq 'HASH' ? join(', ', %$value) : |
130
|
|
|
|
|
|
|
"$value"; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
######################################################################## |
134
|
|
|
|
|
|
|
### METHOD GENERATION: make_methods() |
135
|
|
|
|
|
|
|
######################################################################## |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub make_methods { |
138
|
211
|
|
|
211
|
0
|
432
|
my $mm_def = shift; |
139
|
|
|
|
|
|
|
|
140
|
211
|
100
|
|
|
|
805
|
return unless ( scalar @_ ); |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# Select default interface and initial method parameters |
143
|
210
|
|
50
|
|
|
384
|
my $defaults = { %{ ( $mm_def->{'params'} ||= {} ) } }; |
|
210
|
|
|
|
|
1506
|
|
144
|
210
|
|
50
|
|
|
2475
|
$defaults->{'interface'} ||= $mm_def->{'interface'}{'-default'} || 'default'; |
|
|
|
33
|
|
|
|
|
145
|
210
|
|
|
|
|
1373
|
$defaults->{'target_class'} = $mm_def->_context('TargetClass'); |
146
|
210
|
|
|
|
|
614
|
$defaults->{'template_class'} = $mm_def->{'template_class'}; |
147
|
210
|
|
|
|
|
642
|
$defaults->{'template_name'} = $mm_def->{'template_name'}; |
148
|
|
|
|
|
|
|
|
149
|
210
|
|
|
|
|
407
|
my %interface_cache; |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# Our return value is the accumulated list of method-name => method-sub pairs |
152
|
|
|
|
|
|
|
my @methods; |
153
|
|
|
|
|
|
|
|
154
|
210
|
|
|
|
|
771
|
while (scalar @_) { |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
### PARSING ### Requires: $mm_def, $defaults, @_ |
157
|
|
|
|
|
|
|
|
158
|
458
|
|
|
|
|
1628
|
my $m_name = shift @_; |
159
|
458
|
50
|
33
|
|
|
4397
|
_diagnostic('make_empty') unless ( defined $m_name and length $m_name ); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# Normalize: If we've got an array of names, replace it with those names |
162
|
458
|
100
|
|
|
|
1345
|
if ( ref $m_name eq 'ARRAY' ) { |
163
|
2
|
|
|
|
|
4
|
my @items = @{ $m_name }; |
|
2
|
|
|
|
|
11
|
|
164
|
|
|
|
|
|
|
# If array is followed by a params hash, each one gets the same params |
165
|
2
|
50
|
33
|
|
|
38
|
if ( scalar @_ and ref $_[0] eq 'HASH' and ! exists $_[0]->{'name'} ) { |
|
|
|
33
|
|
|
|
|
166
|
0
|
|
|
|
|
0
|
my $params = shift; |
167
|
0
|
|
|
|
|
0
|
@items = map { $_, $params } @items |
|
0
|
|
|
|
|
0
|
|
168
|
|
|
|
|
|
|
} |
169
|
2
|
|
|
|
|
9
|
unshift @_, @items; |
170
|
2
|
|
|
|
|
10
|
next; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Parse interfaces, modifiers and parameters |
174
|
456
|
100
|
|
|
|
1846
|
if ( $m_name =~ s/^-// ) { |
175
|
131
|
100
|
|
|
|
628
|
if ( $m_name !~ s/^-// ) { |
176
|
|
|
|
|
|
|
# -param => value |
177
|
60
|
|
|
|
|
165
|
$defaults->{$m_name} = shift @_; |
178
|
|
|
|
|
|
|
} else { |
179
|
71
|
50
|
|
|
|
437
|
if ( $m_name eq '' ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# '--' => { param => value ... } |
181
|
0
|
|
|
|
|
0
|
%$defaults = ( %$defaults, %{ shift @_ } ); |
|
0
|
|
|
|
|
0
|
|
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
} elsif ( exists $mm_def->{'interface'}{$m_name} ) { |
184
|
|
|
|
|
|
|
# --interface |
185
|
51
|
|
|
|
|
118
|
$defaults->{'interface'} = $m_name; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
} elsif ( exists $mm_def->{'modifier'}{$m_name} ) { |
188
|
|
|
|
|
|
|
# --modifier |
189
|
9
|
100
|
|
|
|
36
|
$defaults->{'modifier'} .= |
190
|
|
|
|
|
|
|
( $defaults->{'modifier'} ? ' ' : '' ) . "-$m_name"; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
} elsif ( exists $mm_def->{'behavior'}{$m_name} ) { |
193
|
|
|
|
|
|
|
# --behavior as shortcut for single-method interface |
194
|
11
|
|
|
|
|
24
|
$defaults->{'interface'} = $m_name; |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
} else { |
197
|
0
|
|
|
|
|
0
|
_diagnostic('make_bad_modifier', $mm_def->{'name'}, "--$m_name"); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
} |
200
|
131
|
|
|
|
|
450
|
next; |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# Make a new meta-method hash |
204
|
325
|
|
|
|
|
495
|
my $m_info; |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# Parse string, string-then-hash, and hash-only meta-method parameters |
207
|
325
|
100
|
|
|
|
1065
|
if ( ! ref $m_name ) { |
|
|
50
|
|
|
|
|
|
208
|
297
|
100
|
100
|
|
|
1899
|
if ( scalar @_ and ref $_[0] eq 'HASH' and ! exists $_[0]->{'name'} ) { |
|
|
|
100
|
|
|
|
|
209
|
8
|
|
|
|
|
15
|
%$m_info = ( 'name' => $m_name, %{ shift @_ } ); |
|
8
|
|
|
|
|
60
|
|
210
|
|
|
|
|
|
|
} else { |
211
|
289
|
|
|
|
|
1296
|
$m_info = { 'name' => $m_name }; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
} elsif ( ref $m_name eq 'HASH' ) { |
215
|
28
|
50
|
33
|
|
|
292
|
unless ( exists $m_name->{'name'} and length $m_name->{'name'} ) { |
216
|
0
|
|
|
|
|
0
|
_diagnostic('make_noname'); |
217
|
|
|
|
|
|
|
} |
218
|
28
|
|
|
|
|
170
|
$m_info = { %$m_name }; |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
} else { |
221
|
0
|
|
|
|
|
0
|
_diagnostic('make_unsupported', $m_name); |
222
|
|
|
|
|
|
|
} |
223
|
325
|
50
|
|
|
|
2586
|
_diagnostic('debug_declaration', join(', ', map { defined $_ ? $_ : '(undef)' } %$m_info) ); |
|
742
|
|
|
|
|
3236
|
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
### INITIALIZATION ### Requires: $mm_def, $defaults, $m_info |
226
|
|
|
|
|
|
|
|
227
|
325
|
|
66
|
|
|
4706
|
my $interface = ( |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
228
|
|
|
|
|
|
|
$interface_cache{ $m_info->{'interface'} || $defaults->{'interface'} } |
229
|
|
|
|
|
|
|
||= _interpret_interface( $mm_def, $m_info->{'interface'} || $defaults->{'interface'} ) |
230
|
|
|
|
|
|
|
); |
231
|
12
|
|
|
|
|
166
|
%$m_info = ( |
232
|
|
|
|
|
|
|
%$defaults, |
233
|
325
|
100
|
|
|
|
4823
|
( $interface->{-params} ? %{$interface->{-params}} : () ), |
234
|
|
|
|
|
|
|
%$m_info |
235
|
|
|
|
|
|
|
); |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# warn "Actual: " . Dumper( $m_info ); |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# Expand * and *{...} strings. |
242
|
325
|
|
|
|
|
2332
|
foreach (grep defined $m_info->{$_}, keys %$m_info) { |
243
|
2137
|
|
100
|
|
|
6204
|
$m_info->{$_} =~ s/\*(?:\{([^\}]+)?\})?/ $m_info->{ $1 || 'name' } /ge |
|
285
|
|
|
|
|
2570
|
|
244
|
|
|
|
|
|
|
} |
245
|
325
|
100
|
66
|
|
|
1581
|
if ( $m_info->{'modifier'} and $mm_def->{modifier}{-folding} ) { |
246
|
7
|
|
|
|
|
25
|
$m_info->{'modifier'} = _fold_modifiers( $m_info->{'modifier'}, |
247
|
|
|
|
|
|
|
$mm_def->{modifier}{-folding} ) |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
### METHOD GENERATION ### Requires: $mm_def, $interface, $m_info |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# If the MM def provides an initialization "-init" call, run it. |
253
|
325
|
100
|
|
|
|
1759
|
if ( local $_ = $mm_def->{'behavior'}->{'-init'} ) { |
254
|
63
|
100
|
|
|
|
387
|
push @methods, map $_->( $m_info ), (ref($_) eq 'ARRAY') ? @$_ : $_; |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
# Build Methods |
257
|
325
|
|
|
|
|
4193
|
for ( grep { /^[^-]/ } keys %$interface ) { |
|
1668
|
|
|
|
|
8148
|
|
258
|
1331
|
|
|
|
|
2531
|
my $function_name = $_; |
259
|
1331
|
|
|
|
|
5896
|
$function_name =~ s/\*/$m_info->{'name'}/g; |
260
|
|
|
|
|
|
|
|
261
|
1331
|
|
|
|
|
3138
|
my $behavior = $interface->{$_}; |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# Fold in additional modifiers |
264
|
1331
|
100
|
|
|
|
5183
|
if ( $m_info->{'modifier'} ) { |
265
|
6
|
50
|
33
|
|
|
25
|
if ( $behavior =~ /^\-/ and $mm_def->{modifier}{-folding} ) { |
266
|
0
|
|
|
|
|
0
|
$behavior = $m_info->{'modifier'} = |
267
|
|
|
|
|
|
|
_fold_modifiers( "$m_info->{'modifier'} $behavior", |
268
|
|
|
|
|
|
|
$mm_def->{modifier}{-folding} ) |
269
|
|
|
|
|
|
|
} else { |
270
|
6
|
|
|
|
|
17
|
$behavior = "$m_info->{'modifier'} $behavior"; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
|
274
|
1331
|
100
|
|
|
|
5663
|
my $builder = |
|
|
100
|
|
|
|
|
|
275
|
|
|
|
|
|
|
( $mm_def->{'-behavior_cache'}{$behavior} ) ? |
276
|
|
|
|
|
|
|
$mm_def->{'-behavior_cache'}{$behavior} : |
277
|
|
|
|
|
|
|
( ref($mm_def->{'behavior'}{$behavior}) eq 'CODE' ) ? |
278
|
|
|
|
|
|
|
$mm_def->{'behavior'}{$behavior} : |
279
|
|
|
|
|
|
|
_behavior_builder( $mm_def, $behavior, $m_info ); |
280
|
|
|
|
|
|
|
|
281
|
1331
|
|
|
|
|
40735
|
my $method = &$builder( $m_info ); |
282
|
|
|
|
|
|
|
|
283
|
1331
|
|
|
|
|
3387
|
_diagnostic('debug_make_behave', $behavior, $function_name, $method); |
284
|
1331
|
50
|
|
|
|
14373
|
push @methods, ($function_name => $method) if ($method); |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
# If the MM def provides a "-subs" call, for forwarding and other |
288
|
|
|
|
|
|
|
# miscelaneous "subsidiary" or "contained" methods, run it. |
289
|
325
|
100
|
|
|
|
1623
|
if ( my $subs = $mm_def->{'behavior'}->{'-subs'} ) { |
290
|
29
|
50
|
|
|
|
108
|
my @subs = (ref($subs) eq 'ARRAY') ? @$subs : $subs; |
291
|
29
|
|
|
|
|
59
|
foreach my $sub ( @subs ) { |
292
|
29
|
|
|
|
|
1510
|
my @results = $sub->($m_info); |
293
|
29
|
50
|
33
|
|
|
193
|
if ( scalar @results == 1 and ref($results[0]) eq 'HASH' ) { |
294
|
|
|
|
|
|
|
# If it returns a hash of helper method types, check the method info |
295
|
|
|
|
|
|
|
# for any matching names and call the corresponding method generator. |
296
|
29
|
|
|
|
|
48
|
my $types = shift @results; |
297
|
29
|
|
|
|
|
88
|
foreach my $type ( keys %$types ) { |
298
|
55
|
100
|
|
|
|
268
|
my $names = $m_info->{$type} or next; |
299
|
11
|
100
|
|
|
|
59
|
my @names = ref($names) eq 'ARRAY' ? @$names : split(' ', $names); |
300
|
11
|
|
|
|
|
26
|
my $generator = $types->{$type}; |
301
|
11
|
|
|
|
|
27
|
push @results, map { $_ => &$generator($m_info, $_) } @names; |
|
11
|
|
|
|
|
41
|
|
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
} |
304
|
29
|
|
|
|
|
117
|
push @methods, @results; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# If the MM def provides a "-register" call, for registering meta-method |
309
|
|
|
|
|
|
|
# information for run-time access, run it. |
310
|
325
|
100
|
|
|
|
2099
|
if ( local $_ = $mm_def->{'behavior'}->{'-register'} ) { |
311
|
13
|
50
|
|
|
|
92
|
push @methods, map $_->( $m_info ), (ref($_) eq 'ARRAY') ? @$_ : $_; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
210
|
|
|
|
|
3767
|
return @methods; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# I'd like for the make_methods() sub to be simpler, and to take advantage |
319
|
|
|
|
|
|
|
# of the standard _get_declarations parsing provided by the superclass. |
320
|
|
|
|
|
|
|
# Sadly the below doesn't work, due to a few order-of-operations peculiarities |
321
|
|
|
|
|
|
|
# of parsing interfaces and modifiers, and their associated default paramters. |
322
|
|
|
|
|
|
|
# Perhaps it might work if the processing of --options could be overridden with |
323
|
|
|
|
|
|
|
# a callback sub, so that interfaces and their params can be parsed in order. |
324
|
|
|
|
|
|
|
sub _x_get_declarations { |
325
|
0
|
|
|
0
|
|
0
|
my $mm_def = shift; |
326
|
|
|
|
|
|
|
|
327
|
0
|
|
|
|
|
0
|
my @declarations = $mm_def::SUPER->_get_declarations( @_ ); |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# use Data::Dumper; |
330
|
|
|
|
|
|
|
# warn "In: " . Dumper( \@_ ); |
331
|
|
|
|
|
|
|
# warn "Auto: " . Dumper( \@declarations ); |
332
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
0
|
my %interface_cache; |
334
|
|
|
|
|
|
|
|
335
|
0
|
|
|
|
|
0
|
while (scalar @declarations) { |
336
|
|
|
|
|
|
|
|
337
|
0
|
|
|
|
|
0
|
my $m_info = shift @declarations; |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
# Parse interfaces and modifiers |
340
|
0
|
|
0
|
|
|
0
|
my @specials = grep $_, split '--', ( delete $m_info->{'--'} || '' ); |
341
|
0
|
|
|
|
|
0
|
foreach my $special ( @specials ) { |
342
|
0
|
0
|
|
|
|
0
|
if ( exists $mm_def->{'interface'}{$special} ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
343
|
|
|
|
|
|
|
# --interface |
344
|
0
|
|
|
|
|
0
|
$m_info->{'interface'} = $special; |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
} elsif ( exists $mm_def->{'modifier'}{$special} ) { |
347
|
|
|
|
|
|
|
# --modifier |
348
|
0
|
0
|
|
|
|
0
|
$m_info->{'modifier'} .= |
349
|
|
|
|
|
|
|
( $m_info->{'modifier'} ? ' ' : '' ) . "-$special"; |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
} elsif ( exists $mm_def->{'behavior'}{$special} ) { |
352
|
|
|
|
|
|
|
# --behavior as shortcut for single-method interface |
353
|
0
|
|
|
|
|
0
|
$m_info->{'interface'} = $special; |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
} else { |
356
|
0
|
|
|
|
|
0
|
_diagnostic('make_bad_modifier', $mm_def->{'name'}, "--$special"); |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
|
360
|
0
|
|
0
|
|
|
0
|
my $interface = ( |
361
|
|
|
|
|
|
|
$interface_cache{ $m_info->{'interface'} } |
362
|
|
|
|
|
|
|
||= _interpret_interface( $mm_def, $m_info->{'interface'} ) |
363
|
|
|
|
|
|
|
); |
364
|
0
|
0
|
|
|
|
0
|
$m_info = { %$m_info, %{$interface->{-params}} } if $interface->{-params}; |
|
0
|
|
|
|
|
0
|
|
365
|
|
|
|
|
|
|
|
366
|
0
|
0
|
|
|
|
0
|
_diagnostic('debug_declaration', join(', ', map { defined $_ ? $_ : '(undef)' } %$m_info) ); |
|
0
|
|
|
|
|
0
|
|
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
# warn "Updated: " . Dumper( $m_info ); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
######################################################################## |
373
|
|
|
|
|
|
|
### TEMPLATES: _interpret_interface() |
374
|
|
|
|
|
|
|
######################################################################## |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub _interpret_interface { |
377
|
216
|
|
|
216
|
|
671
|
my ($mm_def, $interface) = @_; |
378
|
|
|
|
|
|
|
|
379
|
216
|
100
|
33
|
|
|
4707
|
if ( ref $interface eq 'HASH' ) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
380
|
49
|
100
|
|
|
|
232
|
return $interface if exists $interface->{'-parsed'}; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
elsif ( ! defined $interface or ! length $interface ) { |
383
|
0
|
|
|
|
|
0
|
_diagnostic('tmpl_empty'); |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
} |
386
|
|
|
|
|
|
|
elsif ( ! ref $interface ) { |
387
|
167
|
100
|
|
|
|
2218
|
if ( exists $mm_def->{'interface'}{ $interface } ) { |
|
|
50
|
|
|
|
|
|
388
|
163
|
100
|
|
|
|
765
|
if ( ! ref $mm_def->{'interface'}{ $interface } ) { |
389
|
66
|
|
|
|
|
370
|
$mm_def->{'interface'}{ $interface } = |
390
|
|
|
|
|
|
|
{ '*' => $mm_def->{'interface'}{ $interface } }; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
} elsif ( exists $mm_def->{'behavior'}{ $interface } ) { |
393
|
4
|
|
|
|
|
18
|
$mm_def->{'interface'}{ $interface } = { '*' => $interface }; |
394
|
|
|
|
|
|
|
} else { |
395
|
0
|
|
|
|
|
0
|
_diagnostic('tmpl_unkown', $interface); |
396
|
|
|
|
|
|
|
} |
397
|
167
|
|
|
|
|
446
|
$interface = $mm_def->{'interface'}{ $interface }; |
398
|
|
|
|
|
|
|
|
399
|
167
|
100
|
|
|
|
912
|
return $interface if exists $interface->{'-parsed'}; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
elsif ( ref $interface ne 'HASH' ) { |
402
|
0
|
|
|
|
|
0
|
_diagnostic('tmpl_unsupported', $interface); |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
155
|
|
|
|
|
869
|
$interface->{'-parsed'} = "$_[1]"; |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# Allow interface inheritance via -base specification |
408
|
155
|
100
|
|
|
|
717
|
if ( $interface->{'-base'} ) { |
409
|
1
|
|
|
|
|
6
|
for ( split ' ', $interface->{'-base'} ) { |
410
|
1
|
|
|
|
|
7
|
my $base = _interpret_interface( $mm_def, $_ ); |
411
|
1
|
|
|
|
|
11
|
%$interface = ( %$base, %$interface ); |
412
|
|
|
|
|
|
|
} |
413
|
1
|
|
|
|
|
3
|
delete $interface->{'-base'}; |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
155
|
|
|
|
|
778
|
for (keys %$interface) { |
417
|
|
|
|
|
|
|
# Remove empty/undefined items. |
418
|
707
|
50
|
33
|
|
|
4326
|
unless ( defined $interface->{$_} and length $interface->{$_} ) { |
419
|
0
|
|
|
|
|
0
|
delete $interface->{$_}; |
420
|
0
|
|
|
|
|
0
|
next; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
} |
423
|
|
|
|
|
|
|
# _diagnostic('debug_interface', $_[1], join(', ', %$interface )); |
424
|
|
|
|
|
|
|
|
425
|
155
|
|
|
|
|
1273
|
return $interface; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
######################################################################## |
429
|
|
|
|
|
|
|
### BEHAVIORS AND MODIFIERS: _fold_modifiers(), _behavior_builder() |
430
|
|
|
|
|
|
|
######################################################################## |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
sub _fold_modifiers { |
433
|
7
|
|
|
7
|
|
13
|
my $spec = shift; |
434
|
7
|
|
|
|
|
8
|
my $rules = shift; |
435
|
7
|
|
|
|
|
35
|
my %rules = @$rules; |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
# Longest first, to prevent over-eager matching. |
438
|
51
|
|
|
|
|
99
|
my $rule = join '|', map "\Q$_\E", |
439
|
7
|
|
|
|
|
29
|
sort { length($b) <=> length($a) } keys %rules; |
440
|
|
|
|
|
|
|
# Match repeatedly from the front. |
441
|
7
|
|
|
|
|
309
|
1 while ( $spec =~ s/($rule)/$rules{$1}/ ); |
442
|
7
|
|
|
|
|
37
|
$spec =~ s/(^|\s)\s/$1/g; |
443
|
7
|
|
|
|
|
32
|
return $spec; |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
sub _behavior_builder { |
447
|
427
|
|
|
427
|
|
744
|
my ( $mm_def, $behavior, $m_info ) = @_; |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
# We're going to have to do some extra work here, so we'll cache the result |
450
|
427
|
|
|
|
|
666
|
my $builder; |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# Separate the modifiers |
453
|
427
|
|
|
|
|
622
|
my $core_behavior = $behavior; |
454
|
427
|
|
|
|
|
753
|
my @modifiers; |
455
|
427
|
|
|
|
|
1488
|
while ( $core_behavior =~ s/\-(\w+)\s// ) { push @modifiers, $1 } |
|
4
|
|
|
|
|
19
|
|
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# Find either the built-in or universal behavior template |
458
|
427
|
50
|
|
|
|
1338
|
if ( $mm_def->{'behavior'}{$core_behavior} ) { |
459
|
427
|
|
|
|
|
879
|
$builder = $mm_def->{'behavior'}{$core_behavior}; |
460
|
|
|
|
|
|
|
} else { |
461
|
0
|
|
|
|
|
0
|
my $universal = _definition('Class::MakeMethods::Template::Universal','generic'); |
462
|
0
|
|
|
|
|
0
|
$builder = $universal->{'behavior'}{$core_behavior} |
463
|
|
|
|
|
|
|
} |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
# Otherwise we're hosed. |
466
|
427
|
50
|
|
|
|
1085
|
$builder or _diagnostic('make_bad_behavior', $m_info->{'name'}, $behavior); |
467
|
|
|
|
|
|
|
|
468
|
427
|
50
|
|
|
|
1088
|
if ( ! ref $builder ) { |
|
|
0
|
|
|
|
|
|
469
|
|
|
|
|
|
|
# If we've got a text template, pass it off for interpretation. |
470
|
427
|
50
|
|
|
|
1830
|
my $code = ( ! $Class::MakeMethods::Utility::DiskCache::DiskCacheDir ) ? |
471
|
|
|
|
|
|
|
_interpret_text_builder($mm_def, $core_behavior, $builder, @modifiers) |
472
|
|
|
|
|
|
|
: _disk_cache_builder($mm_def, $core_behavior, $builder, @modifiers); |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
# _diagnostic('debug_eval_builder', $name, $code); |
475
|
427
|
50
|
|
|
|
2903
|
local $^W unless $Class::MakeMethods::CONTEXT{Debug}; |
476
|
427
|
100
|
100
|
460
|
|
76069
|
$builder = eval $code; |
|
460
|
100
|
100
|
1
|
|
45191
|
|
|
460
|
100
|
|
1
|
|
2272
|
|
|
283
|
100
|
|
1
|
|
4875
|
|
|
329
|
100
|
|
1
|
|
2436
|
|
|
267
|
|
|
1
|
|
7141
|
|
|
261
|
|
|
1
|
|
2809
|
|
|
220
|
|
|
1
|
|
7554
|
|
|
200
|
|
|
1
|
|
2137
|
|
|
179
|
|
|
1
|
|
3838
|
|
|
156
|
|
|
|
|
1734
|
|
|
175
|
|
|
|
|
3186
|
|
|
134
|
|
|
|
|
1687
|
|
|
185
|
|
|
|
|
7372
|
|
|
152
|
|
|
|
|
1301
|
|
|
98
|
|
|
|
|
2327
|
|
|
145
|
|
|
|
|
2233
|
|
|
156
|
|
|
|
|
719
|
|
|
141
|
|
|
|
|
771
|
|
|
150
|
|
|
|
|
2998
|
|
|
154
|
|
|
|
|
2307
|
|
|
111
|
|
|
|
|
837
|
|
|
171
|
|
|
|
|
1757
|
|
|
148
|
|
|
|
|
2133
|
|
|
141
|
|
|
|
|
764
|
|
|
68
|
|
|
|
|
1305
|
|
|
71
|
|
|
|
|
455
|
|
|
58
|
|
|
|
|
804
|
|
|
43
|
|
|
|
|
246
|
|
|
44
|
|
|
|
|
344
|
|
|
45
|
|
|
|
|
963
|
|
|
74
|
|
|
|
|
1796
|
|
|
74
|
|
|
|
|
1585
|
|
|
71
|
|
|
|
|
249
|
|
|
56
|
|
|
|
|
681
|
|
|
61
|
|
|
|
|
827
|
|
|
50
|
|
|
|
|
1341
|
|
|
33
|
|
|
|
|
167
|
|
|
45
|
|
|
|
|
1048
|
|
|
58
|
|
|
|
|
515
|
|
|
58
|
|
|
|
|
405
|
|
|
39
|
|
|
|
|
215
|
|
|
50
|
|
|
|
|
320
|
|
|
55
|
|
|
|
|
591
|
|
|
32
|
|
|
|
|
318
|
|
|
25
|
|
|
|
|
121
|
|
|
24
|
|
|
|
|
307
|
|
477
|
427
|
50
|
|
|
|
1471
|
if ( $@ ) { _diagnostic('behavior_eval', $@, $code) } |
|
0
|
|
|
|
|
0
|
|
478
|
427
|
50
|
|
|
|
1935
|
unless (ref $builder eq 'CODE') { _diagnostic('behavior_eval', $@, $code) } |
|
0
|
|
|
|
|
0
|
|
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
} elsif ( scalar @modifiers ) { |
481
|
|
|
|
|
|
|
# Can't modify code subs |
482
|
0
|
|
|
|
|
0
|
_diagnostic('make_behavior_mod', join(', ', @modifiers), $core_behavior); |
483
|
|
|
|
|
|
|
} |
484
|
|
|
|
|
|
|
|
485
|
427
|
|
|
|
|
1492
|
$mm_def->{'-behavior_cache'}{$behavior} = $builder; |
486
|
|
|
|
|
|
|
|
487
|
427
|
|
|
|
|
1169
|
return $builder; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
######################################################################## |
491
|
|
|
|
|
|
|
### CODE EXPRESSIONS: _interpret_text_builder(), _disk_cache_builder() |
492
|
|
|
|
|
|
|
######################################################################## |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
sub _interpret_text_builder { |
495
|
427
|
|
|
427
|
|
97310
|
require Class::MakeMethods::Utility::TextBuilder; |
496
|
|
|
|
|
|
|
|
497
|
427
|
|
|
|
|
1360
|
my ( $mm_def, $name, $code, @modifiers ) = @_; |
498
|
|
|
|
|
|
|
|
499
|
427
|
|
|
|
|
1059
|
foreach ( @modifiers ) { |
500
|
4
|
50
|
|
|
|
21
|
exists $mm_def->{'modifier'}{$_} |
501
|
|
|
|
|
|
|
or _diagnostic('behavior_mod_unknown', $name, $_); |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
|
504
|
1708
|
|
66
|
|
|
2906
|
my @exprs = grep { $_ } map { |
|
854
|
|
|
|
|
6639
|
|
505
|
427
|
100
|
|
|
|
1323
|
$mm_def->{'modifier'}{ $_ }, |
506
|
|
|
|
|
|
|
$mm_def->{'modifier'}{ "$_ $name" } || $mm_def->{'modifier'}{ "$_ *" } |
507
|
|
|
|
|
|
|
} ( '-all', ( scalar(@modifiers) ? @modifiers : '-default' ) ); |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
# Generic method template |
510
|
427
|
|
|
|
|
864
|
push @exprs, "return sub _SUB_ATTRIBS_ { \n my \$self = shift;\n * }"; |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# Closure-generator |
513
|
427
|
|
|
|
|
648
|
push @exprs, "sub { my \$m_info = \$_[0]; * }"; |
514
|
|
|
|
|
|
|
|
515
|
427
|
|
|
|
|
769
|
my $exprs = $mm_def->{code_expr}; |
516
|
8765
|
|
|
|
|
19465
|
unshift @exprs, { |
517
|
427
|
|
|
|
|
6541
|
( map { $_=>$exprs->{$_} } grep /^[^-]/, keys %$exprs ), |
518
|
|
|
|
|
|
|
'_BEHAVIOR_{}' => $mm_def->{'behavior'}, |
519
|
|
|
|
|
|
|
'_SUB_ATTRIBS_' => '', |
520
|
|
|
|
|
|
|
}; |
521
|
|
|
|
|
|
|
|
522
|
427
|
|
|
|
|
2914
|
my $result = Class::MakeMethods::Utility::TextBuilder::text_builder($code, |
523
|
|
|
|
|
|
|
@exprs); |
524
|
|
|
|
|
|
|
|
525
|
427
|
|
|
|
|
1238
|
my $modifier_string = join(' ', map "-$_", @modifiers); |
526
|
427
|
100
|
|
|
|
2431
|
my $full_name = "$name ($mm_def->{template_class} $mm_def->{template_name}" . |
527
|
|
|
|
|
|
|
( $modifier_string ? " $modifier_string" : '' ) . ")"; |
528
|
|
|
|
|
|
|
|
529
|
427
|
|
|
|
|
1202
|
_diagnostic('debug_template_builder', $full_name, $code, $result); |
530
|
|
|
|
|
|
|
|
531
|
427
|
|
|
|
|
8642
|
return $result; |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
sub _disk_cache_builder { |
535
|
0
|
|
|
0
|
|
0
|
require Class::MakeMethods::Utility::DiskCache; |
536
|
0
|
|
|
|
|
0
|
my ( $mm_def, $core_behavior, $builder, @modifiers ) = @_; |
537
|
|
|
|
|
|
|
|
538
|
0
|
|
|
|
|
0
|
Class::MakeMethods::Utility::DiskCache::disk_cache( |
539
|
|
|
|
|
|
|
"$mm_def->{template_class}::$mm_def->{template_name}", |
540
|
|
|
|
|
|
|
join('.', $core_behavior, @modifiers), |
541
|
|
|
|
|
|
|
\&_interpret_text_builder, ($mm_def, $core_behavior, $builder, @modifiers) |
542
|
|
|
|
|
|
|
); |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
1; |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
__END__ |