line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
18
|
|
|
18
|
|
697470
|
use strict; |
|
18
|
|
|
|
|
56
|
|
|
18
|
|
|
|
|
1095
|
|
2
|
18
|
|
|
18
|
|
100
|
use warnings; |
|
18
|
|
|
|
|
37
|
|
|
18
|
|
|
|
|
1391
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Class::AutoGenerate; |
5
|
|
|
|
|
|
|
|
6
|
18
|
|
|
18
|
|
16650
|
use Class::AutoGenerate::Declare (); |
|
18
|
|
|
|
|
49
|
|
|
18
|
|
|
|
|
474
|
|
7
|
18
|
|
|
18
|
|
153
|
use Scalar::Util qw/ blessed reftype /; |
|
18
|
|
|
|
|
32
|
|
|
18
|
|
|
|
|
3947
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = 0.05; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our %AUTOGENERATED; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 NAME |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Class::AutoGenerate - Automatically generate code upon require or use |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
=head1 SYNOPSIS |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# Create a customized class loader (auto-generator) |
20
|
|
|
|
|
|
|
package My::ClassLoader; |
21
|
|
|
|
|
|
|
use Class::AutoGenerate -base; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# Define a matching rule that generates some code... |
24
|
|
|
|
|
|
|
requiring 'Some::**::Class' => generates { qq{ |
25
|
|
|
|
|
|
|
sub print_my_middle_names { print $1,"\n" } |
26
|
|
|
|
|
|
|
} }; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# In some other file, let's use the class loader |
29
|
|
|
|
|
|
|
package main; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Create the class loader, which adds itself to @INC |
32
|
|
|
|
|
|
|
use My::ClassLoader; |
33
|
|
|
|
|
|
|
BEGIN { My::ClassLoader->new( match_only => '**::Freaking::Class' ); } |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# These class will be generated on the fly... |
36
|
|
|
|
|
|
|
use Some::Freaking::Class; |
37
|
|
|
|
|
|
|
use Some::Other::Freaking::Class; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
Some::Freaking::Class->print_my_middle_names; |
40
|
|
|
|
|
|
|
Some::Other::Freaking::Class->print_my_middle_names; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# Output is: |
43
|
|
|
|
|
|
|
# Freaking |
44
|
|
|
|
|
|
|
# Other::Freaking |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head1 DESCRIPTION |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
B I'm trying this idea out. Please let me know what you think by contacting me using the information listed under L. This is an experiment and any and all aspects of the API are up for revision at this point and I'm not even sure I'll maintain it, but I hope it will be found useful to myself and others. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
Sometimes it's nice to be able to generate code on the fly. This tool does just that. You declare a few rules that can be used to define the class names you want to auto-generate and then the code that is to be built from it. Later you create your auto-generator object and start using the auto-generated classes. |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
This is a generalization baed upon L. If this experiment is successful in the way I'm testing it out for, it may be used to re-implement that class. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head1 METHODS |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head2 import |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
When you are creating a new auto-generating class loader, you will include this statement in your package definition: |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
package My::ClassLoader; |
61
|
|
|
|
|
|
|
use Class::AutoGenerate -base; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
This statement tells L to import all the subroutines in L into the current package so that a new class loader can be declared. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
Later, when you use your class loader, you will use the undecorated form: |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
use My::ClassLoader; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
In this case, the import method does nothing special. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=cut |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub import { |
74
|
21
|
|
|
21
|
|
879
|
my $class = shift; |
75
|
21
|
|
|
|
|
52
|
my $base = shift; |
76
|
|
|
|
|
|
|
|
77
|
21
|
|
|
|
|
83
|
my $package = caller; |
78
|
|
|
|
|
|
|
|
79
|
21
|
100
|
66
|
|
|
306
|
if (defined $base and $base eq '-base') { |
80
|
18
|
|
|
|
|
4309
|
Class::AutoGenerate::Declare->export_to_level(1, undef); |
81
|
|
|
|
|
|
|
|
82
|
18
|
|
|
18
|
|
100
|
no strict 'refs'; |
|
18
|
|
|
|
|
31
|
|
|
18
|
|
|
|
|
596
|
|
83
|
18
|
|
|
18
|
|
122
|
no warnings 'once'; |
|
18
|
|
|
|
|
33
|
|
|
18
|
|
|
|
|
71041
|
|
84
|
18
|
|
|
|
|
43
|
push @{ $package . '::ISA' }, $class; |
|
18
|
|
|
|
|
690
|
|
85
|
18
|
|
|
|
|
44
|
@{ $package . '::RULES' } = (); |
|
18
|
|
|
|
|
157
|
|
86
|
|
|
|
|
|
|
|
87
|
18
|
|
|
|
|
41
|
*{ $package . '::autogenerated' } = *autogenerated; |
|
18
|
|
|
|
|
201
|
|
88
|
18
|
|
|
|
|
41
|
*{ $package . '::autogenerator_of' } = *autogenerator_of; |
|
18
|
|
|
|
|
101
|
|
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
21
|
|
|
|
|
63615
|
return 1; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=head2 new |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
Creates a new instance of the auto-generating class loader object you've built. The class loader automatically adds itself to the C<@INC> array to start loading classes. |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
If you want to immediately start using the class loader at compile time, you may wish to call this method within a C block: |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
use My::Custom::ClassLoader; |
101
|
|
|
|
|
|
|
BEGIN { My::Custom::ClassLoader->new }; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
The constructor also recognizes the following options, passed in a hash, that can modify the behavior of the class loader. |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=over |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=item match_only |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
This argument may be passed as anything that would be accepted in a L clause and is used to prequalify which classes may actually be generated by this class loader. Using this, you can build one generic class loader that may be limited in how it is applied. |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
A module will only be generated if it first matches at least one of the patterns provided to "match_only". |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
For example, |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
package My::ClassLoader; |
116
|
|
|
|
|
|
|
use Class::AutoGenerate -base; |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
requiring '**' => generates {}; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
1; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
BEGIN { |
123
|
|
|
|
|
|
|
My::ClassLoader->new( match_only => [ 'Prefix1::**', 'Prefix2::*' ] ); |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
use Prefix1::Thing; |
127
|
|
|
|
|
|
|
use Prefix2::Thing; |
128
|
|
|
|
|
|
|
use Prefix3::Thing; # <--- ERROR: does not match the match_only clause |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=back |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=cut |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub new { |
135
|
21
|
|
|
21
|
1
|
84
|
my $class = shift; |
136
|
21
|
|
|
|
|
67
|
my %args = @_; |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# Create the class |
139
|
21
|
|
|
|
|
78
|
my $self = bless \%args, $class; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# if the match_only is given, remember that |
142
|
21
|
100
|
|
|
|
219
|
if (defined $self->{match_only}) { |
143
|
7
|
100
|
|
|
|
735
|
$self->{match_only} = [ $self->{match_only} ] |
144
|
|
|
|
|
|
|
unless ref $self->{match_only}; |
145
|
|
|
|
|
|
|
|
146
|
7
|
|
|
|
|
42
|
$_ = Class::AutoGenerate::Declare::_compile_glob_pattern($_) |
147
|
7
|
|
|
|
|
12
|
foreach (@{ $self->{match_only} }); |
148
|
|
|
|
|
|
|
|
149
|
7
|
50
|
|
|
|
38
|
$self->{match_only} = $self->{match_only} |
150
|
|
|
|
|
|
|
if defined $self->{match_only}; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# Now, load the rule set from the declarations |
154
|
21
|
|
|
|
|
75
|
for my $declaration (@{ $self->_declarations }) { |
|
21
|
|
|
|
|
73
|
|
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
# Handle declare { ... } blocks |
157
|
47
|
100
|
|
|
|
198
|
if (reftype $declaration eq 'CODE') { |
158
|
2
|
|
|
|
|
7
|
my @declarations = $declaration->($self); |
159
|
2
|
|
|
|
|
3
|
push @{ $self->{rules} }, @declarations; |
|
2
|
|
|
|
|
11
|
|
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# Handle top-level requiring ... => rules |
163
|
|
|
|
|
|
|
else { |
164
|
45
|
|
|
|
|
60
|
push @{ $self->{rules} }, $declaration; |
|
45
|
|
|
|
|
162
|
|
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# place ourself into @INC |
169
|
21
|
|
|
|
|
60
|
push @INC, $self; |
170
|
|
|
|
|
|
|
|
171
|
21
|
|
|
|
|
63
|
return $self; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=head2 INC |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
This is the subroutine called by Perl during a L or L and evaluates the rules defined in your class loader. See L (towards the end) to see how this works. |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
It should be noted, however, that we cheat the system a little bit. According ot the require hook API, this method should return either a filehandle containing the code to be read or C indicating that the hook does not know about the file being required. |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
This is done, except that only an empty stub package like this is ever returned when a class is auto-generated: |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
use strict; |
183
|
|
|
|
|
|
|
use warnings; |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
package The::Included::Package::Name; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
1; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
Instead of having the import mechanism within Perl compile the code, most of the work is handled through symbol table manipulations and code evaluation before the file handle is returned. This allows for some earlier compile-time checking via closures and the like. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=cut |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# Use the fully-qualified name since Perl ignores "sub INC" |
194
|
|
|
|
|
|
|
# (see perldoc require) |
195
|
|
|
|
|
|
|
sub Class::AutoGenerate::INC { |
196
|
104
|
|
|
104
|
1
|
145802
|
my $self = shift; |
197
|
104
|
|
|
|
|
322
|
my $module = shift; |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# Canonicalize $module to :: style rather than / and .pm style |
200
|
104
|
|
|
|
|
721
|
$module =~ s{\.pm$}{}; |
201
|
104
|
|
|
|
|
446
|
$module =~ s{/}{::}g; |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# Pass off control to _match_and_generate() to do the real work |
204
|
104
|
|
|
|
|
600
|
return $self->_match_and_generate($module); |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=head2 autogenerated MODULE |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
This method may be called in any of the following ways: |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
Class::AutoGenerate::autogenerated 'Some::Module'; |
212
|
|
|
|
|
|
|
Class::AutoGenerate->autogenerated('Some::Module'); |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# Where My::AutoGenerator->isa('Class::AutoGenerate') |
215
|
|
|
|
|
|
|
My::AutoGenerator::autogenerated 'Some::Module'; |
216
|
|
|
|
|
|
|
My::AutoGenerator->autogenerated('Some::Module'); |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# Where $autogenerator->isa('Class::AutoGenerate'); |
219
|
|
|
|
|
|
|
$autogenerator->autogenerated('Some::Module'); |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Returns true if the package named was autogenerated by a L class loader. Returns C in any other case. |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=cut |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub autogenerated($) { |
226
|
18
|
|
|
18
|
1
|
862
|
my $class = shift; |
227
|
18
|
50
|
33
|
|
|
152
|
if (blessed $class or (not ref $class and $class =~ /^[:\w]+$/)) { |
|
|
|
66
|
|
|
|
|
228
|
18
|
100
|
|
|
|
118
|
$class = shift if $class->isa('Class::AutoGenerate'); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
18
|
|
|
|
|
88
|
return exists $AUTOGENERATED{ $class }; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=head2 autogenerator_of MODULE |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
This method may be called in any of the following ways: |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
Class::AutoGenerate::autogenerator_of 'Some::Module'; |
239
|
|
|
|
|
|
|
Class::AutoGenerate->autogenerator_of('Some::Module'); |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# Where My::AutoGenerator->isa('Class::AutoGenerate') |
242
|
|
|
|
|
|
|
My::AutoGenerator::autogenerator_of 'Some::Module'; |
243
|
|
|
|
|
|
|
My::AutoGenerator->autogenerator_of('Some::Module'); |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Where $autogenerator->isa('Class::AutoGenerate'); |
246
|
|
|
|
|
|
|
$autogenerator->autogenerator_of('Some::Module'); |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
Returns the object that was used to autogenerate the module. This is really just a shortcut for looking up the information in C<%INC>, but saves some work of converting Perl module names into package file names and the cryptic use of the C<%INC> variable. |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=cut |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub autogenerator_of($) { |
253
|
18
|
|
|
18
|
1
|
42
|
my $class = shift; |
254
|
18
|
50
|
33
|
|
|
172
|
if (blessed $class or (not ref $class and $class =~ /^[:\w]+$/)) { |
|
|
|
66
|
|
|
|
|
255
|
18
|
100
|
|
|
|
110
|
$class = shift if $class->isa('Class::AutoGenerate'); |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# Convert the module name into a package file, Some::Thing -> Some/Thing.pm |
259
|
18
|
|
|
|
|
64
|
my $package_file = $class; |
260
|
18
|
|
|
|
|
254
|
$package_file =~ s{::}{/}g; |
261
|
18
|
|
|
|
|
27
|
$package_file .= '.pm'; |
262
|
|
|
|
|
|
|
|
263
|
18
|
100
|
|
|
|
126
|
return exists($INC{ $package_file }) ? $INC{ $package_file } : undef; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=head2 _match_and_generate MODULE |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
This method is used internally to match L statements and automatically generate code upon a match. |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=cut |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
sub _match_and_generate { |
273
|
104
|
|
|
104
|
|
175
|
my $self = shift; |
274
|
104
|
|
|
|
|
301
|
my $module = shift; |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
# If match_only is specified, make sure it matches that first |
277
|
104
|
100
|
|
|
|
509
|
if (defined $self->{match_only}) { |
278
|
59
|
|
|
|
|
170
|
return unless grep { $self->_match_requiring($module, $_) } |
|
34
|
|
|
|
|
99
|
|
279
|
34
|
100
|
|
|
|
49
|
@{ $self->{match_only} }; |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
# Get the requiring/generates rules |
283
|
101
|
|
|
|
|
381
|
my $rules = $self->_rules; |
284
|
|
|
|
|
|
|
#use Data::Dumper; |
285
|
|
|
|
|
|
|
#$Data::Dumper::Deparse = 1; |
286
|
|
|
|
|
|
|
#Test::More::diag(Dumper($rules)); |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
# Iterate through the rules |
289
|
|
|
|
|
|
|
RULE: |
290
|
101
|
|
|
|
|
254
|
for my $rule (@$rules) { |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
# Does it match? First match wins... |
293
|
252
|
100
|
|
|
|
764
|
if ($self->_match_requiring($module, $rule->[0])) { |
294
|
86
|
|
|
|
|
182
|
my $conclude_with = eval { |
295
|
86
|
|
|
|
|
636
|
$self->_autogenerate($module, $rule->[0], $rule->[1]); |
296
|
|
|
|
|
|
|
}; |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# Handle a call to next_rule |
299
|
86
|
100
|
|
|
|
443
|
if ($@ eq "NEXT_RULE\n") { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
300
|
1
|
|
|
|
|
5
|
next RULE; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
# Handle a call to last_rule |
304
|
|
|
|
|
|
|
elsif ($@ eq "LAST_RULE\n") { |
305
|
1
|
|
|
|
|
3
|
last RULE; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
# Handle a regular exception |
309
|
|
|
|
|
|
|
elsif ($@) { |
310
|
0
|
|
|
|
|
0
|
die $@; |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
# Return the empty stub to signal class found |
314
|
84
|
|
|
|
|
386
|
return $self->_stub_file_handle($module, $conclude_with); |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# Return undef to signal no such file found |
319
|
17
|
|
|
|
|
549
|
return; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=head2 _declarations |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
Used internally to reference the L blocks and top-level L rules in the auto-generating class loader's definition. |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
These are, then, instantiated to build the L for the object when L is called. |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=cut |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
sub _declarations { |
331
|
65
|
|
|
65
|
|
115
|
my $self = shift; |
332
|
65
|
|
66
|
|
|
386
|
my $package = blessed $self || $self; |
333
|
|
|
|
|
|
|
|
334
|
18
|
|
|
18
|
|
303
|
no strict 'refs'; |
|
18
|
|
|
|
|
55
|
|
|
18
|
|
|
|
|
792
|
|
335
|
18
|
|
|
18
|
|
108
|
no warnings 'once'; |
|
18
|
|
|
|
|
56
|
|
|
18
|
|
|
|
|
8201
|
|
336
|
65
|
|
|
|
|
93
|
return \@{ $package . '::DECLARATIONS' }; |
|
65
|
|
|
|
|
627
|
|
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=head2 _rules |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
Used internally to reference the rules declared and instantiated within the auto-generating class loader. |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=cut |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
sub _rules { |
346
|
101
|
|
|
101
|
|
151
|
my $self = shift; |
347
|
101
|
|
|
|
|
285
|
return $self->{rules}; |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
=head2 _match_requiring MODULE, PATTERN |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
Used internally to match a L declaration to a package name. Returns true if there's a match, or false otherwise. |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=cut |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
sub _match_requiring { |
357
|
311
|
|
|
311
|
|
422
|
my $self = shift; |
358
|
311
|
|
|
|
|
370
|
my $module = shift; |
359
|
311
|
|
|
|
|
353
|
my $pattern = shift; |
360
|
|
|
|
|
|
|
|
361
|
311
|
100
|
|
|
|
1873
|
if ($module =~ $pattern) { |
362
|
|
|
|
|
|
|
#Test::More::diag("$module matches $pattern"); |
363
|
117
|
|
|
|
|
451
|
return 1; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
else { |
366
|
|
|
|
|
|
|
#Test::More::diag("$module misses $pattern"); |
367
|
194
|
|
|
|
|
609
|
return; |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=head2 _autogenerate MODULE, PATTERN, GENERATES |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
This method performs the action of taking the work in the generates declration and stuffing that work into the named package. |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=cut |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
our ($package, $conclude_with); |
378
|
|
|
|
|
|
|
sub _autogenerate { |
379
|
86
|
|
|
86
|
|
144
|
my $self = shift; |
380
|
86
|
|
|
|
|
137
|
my $module = shift; |
381
|
86
|
|
|
|
|
118
|
my $pattern = shift; |
382
|
86
|
|
|
|
|
133
|
my $generates = shift; |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
# match again to setup $1, $2, etc... |
385
|
86
|
|
|
|
|
387
|
$module =~ $pattern; |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
# Setup the $package variable used inside the various declarations |
388
|
86
|
|
|
|
|
191
|
local $package = $module; |
389
|
86
|
|
|
|
|
283
|
local $conclude_with = []; |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# Call the code to generate the various codes |
392
|
86
|
|
|
|
|
287
|
$generates->(); |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# Remember that it was generated |
395
|
84
|
|
|
|
|
31483
|
$AUTOGENERATED{ $module } = 1; |
396
|
|
|
|
|
|
|
|
397
|
84
|
|
|
|
|
318
|
return $conclude_with; |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=head2 _stub_file_handle MODULE, CONCLUSIONS |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
Returns a basic stub class that is handed off to the import infrastructure of Perl to let it know that we succeeded, even though we already did most of the work for it. |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
=cut |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
sub _stub_file_handle { |
407
|
84
|
|
|
84
|
|
135
|
my $self = shift; |
408
|
84
|
|
|
|
|
127
|
my $module = shift; |
409
|
84
|
|
50
|
|
|
239
|
my $conclusions = shift || []; |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# Here's the stub code... |
412
|
84
|
|
|
|
|
234
|
my $code = qq{use strict; use warnings; package $module; }; |
413
|
84
|
|
|
|
|
217
|
for my $conclusion (@$conclusions) { |
414
|
2
|
|
|
|
|
9
|
$code .= "{ $conclusion } "; |
415
|
|
|
|
|
|
|
} |
416
|
84
|
|
|
|
|
249
|
$code .= "1; "; |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
# Magick that code into a file handle |
419
|
18
|
|
|
18
|
|
144
|
open my $fh, '<', \$code; |
|
18
|
|
|
|
|
34
|
|
|
18
|
|
|
|
|
136
|
|
|
84
|
|
|
|
|
1779
|
|
420
|
84
|
|
|
|
|
63217
|
return $fh; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
=head1 SEE ALSO |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
L |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
=head1 AUTHOR |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
Andrew Sterling Hanenkamp C<< >> |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
Copyright 2007 Boomer Consulting, Inc. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
This program is free software and may be modified and distributed under the same terms as Perl itself. |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=cut |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
1; |