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