File Coverage

blib/lib/MooseX/Compile.pm
Criterion Covered Total %
statement 3 3 100.0
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 4 4 100.0


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