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