line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#!/usr/bin/perl |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package MooseX::Compile; |
4
|
2
|
|
|
2
|
|
36188
|
use base qw(MooseX::Compile::Base); |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
644
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
use strict; |
7
|
|
|
|
|
|
|
use warnings; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use constant DEBUG => MooseX::Compile::Base::DEBUG(); |
10
|
|
|
|
|
|
|
use constant default_compiler_class => "MooseX::Compile::Compiler"; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use Devel::INC::Sorted qw(inc_add_floating); |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
BEGIN { |
15
|
|
|
|
|
|
|
inc_add_floating(sub { |
16
|
|
|
|
|
|
|
my ( $self, $file ) = @_; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
if ( DEBUG ) { |
19
|
|
|
|
|
|
|
foreach my $pkg qw( |
20
|
|
|
|
|
|
|
Moose |
21
|
|
|
|
|
|
|
Moose::Meta::Class |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
Class::MOP |
24
|
|
|
|
|
|
|
Class::MOP::Class |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
metaclass |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
Moose::Util::TypeConstraints |
29
|
|
|
|
|
|
|
Moose::Meta::TypeConstraint |
30
|
|
|
|
|
|
|
Moose::Meta::TypeCoercion |
31
|
|
|
|
|
|
|
) { |
32
|
|
|
|
|
|
|
( my $pkg_file = "$pkg.pm" ) =~ s{::}{/}g; |
33
|
|
|
|
|
|
|
require Carp and Carp::carp("loading $pkg") if $file eq $pkg_file; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
if ( $ENV{MX_COMPILE_CLEAN} ) { |
38
|
|
|
|
|
|
|
foreach my $dir ( grep { not ref } @INC ) { |
39
|
|
|
|
|
|
|
my $full = "$dir/$file"; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
my $pmc = "${full}c"; |
42
|
|
|
|
|
|
|
( my $mopc = $full ) =~ s/\.pm$/.mopc/; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
if ( -e $pmc && -e $mopc ) { |
45
|
|
|
|
|
|
|
warn "removing compiled class for file '$file'\n" if DEBUG; |
46
|
|
|
|
|
|
|
unlink $pmc or die "Can't remove pmc file (unlink($pmc)): $!"; |
47
|
|
|
|
|
|
|
unlink $mopc or die "Can't remove cached metaclass (unlink($mopc)): $!"; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
return; |
53
|
|
|
|
|
|
|
}); |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub import { |
57
|
|
|
|
|
|
|
my ($self, @args) = @_; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
my ( $class, $file ) = caller(); |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
if ( $MooseX::Compile::Bootstrap::known_pmc_files{$file} ) { |
62
|
|
|
|
|
|
|
return $self->import_from_pmc( $class, $file, @args ); |
63
|
|
|
|
|
|
|
} else { |
64
|
|
|
|
|
|
|
warn "class '$class' requires compilation\n" if DEBUG; |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
require Check::UnitCheck; |
67
|
|
|
|
|
|
|
Check::UnitCheck::unitcheckify(sub { |
68
|
|
|
|
|
|
|
warn "compilation unit of class '$class' calling UNITCHECK\n" if DEBUG; |
69
|
|
|
|
|
|
|
$self->unit_check( $class, $file, @args ); |
70
|
|
|
|
|
|
|
}); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
require Moose; |
73
|
|
|
|
|
|
|
shift; unshift @_, "Moose"; |
74
|
|
|
|
|
|
|
goto \&Moose::import; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub import_from_pmc { |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub unit_check { |
83
|
|
|
|
|
|
|
my ( $self, $class, $file, @args ) = @_; |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
$self->compile_from_import( |
86
|
|
|
|
|
|
|
class => $class, |
87
|
|
|
|
|
|
|
file => $file, |
88
|
|
|
|
|
|
|
@args, |
89
|
|
|
|
|
|
|
); |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub compile_from_import { |
93
|
|
|
|
|
|
|
my ( $self, %args ) = @_; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
if ( $ENV{MX_COMPILE_IMPLICIT_ANCESTORS} ) { |
96
|
|
|
|
|
|
|
warn "implicitly compiling all ancestors of class '$args{class}'\n" if DEBUG; |
97
|
|
|
|
|
|
|
$self->compile_ancestors( %args ); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
$self->compile_class( %args ); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub compile_ancestors { |
104
|
|
|
|
|
|
|
my ( $self, %args ) = @_; |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
my $class = $args{class}; |
107
|
|
|
|
|
|
|
my $files = $args{files} || {}; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
foreach my $superclass ( reverse $class->meta->linearized_isa ) { |
110
|
|
|
|
|
|
|
next if $superclass eq $class; |
111
|
|
|
|
|
|
|
warn "compiling '$class' superclass '$superclass'\n" if DEBUG; |
112
|
|
|
|
|
|
|
$self->compile_class( %args, class => $superclass, file => $files->{$superclass} ); |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub compile_class { |
117
|
|
|
|
|
|
|
my ( $self, %args ) = @_; |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
my $compiler = $self->create_compiler( %args ); |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
$compiler->compile_class( %args ); |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub compiler_class { |
125
|
|
|
|
|
|
|
my ( $self, %args ) = @_; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
$args{compiler_class} || $self->default_compiler_class; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub create_compiler { |
131
|
|
|
|
|
|
|
my ( $self, @args ) = @_; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
my $compiler_class = $self->compiler_class(@args); |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
$self->load_classes($compiler_class); |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
$compiler_class->new( @args ); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
__PACKAGE__; |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
__END__ |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=pod |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=encoding utf8 |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head1 NAME |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
MooseX::Compile - L<Moose> ⥠L<.pmc> |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head1 SYNOPSIS |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
In C<MyClass.pm>: |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
package MyClass; |
157
|
|
|
|
|
|
|
use Moose; |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# your moose class here |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
On the command line: |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
$ mkcompile compile --make-immutable MyClass |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Or to always compile: |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
use MooseX::Compile; # instead of use Moose |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head1 HERE BE DRAGONS |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
This is alpha code. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
If you decide to to use it please come by the C<#moose> IRC channel on |
174
|
|
|
|
|
|
|
C<irc.perl.org> (maybe this link works: L<irc://irc.perl.org/#moose>). |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
Your help in testing this is highly valued, so please feel free to verbally |
177
|
|
|
|
|
|
|
abuse C<nothingmuch> in C<#moose> until things are working properly. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 DESCRIPTION |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
The example in the L</SYNOPSIS> will compile C<MyClass> into two files, |
182
|
|
|
|
|
|
|
C<MyClass.pmc> and C<MyClass.mopc>. The C<.pmc> file caches all of the |
183
|
|
|
|
|
|
|
generated code, and the C<.mopc> file is a L<Storable> file of the metaclass |
184
|
|
|
|
|
|
|
instance. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
When C<MyClass> is loaded the next time, Perl will see the C<.pmc> file and |
187
|
|
|
|
|
|
|
load that instead. This file will load faster for several reasons: |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=over 4 |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=item * |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
L<Moose> is no longer required to load C<MyClass>, all the methods L<Moose> |
194
|
|
|
|
|
|
|
normally generates are already saved in the C<.pmc> file. |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=item * |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
The metaclass does not need to be loaded, at least until you introspect. |
199
|
|
|
|
|
|
|
C<meta> for compiled classes will lazy load the already computed metaclass |
200
|
|
|
|
|
|
|
instance from the C<.mopc> file. When it is needed the instance will be |
201
|
|
|
|
|
|
|
deserialized and it's class (probably L<Moose::Meta::Class>) will be loaded. |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=back |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
If all your classes are compiled and you don't use introspection in your code, |
206
|
|
|
|
|
|
|
you can then deploy your code without using moose. |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head1 MODUS OPERANDI |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
This is not a source filter. |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
Due to the fragility of source filtering in Perl, C<MooseX::Compile::Compiler> |
213
|
|
|
|
|
|
|
will not alter the body of the class, but instead prefix it with a preamble |
214
|
|
|
|
|
|
|
that sets up the right environment for it. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
This involves temporarily overriding C<CORE::GLOBAL::require> to hide C<Moose> |
217
|
|
|
|
|
|
|
from this module (but not others), and stubbing the sugar with no-ops (the |
218
|
|
|
|
|
|
|
various declarations are thus effectively stripped without altering the source |
219
|
|
|
|
|
|
|
code), amongst other things. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Then the source code of the original class is executed normally, and when the |
222
|
|
|
|
|
|
|
file's lexical scope gets cleaned up then the final pieces of the class are put |
223
|
|
|
|
|
|
|
in place and all the trickery is undone. |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
Until this point C<meta> is replaced with a mock object that will silently or |
226
|
|
|
|
|
|
|
loudly ignore various method calls depending on their nature. For instance |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable(); |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
is a silent no-op, because when the compiler compiled it the class was already |
231
|
|
|
|
|
|
|
immutable, so the loaded version will be immutable too. |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
On the other hand |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
__PACKAGE__->meta->superclasses(qw(Foo)); |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
will complain because the value of C<@ISA> is already captured, and changing it |
238
|
|
|
|
|
|
|
is meaningless. |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=head1 INTERFACE FOR COMPILED MODULES |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=item C<$__mx_is_compiled> |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
This variable is set at C<BEGIN> for modules in a C<.pmc>. This allows you to |
245
|
|
|
|
|
|
|
write conditional code, like: |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
use if not(our $__mx_is_compiled) metaclass => "Blah"; |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
__PACKAGE__->meta->add_attribute( ... ) unless our $__mx_is_compiled; |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
=item C<__mx_compile_post_hook> |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
If you add a subroutine named C<__mx_compile_post_hook> to your class it will |
254
|
|
|
|
|
|
|
be called at the end of compilation, allowing you to to diddle the class after |
255
|
|
|
|
|
|
|
loading. |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
=head1 LIMITATIONS |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
This developer release comes with some serious limitations. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
It has so far only been tested with the C<Point> and C<Point3D> classes from |
262
|
|
|
|
|
|
|
the recipe. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
This means: |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=over 4 |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=item * |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
No method modifiers are supported yet. We know how and it's going to take a while longer. |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=item * |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
Only core, optimized Moose types are guaranteed to work (C<Int>, C<Str>, etc). |
275
|
|
|
|
|
|
|
Other types may or may not deparse properly. |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=item * |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
Roles are not yet supported. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=item * |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
Stuff is definitely going to break. This is just a first release of a fairly |
284
|
|
|
|
|
|
|
complex project, so bear with us =) |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=back |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=head1 TODO |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
There is a fairly long F<TODO> file in the distribution. |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=head1 SEE ALSO |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
L<MooseX::Compile::Compiler>, L<MooseX::Compile::Bootstrap>, |
295
|
|
|
|
|
|
|
L<MooseX::Compile::CLI>. |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=head1 VERSION CONTROL |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
L<http://code2.0beta.co.uk/moose/svn/MooseX-Compile/trunk> |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head1 AUTHOR |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
Yuval Kogman E<lt>nothingmuch@woobling.orgE<gt> |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=head1 COPYRIGHT |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
Copyright (c) 2008 Infinity Interactive, Yuval Kogman. All rights reserved |
308
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
309
|
|
|
|
|
|
|
under the same terms as Perl itself. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
=cut |
312
|
|
|
|
|
|
|
|