8b993b3818ea034387f7b755cce2951d9cf2ef10
[gitmo/Moose.git] / lib / Moose / Exporter.pm
1 package Moose::Exporter;
2
3 use strict;
4 use warnings;
5
6 our $VERSION   = '0.73_02';
7 $VERSION = eval $VERSION;
8 our $AUTHORITY = 'cpan:STEVAN';
9
10 use Class::MOP;
11 use List::MoreUtils qw( first_index uniq );
12 use Moose::Util::MetaRole;
13 use Sub::Exporter;
14
15
16 my %EXPORT_SPEC;
17
18 sub setup_import_methods {
19     my ( $class, %args ) = @_;
20
21     my $exporting_package = $args{exporting_package} ||= caller();
22
23     my ( $import, $unimport ) = $class->build_import_methods(%args);
24
25     no strict 'refs';
26     *{ $exporting_package . '::import' }   = $import;
27     *{ $exporting_package . '::unimport' } = $unimport;
28 }
29
30 sub build_import_methods {
31     my ( $class, %args ) = @_;
32
33     my $exporting_package = $args{exporting_package} ||= caller();
34
35     $EXPORT_SPEC{$exporting_package} = \%args;
36
37     my @exports_from = $class->_follow_also( $exporting_package );
38
39     my $export_recorder = {};
40
41     my ( $exports, $is_removable )
42         = $class->_make_sub_exporter_params(
43         [ @exports_from, $exporting_package ], $export_recorder );
44
45     my $exporter = Sub::Exporter::build_exporter(
46         {
47             exports => $exports,
48             groups  => { default => [':all'] }
49         }
50     );
51
52     # $args{_export_to_main} exists for backwards compat, because
53     # Moose::Util::TypeConstraints did export to main (unlike Moose &
54     # Moose::Role).
55     my $import = $class->_make_import_sub( $exporting_package, $exporter,
56         \@exports_from, $args{_export_to_main} );
57
58     my $unimport = $class->_make_unimport_sub( $exporting_package, $exports,
59         $is_removable, $export_recorder );
60
61     return ( $import, $unimport )
62 }
63
64 {
65     my $seen = {};
66
67     sub _follow_also {
68         my $class             = shift;
69         my $exporting_package = shift;
70
71         local %$seen = ( $exporting_package => 1 );
72
73         return uniq( _follow_also_real($exporting_package) );
74     }
75
76     sub _follow_also_real {
77         my $exporting_package = shift;
78
79         die "Package in also ($exporting_package) does not seem to use Moose::Exporter"
80             unless exists $EXPORT_SPEC{$exporting_package};
81
82         my $also = $EXPORT_SPEC{$exporting_package}{also};
83
84         return unless defined $also;
85
86         my @also = ref $also ? @{$also} : $also;
87
88         for my $package (@also)
89         {
90             die "Circular reference in also parameter to Moose::Exporter between $exporting_package and $package"
91                 if $seen->{$package};
92
93             $seen->{$package} = 1;
94         }
95
96         return @also, map { _follow_also_real($_) } @also;
97     }
98 }
99
100 sub _make_sub_exporter_params {
101     my $class             = shift;
102     my $packages          = shift;
103     my $export_recorder   = shift;
104
105     my %exports;
106     my %is_removable;
107
108     for my $package ( @{$packages} ) {
109         my $args = $EXPORT_SPEC{$package}
110             or die "The $package package does not use Moose::Exporter\n";
111
112         for my $name ( @{ $args->{with_caller} } ) {
113             my $sub = do {
114                 no strict 'refs';
115                 \&{ $package . '::' . $name };
116             };
117
118             my $fq_name = $package . '::' . $name;
119
120             $exports{$name} = $class->_make_wrapped_sub(
121                 $fq_name,
122                 $sub,
123                 $export_recorder,
124             );
125
126             $is_removable{$name} = 1;
127         }
128
129         for my $name ( @{ $args->{as_is} } ) {
130             my $sub;
131
132             if ( ref $name ) {
133                 $sub  = $name;
134
135                 # Even though Moose re-exports things from Carp &
136                 # Scalar::Util, we don't want to remove those at
137                 # unimport time, because the importing package may
138                 # have imported them explicitly ala
139                 #
140                 # use Carp qw( confess );
141                 #
142                 # This is a hack. Since we can't know whether they
143                 # really want to keep these subs or not, we err on the
144                 # safe side and leave them in.
145                 my $coderef_pkg;
146                 ( $coderef_pkg, $name ) = Class::MOP::get_code_info($name);
147
148                 $is_removable{$name} = $coderef_pkg eq $package ? 1 : 0;
149             }
150             else {
151                 $sub = do {
152                     no strict 'refs';
153                     \&{ $package . '::' . $name };
154                 };
155
156                 $is_removable{$name} = 1;
157             }
158
159             $export_recorder->{$sub} = 1;
160
161             $exports{$name} = sub {$sub};
162         }
163     }
164
165     return ( \%exports, \%is_removable );
166 }
167
168 our $CALLER;
169
170 sub _make_wrapped_sub {
171     my $self            = shift;
172     my $fq_name         = shift;
173     my $sub             = shift;
174     my $export_recorder = shift;
175
176     # We need to set the package at import time, so that when
177     # package Foo imports has(), we capture "Foo" as the
178     # package. This lets other packages call Foo::has() and get
179     # the right package. This is done for backwards compatibility
180     # with existing production code, not because this is a good
181     # idea ;)
182     return sub {
183         my $caller = $CALLER;
184
185         my $wrapper = $self->_make_wrapper($caller, $sub, $fq_name);
186
187         my $sub = Class::MOP::subname($fq_name => $wrapper);
188
189         $export_recorder->{$sub} = 1;
190
191         return $sub;
192     };
193 }
194
195 sub _make_wrapper {
196     my $class   = shift;
197     my $caller  = shift;
198     my $sub     = shift;
199     my $fq_name = shift;
200
201     my $wrapper = sub { $sub->($caller, @_) };
202     if (my $proto = prototype $sub) {
203         # XXX - Perl's prototype sucks. Use & to make set_prototype
204         # ignore the fact that we're passing a "provate variable"
205         &Scalar::Util::set_prototype($wrapper, $proto);
206     }
207     return $wrapper;
208 }
209
210 sub _make_import_sub {
211     shift;
212     my $exporting_package = shift;
213     my $exporter          = shift;
214     my $exports_from      = shift;
215     my $export_to_main    = shift;
216
217     return sub {
218
219         # I think we could use Sub::Exporter's collector feature
220         # to do this, but that would be rather gross, since that
221         # feature isn't really designed to return a value to the
222         # caller of the exporter sub.
223         #
224         # Also, this makes sure we preserve backwards compat for
225         # _get_caller, so it always sees the arguments in the
226         # expected order.
227         my $traits;
228         ( $traits, @_ ) = _strip_traits(@_);
229
230         # Normally we could look at $_[0], but in some weird cases
231         # (involving goto &Moose::import), $_[0] ends as something
232         # else (like Squirrel).
233         my $class = $exporting_package;
234
235         $CALLER = _get_caller(@_);
236
237         # this works because both pragmas set $^H (see perldoc
238         # perlvar) which affects the current compilation -
239         # i.e. the file who use'd us - which is why we don't need
240         # to do anything special to make it affect that file
241         # rather than this one (which is already compiled)
242
243         strict->import;
244         warnings->import;
245
246         # we should never export to main
247         if ( $CALLER eq 'main' && !$export_to_main ) {
248             warn
249                 qq{$class does not export its sugar to the 'main' package.\n};
250             return;
251         }
252
253         my $did_init_meta;
254         for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
255             # init_meta can apply a role, which when loaded uses
256             # Moose::Exporter, which in turn sets $CALLER, so we need
257             # to protect against that.
258             local $CALLER = $CALLER;
259             $c->init_meta( for_class => $CALLER );
260             $did_init_meta = 1;
261         }
262
263         if ( $did_init_meta && @{$traits} ) {
264             # The traits will use Moose::Role, which in turn uses
265             # Moose::Exporter, which in turn sets $CALLER, so we need
266             # to protect against that.
267             local $CALLER = $CALLER;
268             _apply_meta_traits( $CALLER, $traits );
269         }
270         elsif ( @{$traits} ) {
271             require Moose;
272             Moose->throw_error(
273                 "Cannot provide traits when $class does not have an init_meta() method"
274             );
275         }
276
277         goto $exporter;
278     };
279 }
280
281
282 sub _strip_traits {
283     my $idx = first_index { $_ eq '-traits' } @_;
284
285     return ( [], @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
286
287     my $traits = $_[ $idx + 1 ];
288
289     splice @_, $idx, 2;
290
291     $traits = [ $traits ] unless ref $traits;
292
293     return ( $traits, @_ );
294 }
295
296 sub _apply_meta_traits {
297     my ( $class, $traits ) = @_;
298
299     return unless @{$traits};
300
301     my $meta = Class::MOP::class_of($class);
302
303     my $type = ( split /::/, ref $meta )[-1]
304         or Moose->throw_error(
305         'Cannot determine metaclass type for trait application . Meta isa '
306         . ref $meta );
307
308     my @resolved_traits
309         = map { Moose::Util::resolve_metatrait_alias( $type => $_ ) }
310         @$traits;
311
312     return unless @resolved_traits;
313
314     Moose::Util::MetaRole::apply_metaclass_roles(
315         for_class       => $class,
316         metaclass_roles => \@resolved_traits,
317     );
318 }
319
320 sub _get_caller {
321     # 1 extra level because it's called by import so there's a layer
322     # of indirection
323     my $offset = 1;
324
325     return
326           ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
327         : ( ref $_[1] && defined $_[1]->{into_level} )
328         ? caller( $offset + $_[1]->{into_level} )
329         : caller($offset);
330 }
331
332 sub _make_unimport_sub {
333     shift;
334     my $exporting_package = shift;
335     my $exports           = shift;
336     my $is_removable      = shift;
337     my $export_recorder   = shift;
338
339     return sub {
340         my $caller = scalar caller();
341         Moose::Exporter->_remove_keywords(
342             $caller,
343             [ keys %{$exports} ],
344             $is_removable,
345             $export_recorder,
346         );
347     };
348 }
349
350 sub _remove_keywords {
351     shift;
352     my $package          = shift;
353     my $keywords         = shift;
354     my $is_removable     = shift;
355     my $recorded_exports = shift;
356
357     no strict 'refs';
358
359     foreach my $name ( @{ $keywords } ) {
360         next unless $is_removable->{$name};
361
362         if ( defined &{ $package . '::' . $name } ) {
363             my $sub = \&{ $package . '::' . $name };
364
365             # make sure it is from us
366             next unless $recorded_exports->{$sub};
367
368             # and if it is from us, then undef the slot
369             delete ${ $package . '::' }{$name};
370         }
371     }
372 }
373
374 1;
375
376 __END__
377
378 =head1 NAME
379
380 Moose::Exporter - make an import() and unimport() just like Moose.pm
381
382 =head1 SYNOPSIS
383
384   package MyApp::Moose;
385
386   use strict;
387   use warnings;
388
389   use Moose ();
390   use Moose::Exporter;
391
392   Moose::Exporter->setup_import_methods(
393       with_caller => [ 'has_rw', 'sugar2' ],
394       as_is       => [ 'sugar3', \&Some::Random::thing ],
395       also        => 'Moose',
396   );
397
398   sub has_rw {
399       my ($caller, $name, %options) = @_;
400       Class::MOP::Class->initialize($caller)->add_attribute($name,
401           is => 'rw',
402           %options,
403       );
404   }
405
406   # then later ...
407   package MyApp::User;
408
409   use MyApp::Moose;
410
411   has 'name';
412   has_rw 'size';
413   thing;
414
415   no MyApp::Moose;
416
417 =head1 DESCRIPTION
418
419 This module encapsulates the logic to export sugar functions like
420 C<Moose.pm>. It does this by building custom C<import> and C<unimport>
421 methods for your module, based on a spec your provide.
422
423 It also lets your "stack" Moose-alike modules so you can export
424 Moose's sugar as well as your own, along with sugar from any random
425 C<MooseX> module, as long as they all use C<Moose::Exporter>.
426
427 =head1 METHODS
428
429 This module provides two public methods:
430
431 =over 4
432
433 =item  B<< Moose::Exporter->setup_import_methods(...) >>
434
435 When you call this method, C<Moose::Exporter> build custom C<import>
436 and C<unimport> methods for your module. The import method will export
437 the functions you specify, and you can also tell it to export
438 functions exported by some other module (like C<Moose.pm>).
439
440 The C<unimport> method cleans the callers namespace of all the
441 exported functions.
442
443 This method accepts the following parameters:
444
445 =over 8
446
447 =item * with_caller => [ ... ]
448
449 This a list of function I<names only> to be exported wrapped and then
450 exported. The wrapper will pass the name of the calling package as the
451 first argument to the function. Many sugar functions need to know
452 their caller so they can get the calling package's metaclass object.
453
454 =item * as_is => [ ... ]
455
456 This a list of function names or sub references to be exported
457 as-is. You can identify a subroutine by reference, which is handy to
458 re-export some other module's functions directly by reference
459 (C<\&Some::Package::function>).
460
461 If you do export some other packages function, this function will
462 never be removed by the C<unimport> method. The reason for this is we
463 cannot know if the caller I<also> explicitly imported the sub
464 themselves, and therefore wants to keep it.
465
466 =item * also => $name or \@names
467
468 This is a list of modules which contain functions that the caller
469 wants to export. These modules must also use C<Moose::Exporter>. The
470 most common use case will be to export the functions from C<Moose.pm>.
471 Functions specified by C<with_caller> or C<as_is> take precedence over
472 functions exported by modules specified by C<also>, so that a module
473 can selectively override functions exported by another module.
474
475 C<Moose::Exporter> also makes sure all these functions get removed
476 when C<unimport> is called.
477
478 =back
479
480 =item B<< Moose::Exporter->build_import_methods(...) >>
481
482 Returns two code refs, one for import and one for unimport.
483
484 Used by C<setup_import_methods>.
485
486 =back
487
488 =head1 IMPORTING AND init_meta
489
490 If you want to set an alternative base object class or metaclass
491 class, simply define an C<init_meta> method in your class. The
492 C<import> method that C<Moose::Exporter> generates for you will call
493 this method (if it exists). It will always pass the caller to this
494 method via the C<for_class> parameter.
495
496 Most of the time, your C<init_meta> method will probably just call C<<
497 Moose->init_meta >> to do the real work:
498
499   sub init_meta {
500       shift; # our class name
501       return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
502   }
503
504 =head1 METACLASS TRAITS
505
506 The C<import> method generated by C<Moose::Exporter> will allow the
507 user of your module to specify metaclass traits in a C<-traits>
508 parameter passed as part of the import:
509
510   use Moose -traits => 'My::Meta::Trait';
511
512   use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
513
514 These traits will be applied to the caller's metaclass
515 instance. Providing traits for an exporting class that does not create
516 a metaclass for the caller is an error.
517
518 =head1 AUTHOR
519
520 Dave Rolsky E<lt>autarch@urth.orgE<gt>
521
522 This is largely a reworking of code in Moose.pm originally written by
523 Stevan Little and others.
524
525 =head1 COPYRIGHT AND LICENSE
526
527 Copyright 2009 by Infinity Interactive, Inc.
528
529 L<http://www.iinteractive.com>
530
531 This library is free software; you can redistribute it and/or modify
532 it under the same terms as Perl itself.
533
534 =cut