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