eecb2f77236246a2b9e3c69656d43382ad827e93
[gitmo/Moose.git] / lib / Moose / Exporter.pm
1 package Moose::Exporter;
2
3 use strict;
4 use warnings;
5
6 use Carp qw( confess );
7 use Class::MOP;
8 use List::MoreUtils qw( first_index uniq );
9 use Sub::Exporter;
10
11
12 my %EXPORT_SPEC;
13
14 sub build_import_methods {
15     my $class = shift;
16     my %args  = @_;
17
18     my $exporting_package = caller();
19
20     $EXPORT_SPEC{$exporting_package} = \%args;
21
22     my @exports_from = $class->_follow_also( $exporting_package );
23
24     my $exports
25         = $class->_make_sub_exporter_params( $exporting_package, @exports_from );
26
27     my $exporter = Sub::Exporter::build_exporter(
28         {
29             exports => $exports,
30             groups  => { default => [':all'] }
31         }
32     );
33
34     # $args{_export_to_main} exists for backwards compat, because
35     # Moose::Util::TypeConstraints did export to main (unlike Moose &
36     # Moose::Role).
37     my $import = $class->_make_import_sub( $exporter, \@exports_from, $args{_export_to_main} );
38
39     my $unimport = $class->_make_unimport_sub( \@exports_from, [ keys %{$exports} ] );
40
41     no strict 'refs';
42     *{ $exporting_package . '::import' }   = $import;
43     *{ $exporting_package . '::unimport' } = $unimport;
44 }
45
46 {
47     my %seen;
48
49     sub _follow_also {
50         my $class             = shift;
51         my $exporting_package = shift;
52
53         %seen = ( $exporting_package => 1 );
54
55         return uniq( _follow_also_real($exporting_package) );
56     }
57
58     sub _follow_also_real {
59         my $exporting_package = shift;
60
61         die "Package in also ($exporting_package) does not seem to use MooseX::Exporter"
62             unless exists $EXPORT_SPEC{$exporting_package};
63
64         my $also = $EXPORT_SPEC{$exporting_package}{also};
65
66         return unless defined $also;
67
68         my @also = ref $also ? @{$also} : $also;
69
70         for my $package (@also)
71         {
72             die "Circular reference in also parameter to MooseX::Exporter between $exporting_package and $package"
73                 if $seen{$package};
74
75             $seen{$package} = 1;
76         }
77
78         return @also, map { _follow_also_real($_) } @also;
79     }
80 }
81
82 sub _make_sub_exporter_params {
83     my $class    = shift;
84     my @packages = @_;
85
86     my %exports;
87
88     for my $package (@packages) {
89         my $args = $EXPORT_SPEC{$package}
90             or die "The $package package does not use Moose::Exporter\n";
91
92         for my $name ( @{ $args->{with_caller} } ) {
93             my $sub = do {
94                 no strict 'refs';
95                 \&{ $package . '::' . $name };
96             };
97
98             $exports{$name} = $class->_make_wrapped_sub(
99                 $package,
100                 $name,
101                 $sub
102             );
103         }
104
105         for my $name ( @{ $args->{as_is} } ) {
106             my $sub;
107
108             if ( ref $name ) {
109                 $sub  = $name;
110                 $name = ( Class::MOP::get_code_info($name) )[1];
111             }
112             else {
113                 $sub = do {
114                     no strict 'refs';
115                     \&{ $package . '::' . $name };
116                 };
117             }
118
119             $exports{$name} = sub {$sub};
120         }
121     }
122
123     return \%exports;
124 }
125
126 {
127     # This variable gets closed over in each export _generator_. Then
128     # in the generator we grab the value and close over it _again_ in
129     # the real export, so it gets captured each time the generator
130     # runs.
131     #
132     # In the meantime, we arrange for the import method we generate to
133     # set this variable to the caller each time it is called.
134     #
135     # This is all a bit confusing, but it works.
136     my $CALLER;
137
138     sub _make_wrapped_sub {
139         my $class             = shift;
140         my $exporting_package = shift;
141         my $name              = shift;
142         my $sub               = shift;
143
144         # We need to set the package at import time, so that when
145         # package Foo imports has(), we capture "Foo" as the
146         # package. This lets other packages call Foo::has() and get
147         # the right package. This is done for backwards compatibility
148         # with existing production code, not because this is a good
149         # idea ;)
150         return sub {
151             my $caller = $CALLER;
152             Class::MOP::subname( $exporting_package . '::'
153                     . $name => sub { $sub->( $caller, @_ ) } );
154         };
155     }
156
157     sub _make_import_sub {
158         shift;
159         my $exporter       = shift;
160         my $exports_from   = shift;
161         my $export_to_main = shift;
162
163         return sub {
164             # I think we could use Sub::Exporter's collector feature
165             # to do this, but that would be rather gross, since that
166             # feature isn't really designed to return a value to the
167             # caller of the exporter sub.
168             #
169             # Also, this makes sure we preserve backwards compat for
170             # _get_caller, so it always sees the arguments in the
171             # expected order.
172             my $traits;
173             ($traits, @_) = Moose::Exporter::_strip_traits(@_);
174
175             # It's important to leave @_ as-is for the benefit of
176             # Sub::Exporter.
177             my $class = $_[0];
178
179             $CALLER = Moose::Exporter::_get_caller(@_);
180
181             # this works because both pragmas set $^H (see perldoc
182             # perlvar) which affects the current compilation -
183             # i.e. the file who use'd us - which is why we don't need
184             # to do anything special to make it affect that file
185             # rather than this one (which is already compiled)
186
187             strict->import;
188             warnings->import;
189
190             # we should never export to main
191             if ( $CALLER eq 'main' && ! $export_to_main ) {
192                 warn
193                     qq{$class does not export its sugar to the 'main' package.\n};
194                 return;
195             }
196
197             my $did_init_meta;
198             for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
199
200                 $c->init_meta( for_class => $CALLER );
201                 $did_init_meta = 1;
202             }
203
204             _apply_meta_traits( $CALLER, $traits )
205                 if $did_init_meta;
206
207             goto $exporter;
208         };
209     }
210 }
211
212 sub _strip_traits {
213     my $idx = first_index { $_ eq '-traits' } @_;
214
215     return ( undef, @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
216
217     my $traits = $_[ $idx + 1 ];
218
219     splice @_, $idx, 2;
220
221     return ( $traits, @_ );
222 }
223
224 sub _apply_meta_traits {
225     my ( $class, $traits ) = @_;
226
227     return
228         unless $traits && @$traits;
229
230     my $meta = $class->meta();
231
232     my $type = ( split /::/, ref $meta )[-1]
233         or confess
234         'Cannot determine metaclass type for trait application . Meta isa '
235         . ref $meta;
236
237     # We can only call does_role() on Moose::Meta::Class objects, and
238     # we can only do that on $meta->meta() if it has already had at
239     # least one trait applied to it. By default $meta->meta() returns
240     # a Class::MOP::Class object (not a Moose::Meta::Class).
241     my @traits = grep {
242         $meta->meta()->can('does_role')
243             ? not $meta->meta()->does_role($_)
244             : 1
245         }
246         map { Moose::Util::resolve_metatrait_alias( $type => $_ ) } @$traits;
247
248     return unless @traits;
249
250     Moose::Util::apply_all_roles_with_method( $meta,
251         'apply_to_metaclass_instance', \@traits );
252 }
253
254 sub _get_caller {
255     # 1 extra level because it's called by import so there's a layer
256     # of indirection
257     my $offset = 1;
258
259     return
260           ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
261         : ( ref $_[1] && defined $_[1]->{into_level} )
262         ? caller( $offset + $_[1]->{into_level} )
263         : caller($offset);
264 }
265
266 sub _make_unimport_sub {
267     shift;
268     my $sources  = shift;
269     my $keywords = shift;
270
271     return sub {
272         my $class  = shift;
273         my $caller = scalar caller();
274         Moose::Exporter->_remove_keywords(
275             $caller,
276             [ $class, @{$sources} ],
277             $keywords
278         );
279     };
280 }
281
282 sub _remove_keywords {
283     shift;
284     my $package  = shift;
285     my $sources  = shift;
286     my $keywords = shift;
287
288     my %sources = map { $_ => 1 } @{$sources};
289
290     no strict 'refs';
291
292     # loop through the keywords ...
293     foreach my $name ( @{$keywords} ) {
294
295         # if we find one ...
296         if ( defined &{ $package . '::' . $name } ) {
297             my $keyword = \&{ $package . '::' . $name };
298
299             # make sure it is from us
300             my ($pkg_name) = Class::MOP::get_code_info($keyword);
301             next unless $sources{$pkg_name};
302
303             # and if it is from us, then undef the slot
304             delete ${ $package . '::' }{$name};
305         }
306     }
307 }
308
309 1;
310
311 __END__
312
313 =head1 NAME
314
315 Moose::Exporter - make an import() and unimport() just like Moose.pm
316
317 =head1 SYNOPSIS
318
319   package MyApp::Moose;
320
321   use strict;
322   use warnings;
323
324   use Moose ();
325   use Moose::Exporter;
326
327   Moose::Exporter->build_export_methods(
328       export         => [ 'sugar1', 'sugar2', \&Some::Random::thing ],
329       init_meta_args => { metaclass_class => 'MyApp::Meta::Class' ],
330   );
331
332   # then later ...
333   package MyApp::User;
334
335   use MyApp::Moose;
336
337   has 'name';
338   sugar1 'do your thing';
339   thing;
340
341   no MyApp::Moose;
342
343 =head1 DESCRIPTION
344
345 This module encapsulates the logic to export sugar functions like
346 C<Moose.pm>. It does this by building custom C<import> and C<unimport>
347 methods for your module, based on a spec your provide.
348
349 It also lets your "stack" Moose-alike modules so you can export
350 Moose's sugar as well as your own, along with sugar from any random
351 C<MooseX> module, as long as they all use C<Moose::Exporter>.
352
353 =head1 METHODS
354
355 This module provides exactly one public method:
356
357 =head2 Moose::Exporter->build_import_methods(...)
358
359 When you call this method, C<Moose::Exporter> build custom C<import>
360 and C<unimport> methods for your module. The import method will export
361 the functions you specify, and you can also tell it to export
362 functions exported by some other module (like C<Moose.pm>).
363
364 The C<unimport> method cleans the callers namespace of all the
365 exported functions.
366
367 This method accepts the following parameters:
368
369 =over 4
370
371 =item * with_caller => [ ... ]
372
373 This a list of function I<names only> to be exported wrapped and then
374 exported. The wrapper will pass the name of the calling package as the
375 first argument to the function. Many sugar functions need to know
376 their caller so they can get the calling package's metaclass object.
377
378 =item * as_is => [ ... ]
379
380 This a list of function names or sub references to be exported
381 as-is. You can identify a subroutine by reference, which is handy to
382 re-export some other module's functions directly by reference
383 (C<\&Some::Package::function>).
384
385 =item * also => $name or \@names
386
387 This is a list of modules which contain functions that the caller
388 wants to export. These modules must also use C<Moose::Exporter>. The
389 most common use case will be to export the functions from C<Moose.pm>.
390
391 C<Moose::Exporter> also makes sure all these functions get removed
392 when C<unimport> is called.
393
394 =back
395
396 =head1 IMPORTING AND init_meta
397
398 If you want to set an alternative base object class or metaclass
399 class, simply define an C<init_meta> method in your class. The
400 C<import> method that C<Moose::Exporter> generates for you will call
401 this method (if it exists). It will always pass the caller to this
402 method via the C<for_class> parameter.
403
404 Most of the time, your C<init_meta> method will probably just call C<<
405 Moose->init_meta >> to do the real work:
406
407   sub init_meta {
408       shift; # our class name
409       return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
410   }
411
412 =head1 AUTHOR
413
414 Dave Rolsky E<lt>autarch@urth.orgE<gt>
415
416 This is largely a reworking of code in Moose.pm originally written by
417 Stevan Little and others.
418
419 =head1 COPYRIGHT AND LICENSE
420
421 Copyright 2008 by Infinity Interactive, Inc.
422
423 L<http://www.iinteractive.com>
424
425 This library is free software; you can redistribute it and/or modify
426 it under the same terms as Perl itself.
427
428 =cut