26eaa11c870ae987353f4d8808ccd2cc5d08e003
[gitmo/Moose.git] / lib / Moose / Exporter.pm
1 package Moose::Exporter;
2
3 use strict;
4 use warnings;
5
6 our $VERSION   = '0.89_01';
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 0.980;
14 use Sub::Name qw(subname);
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     $class->build_import_methods(
24         %args,
25         install => [qw(import unimport init_meta)]
26     );
27 }
28
29 sub build_import_methods {
30     my ( $class, %args ) = @_;
31
32     my $exporting_package = $args{exporting_package} ||= caller();
33
34     $EXPORT_SPEC{$exporting_package} = \%args;
35
36     my @exports_from = $class->_follow_also( $exporting_package );
37
38     my $export_recorder = {};
39
40     my ( $exports, $is_removable )
41         = $class->_make_sub_exporter_params(
42         [ @exports_from, $exporting_package ], $export_recorder );
43
44     my $exporter = Sub::Exporter::build_exporter(
45         {
46             exports => $exports,
47             groups  => { default => [':all'] }
48         }
49     );
50
51     my %methods;
52     # $args{_export_to_main} exists for backwards compat, because
53     # Moose::Util::TypeConstraints did export to main (unlike Moose &
54     # Moose::Role).
55     $methods{import} = $class->_make_import_sub( $exporting_package,
56         $exporter, \@exports_from, $args{_export_to_main} );
57
58     $methods{unimport} = $class->_make_unimport_sub( $exporting_package,
59         $exports, $is_removable, $export_recorder );
60
61     $methods{init_meta} = $class->_make_init_meta( $exporting_package,
62         \%args );
63
64     my $package = Class::MOP::Package->initialize($exporting_package);
65     for my $to_install ( @{ $args{install} || [] } ) {
66         my $symbol = '&' . $to_install;
67         next
68             unless $methods{$to_install}
69                 && !$package->has_package_symbol($symbol);
70         $package->add_package_symbol( $symbol, $methods{$to_install} );
71     }
72
73     return ( $methods{import}, $methods{unimport}, $methods{init_meta} )
74 }
75
76 {
77     my $seen = {};
78
79     sub _follow_also {
80         my $class             = shift;
81         my $exporting_package = shift;
82
83         local %$seen = ( $exporting_package => 1 );
84
85         return uniq( _follow_also_real($exporting_package) );
86     }
87
88     sub _follow_also_real {
89         my $exporting_package = shift;
90
91         if (!exists $EXPORT_SPEC{$exporting_package}) {
92             my $loaded = Class::MOP::is_class_loaded($exporting_package);
93
94             die "Package in also ($exporting_package) does not seem to "
95               . "use Moose::Exporter"
96               . ($loaded ? "" : " (is it loaded?)");
97         }
98
99         my $also = $EXPORT_SPEC{$exporting_package}{also};
100
101         return unless defined $also;
102
103         my @also = ref $also ? @{$also} : $also;
104
105         for my $package (@also)
106         {
107             die "Circular reference in also parameter to Moose::Exporter between $exporting_package and $package"
108                 if $seen->{$package};
109
110             $seen->{$package} = 1;
111         }
112
113         return @also, map { _follow_also_real($_) } @also;
114     }
115 }
116
117 sub _make_sub_exporter_params {
118     my $class             = shift;
119     my $packages          = shift;
120     my $export_recorder   = shift;
121
122     my %exports;
123     my %is_removable;
124
125     for my $package ( @{$packages} ) {
126         my $args = $EXPORT_SPEC{$package}
127             or die "The $package package does not use Moose::Exporter\n";
128
129         for my $name ( @{ $args->{with_meta} } ) {
130             my $sub = do {
131                 no strict 'refs';
132                 \&{ $package . '::' . $name };
133             };
134
135             if ( !defined(&$sub) ) {
136                 Carp::cluck
137                     "Trying to export undefined sub ${package}::${name}";
138                 next;
139             }
140
141             my $fq_name = $package . '::' . $name;
142
143             $exports{$name} = $class->_make_wrapped_sub_with_meta(
144                 $fq_name,
145                 $sub,
146                 $export_recorder,
147             );
148
149             $is_removable{$name} = 1;
150         }
151
152         for my $name ( @{ $args->{with_caller} } ) {
153             my $sub = do {
154                 no strict 'refs';
155                 \&{ $package . '::' . $name };
156             };
157
158             if ( !defined(&$sub) ) {
159                 Carp::cluck
160                     "Trying to export undefined sub ${package}::${name}";
161                 next;
162             }
163
164             my $fq_name = $package . '::' . $name;
165
166             $exports{$name} = $class->_make_wrapped_sub(
167                 $fq_name,
168                 $sub,
169                 $export_recorder,
170             );
171
172             $is_removable{$name} = 1;
173         }
174
175         for my $name ( @{ $args->{as_is} } ) {
176             my ($sub, $coderef_name);
177
178             if ( ref $name ) {
179                 $sub  = $name;
180
181                 # Even though Moose re-exports things from Carp &
182                 # Scalar::Util, we don't want to remove those at
183                 # unimport time, because the importing package may
184                 # have imported them explicitly ala
185                 #
186                 # use Carp qw( confess );
187                 #
188                 # This is a hack. Since we can't know whether they
189                 # really want to keep these subs or not, we err on the
190                 # safe side and leave them in.
191                 my $coderef_pkg;
192                 ( $coderef_pkg, $coderef_name )
193                     = Class::MOP::get_code_info($name);
194
195                 $is_removable{$coderef_name} = $coderef_pkg eq $package ? 1 : 0;
196             }
197             else {
198                 $sub = do {
199                     no strict 'refs';
200                     \&{ $package . '::' . $name };
201                 };
202
203                 if ( !defined(&$sub) ) {
204                     Carp::cluck
205                         "Trying to export undefined sub ${package}::${name}";
206                     next;
207                 }
208
209                 $is_removable{$name} = 1;
210                 $coderef_name = $name;
211             }
212
213             $export_recorder->{$sub} = 1;
214
215             $exports{$coderef_name} = sub {$sub};
216         }
217     }
218
219     return ( \%exports, \%is_removable );
220 }
221
222 our $CALLER;
223
224 sub _make_wrapped_sub {
225     my $self            = shift;
226     my $fq_name         = shift;
227     my $sub             = shift;
228     my $export_recorder = shift;
229
230     # We need to set the package at import time, so that when
231     # package Foo imports has(), we capture "Foo" as the
232     # package. This lets other packages call Foo::has() and get
233     # the right package. This is done for backwards compatibility
234     # with existing production code, not because this is a good
235     # idea ;)
236     return sub {
237         my $caller = $CALLER;
238
239         my $wrapper = $self->_curry_wrapper($sub, $fq_name, $caller);
240
241         my $sub = subname($fq_name => $wrapper);
242
243         $export_recorder->{$sub} = 1;
244
245         return $sub;
246     };
247 }
248
249 sub _make_wrapped_sub_with_meta {
250     my $self            = shift;
251     my $fq_name         = shift;
252     my $sub             = shift;
253     my $export_recorder = shift;
254
255     return sub {
256         my $caller = $CALLER;
257
258         my $wrapper = $self->_late_curry_wrapper($sub, $fq_name,
259             sub { Class::MOP::class_of(shift) } => $caller);
260
261         my $sub = subname($fq_name => $wrapper);
262
263         $export_recorder->{$sub} = 1;
264
265         return $sub;
266     };
267 }
268
269 sub _make_wrapped_group {
270     my $class           = shift;
271     my $package         = shift; # package calling use Moose::Exporter
272     my $sub             = shift;
273     my $export_recorder = shift;
274     my $keywords        = shift;
275     my $is_removable    = shift;
276
277     return sub {
278         my $caller = $CALLER; # package calling use PackageUsingMooseExporter -group => {args}
279
280         # there are plenty of ways to deal with telling the code which
281         # package it lives in. the last arg (collector hashref) is
282         # otherwise unused, so we'll stick the original package in
283         # there and act like 'with_caller' by putting the calling
284         # package name as the first arg
285         $_[0] = $caller;
286         $_[3]{from} = $package;
287
288         my $named_code = $sub->(@_);
289         $named_code ||= { };
290
291         # send invalid return value error up to Sub::Exporter
292         unless (ref $named_code eq 'HASH') {
293             return $named_code;
294         }
295
296         for my $name (keys %$named_code) {
297             my $code = $named_code->{$name};
298
299             my $fq_name = $package . '::' . $name;
300             my $wrapper = $class->_curry_wrapper(
301                 $code,
302                 $fq_name,
303                 $caller
304             );
305
306             my $sub = subname( $fq_name => $wrapper );
307             $named_code->{$name} = $sub;
308
309             # mark each coderef as ours
310             $keywords->{$name} = 1;
311             $is_removable->{$name} = 1;
312             $export_recorder->{$sub} = 1;
313         }
314
315         return $named_code;
316     };
317 }
318
319 sub _curry_wrapper {
320     my $class   = shift;
321     my $sub     = shift;
322     my $fq_name = shift;
323     my @extra   = @_;
324
325     my $wrapper = sub { $sub->(@extra, @_) };
326     if (my $proto = prototype $sub) {
327         # XXX - Perl's prototype sucks. Use & to make set_prototype
328         # ignore the fact that we're passing "private variables"
329         &Scalar::Util::set_prototype($wrapper, $proto);
330     }
331     return $wrapper;
332 }
333
334 sub _late_curry_wrapper {
335     my $class   = shift;
336     my $sub     = shift;
337     my $fq_name = shift;
338     my $extra   = shift;
339     my @ex_args = @_;
340
341     my $wrapper = sub {
342         # resolve curried arguments at runtime via this closure
343         my @curry = ( $extra->( @ex_args ) );
344         return $sub->(@curry, @_);
345     };
346
347     if (my $proto = prototype $sub) {
348         # XXX - Perl's prototype sucks. Use & to make set_prototype
349         # ignore the fact that we're passing "private variables"
350         &Scalar::Util::set_prototype($wrapper, $proto);
351     }
352     return $wrapper;
353 }
354
355 sub _make_import_sub {
356     shift;
357     my $exporting_package = shift;
358     my $exporter          = shift;
359     my $exports_from      = shift;
360     my $export_to_main    = shift;
361
362     return sub {
363
364         # I think we could use Sub::Exporter's collector feature
365         # to do this, but that would be rather gross, since that
366         # feature isn't really designed to return a value to the
367         # caller of the exporter sub.
368         #
369         # Also, this makes sure we preserve backwards compat for
370         # _get_caller, so it always sees the arguments in the
371         # expected order.
372         my $traits;
373         ( $traits, @_ ) = _strip_traits(@_);
374
375         my $metaclass;
376         ( $metaclass, @_ ) = _strip_metaclass(@_);
377         $metaclass = Moose::Util::resolve_metaclass_alias(
378             'Class' => $metaclass
379         ) if defined $metaclass && length $metaclass;
380
381         # Normally we could look at $_[0], but in some weird cases
382         # (involving goto &Moose::import), $_[0] ends as something
383         # else (like Squirrel).
384         my $class = $exporting_package;
385
386         $CALLER = _get_caller(@_);
387
388         # this works because both pragmas set $^H (see perldoc
389         # perlvar) which affects the current compilation -
390         # i.e. the file who use'd us - which is why we don't need
391         # to do anything special to make it affect that file
392         # rather than this one (which is already compiled)
393
394         strict->import;
395         warnings->import;
396
397         # we should never export to main
398         if ( $CALLER eq 'main' && !$export_to_main ) {
399             warn
400                 qq{$class does not export its sugar to the 'main' package.\n};
401             return;
402         }
403
404         my $did_init_meta;
405         for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
406             # init_meta can apply a role, which when loaded uses
407             # Moose::Exporter, which in turn sets $CALLER, so we need
408             # to protect against that.
409             local $CALLER = $CALLER;
410             $c->init_meta( for_class => $CALLER, metaclass => $metaclass );
411             $did_init_meta = 1;
412         }
413
414         if ( $did_init_meta && @{$traits} ) {
415             # The traits will use Moose::Role, which in turn uses
416             # Moose::Exporter, which in turn sets $CALLER, so we need
417             # to protect against that.
418             local $CALLER = $CALLER;
419             _apply_meta_traits( $CALLER, $traits );
420         }
421         elsif ( @{$traits} ) {
422             require Moose;
423             Moose->throw_error(
424                 "Cannot provide traits when $class does not have an init_meta() method"
425             );
426         }
427
428         goto $exporter;
429     };
430 }
431
432
433 sub _strip_traits {
434     my $idx = first_index { $_ eq '-traits' } @_;
435
436     return ( [], @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
437
438     my $traits = $_[ $idx + 1 ];
439
440     splice @_, $idx, 2;
441
442     $traits = [ $traits ] unless ref $traits;
443
444     return ( $traits, @_ );
445 }
446
447 sub _strip_metaclass {
448     my $idx = first_index { $_ eq '-metaclass' } @_;
449
450     return ( undef, @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
451
452     my $metaclass = $_[ $idx + 1 ];
453
454     splice @_, $idx, 2;
455
456     return ( $metaclass, @_ );
457 }
458
459 sub _apply_meta_traits {
460     my ( $class, $traits ) = @_;
461
462     return unless @{$traits};
463
464     my $meta = Class::MOP::class_of($class);
465
466     my $type = ( split /::/, ref $meta )[-1]
467         or Moose->throw_error(
468         'Cannot determine metaclass type for trait application . Meta isa '
469         . ref $meta );
470
471     my @resolved_traits
472         = map {
473             ref $_ ? $_ : Moose::Util::resolve_metatrait_alias( $type => $_ )
474         }
475         @$traits;
476
477     return unless @resolved_traits;
478
479     Moose::Util::MetaRole::apply_metaclass_roles(
480         for_class       => $class,
481         metaclass_roles => \@resolved_traits,
482     );
483 }
484
485 sub _get_caller {
486     # 1 extra level because it's called by import so there's a layer
487     # of indirection
488     my $offset = 1;
489
490     return
491           ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
492         : ( ref $_[1] && defined $_[1]->{into_level} )
493         ? caller( $offset + $_[1]->{into_level} )
494         : caller($offset);
495 }
496
497 sub _make_unimport_sub {
498     shift;
499     my $exporting_package = shift;
500     my $exports           = shift;
501     my $is_removable      = shift;
502     my $export_recorder   = shift;
503
504     return sub {
505         my $caller = scalar caller();
506         Moose::Exporter->_remove_keywords(
507             $caller,
508             [ keys %{$exports} ],
509             $is_removable,
510             $export_recorder,
511         );
512     };
513 }
514
515 sub _remove_keywords {
516     shift;
517     my $package          = shift;
518     my $keywords         = shift;
519     my $is_removable     = shift;
520     my $recorded_exports = shift;
521
522     no strict 'refs';
523
524     foreach my $name ( @{ $keywords } ) {
525         next unless $is_removable->{$name};
526
527         if ( defined &{ $package . '::' . $name } ) {
528             my $sub = \&{ $package . '::' . $name };
529
530             # make sure it is from us
531             next unless $recorded_exports->{$sub};
532
533             # and if it is from us, then undef the slot
534             delete ${ $package . '::' }{$name};
535         }
536     }
537 }
538
539 sub _make_init_meta {
540     shift;
541     my $class = shift;
542     my $args  = shift;
543
544     my %metaclass_roles;
545     for my $role (
546         map {"${_}_roles"}
547         qw(metaclass
548         attribute_metaclass
549         method_metaclass
550         wrapped_method_metaclass
551         instance_metaclass
552         constructor_class
553         destructor_class
554         error_class
555         application_to_class_class
556         application_to_role_class
557         application_to_instance_class)
558         ) {
559         $metaclass_roles{$role} = $args->{$role} if exists $args->{$role};
560     }
561
562     my %base_class_roles;
563     %base_class_roles = ( roles => $args->{base_class_roles} )
564         if exists $args->{base_class_roles};
565
566     return unless %metaclass_roles || %base_class_roles;
567
568     return sub {
569         shift;
570         my %options = @_;
571
572         return unless Class::MOP::class_of( $options{for_class} );
573
574         Moose::Util::MetaRole::apply_metaclass_roles(
575             for_class => $options{for_class},
576             %metaclass_roles,
577         );
578
579         Moose::Util::MetaRole::apply_base_class_roles(
580             for_class => $options{for_class},
581             %base_class_roles,
582             )
583             if Class::MOP::class_of( $options{for_class} )
584                 ->isa('Moose::Meta::Class');
585
586         return Class::MOP::class_of( $options{for_class} );
587     };
588 }
589
590 sub import {
591     strict->import;
592     warnings->import;
593 }
594
595 1;
596
597 __END__
598
599 =head1 NAME
600
601 Moose::Exporter - make an import() and unimport() just like Moose.pm
602
603 =head1 SYNOPSIS
604
605   package MyApp::Moose;
606
607   use Moose ();
608   use Moose::Exporter;
609
610   Moose::Exporter->setup_import_methods(
611       with_meta => [ 'has_rw', 'sugar2' ],
612       as_is     => [ 'sugar3', \&Some::Random::thing ],
613       also      => 'Moose',
614   );
615
616   sub has_rw {
617       my ( $meta, $name, %options ) = @_;
618       $meta->add_attribute(
619           $name,
620           is => 'rw',
621           %options,
622       );
623   }
624
625   # then later ...
626   package MyApp::User;
627
628   use MyApp::Moose;
629
630   has 'name';
631   has_rw 'size';
632   thing;
633
634   no MyApp::Moose;
635
636 =head1 DESCRIPTION
637
638 This module encapsulates the exporting of sugar functions in a
639 C<Moose.pm>-like manner. It does this by building custom C<import>,
640 C<unimport>, and C<init_meta> methods for your module, based on a spec you
641 provide.
642
643 It also lets you "stack" Moose-alike modules so you can export Moose's sugar
644 as well as your own, along with sugar from any random C<MooseX> module, as
645 long as they all use C<Moose::Exporter>. This feature exists to let you bundle
646 a set of MooseX modules into a policy module that developers can use directly
647 instead of using Moose itself.
648
649 To simplify writing exporter modules, C<Moose::Exporter> also imports
650 C<strict> and C<warnings> into your exporter module, as well as into
651 modules that use it.
652
653 =head1 METHODS
654
655 This module provides two public methods:
656
657 =over 4
658
659 =item  B<< Moose::Exporter->setup_import_methods(...) >>
660
661 When you call this method, C<Moose::Exporter> builds custom C<import>,
662 C<unimport>, and C<init_meta> methods for your module. The C<import> method
663 will export the functions you specify, and can also re-export functions
664 exported by some other module (like C<Moose.pm>).
665
666 The C<unimport> method cleans the caller's namespace of all the exported
667 functions.
668
669 If you pass any parameters for L<Moose::Util::MetaRole>, this method will
670 generate an C<init_meta> for you as well (see below for details). This
671 C<init_meta> will call C<Moose::Util::MetaRole::apply_metaclass_roles> and
672 C<Moose::Util::MetaRole::apply_base_class_roles> as needed.
673
674 Note that if any of these methods already exist, they will not be
675 overridden, you will have to use C<build_import_methods> to get the
676 coderef that would be installed.
677
678 This method accepts the following parameters:
679
680 =over 8
681
682 =item * with_meta => [ ... ]
683
684 This list of function I<names only> will be wrapped and then exported. The
685 wrapper will pass the metaclass object for the caller as its first argument.
686
687 Many sugar functions will need to use this metaclass object to do something to
688 the calling package.
689
690 =item * as_is => [ ... ]
691
692 This list of function names or sub references will be exported as-is. You can
693 identify a subroutine by reference, which is handy to re-export some other
694 module's functions directly by reference (C<\&Some::Package::function>).
695
696 If you do export some other package's function, this function will never be
697 removed by the C<unimport> method. The reason for this is we cannot know if
698 the caller I<also> explicitly imported the sub themselves, and therefore wants
699 to keep it.
700
701 =item * also => $name or \@names
702
703 This is a list of modules which contain functions that the caller
704 wants to export. These modules must also use C<Moose::Exporter>. The
705 most common use case will be to export the functions from C<Moose.pm>.
706 Functions specified by C<with_meta> or C<as_is> take precedence over
707 functions exported by modules specified by C<also>, so that a module
708 can selectively override functions exported by another module.
709
710 C<Moose::Exporter> also makes sure all these functions get removed
711 when C<unimport> is called.
712
713 =back
714
715 Any of the C<*_roles> options for
716 C<Moose::Util::MetaRole::apply_metaclass_roles> and
717 C<Moose::Util::MetaRole::base_class_roles> are also acceptable.
718
719 =item B<< Moose::Exporter->build_import_methods(...) >>
720
721 Returns two or three code refs, one for C<import>, one for
722 C<unimport>, and optionally one for C<init_meta>, if the appropriate
723 options are passed in.
724
725 Accepts the additional C<install> option, which accepts an arrayref of method
726 names to install into your exporting package. The valid options are C<import>,
727 C<unimport>, and C<init_meta>. Calling C<setup_import_methods> is equivalent
728 to calling C<build_import_methods> with C<< install => [qw(import unimport
729 init_meta)] >> except that it doesn't also return the methods.
730
731 Used by C<setup_import_methods>.
732
733 =back
734
735 =head1 IMPORTING AND init_meta
736
737 If you want to set an alternative base object class or metaclass class, see
738 above for details on how this module can call L<Moose::Util::MetaRole> for
739 you.
740
741 If you want to do something that is not supported by this module, simply
742 define an C<init_meta> method in your class. The C<import> method that
743 C<Moose::Exporter> generates for you will call this method (if it exists). It
744 will always pass the caller to this method via the C<for_class> parameter.
745
746 Most of the time, your C<init_meta> method will probably just call C<<
747 Moose->init_meta >> to do the real work:
748
749   sub init_meta {
750       shift; # our class name
751       return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
752   }
753
754 Keep in mind that C<build_import_methods> will return an C<init_meta>
755 method for you, which you can also call from within your custom
756 C<init_meta>:
757
758   my ( $import, $unimport, $init_meta ) =
759       Moose::Exporter->build_import_methods( ... );
760
761   sub import {
762      my $class = shift;
763
764      ...
765
766      $class->$import(...);
767
768      ...
769   }
770
771   sub unimport { goto &$unimport }
772
773   sub init_meta {
774      my $class = shift;
775
776      ...
777
778      $class->$init_meta(...);
779
780      ...
781   }
782
783 =head1 METACLASS TRAITS
784
785 The C<import> method generated by C<Moose::Exporter> will allow the
786 user of your module to specify metaclass traits in a C<-traits>
787 parameter passed as part of the import:
788
789   use Moose -traits => 'My::Meta::Trait';
790
791   use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
792
793 These traits will be applied to the caller's metaclass
794 instance. Providing traits for an exporting class that does not create
795 a metaclass for the caller is an error.
796
797 =head1 AUTHOR
798
799 Dave Rolsky E<lt>autarch@urth.orgE<gt>
800
801 This is largely a reworking of code in Moose.pm originally written by
802 Stevan Little and others.
803
804 =head1 COPYRIGHT AND LICENSE
805
806 Copyright 2009 by Infinity Interactive, Inc.
807
808 L<http://www.iinteractive.com>
809
810 This library is free software; you can redistribute it and/or modify
811 it under the same terms as Perl itself.
812
813 =cut