allow exporting to main
[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
305     return sub {
306
307         # I think we could use Sub::Exporter's collector feature
308         # to do this, but that would be rather gross, since that
309         # feature isn't really designed to return a value to the
310         # caller of the exporter sub.
311         #
312         # Also, this makes sure we preserve backwards compat for
313         # _get_caller, so it always sees the arguments in the
314         # expected order.
315         my $traits;
316         ( $traits, @_ ) = _strip_traits(@_);
317
318         my $metaclass;
319         ( $metaclass, @_ ) = _strip_metaclass(@_);
320         $metaclass = Moose::Util::resolve_metaclass_alias(
321             'Class' => $metaclass
322         ) if defined $metaclass && length $metaclass;
323
324         # Normally we could look at $_[0], but in some weird cases
325         # (involving goto &Moose::import), $_[0] ends as something
326         # else (like Squirrel).
327         my $class = $exporting_package;
328
329         $CALLER = _get_caller(@_);
330
331         # this works because both pragmas set $^H (see perldoc
332         # perlvar) which affects the current compilation -
333         # i.e. the file who use'd us - which is why we don't need
334         # to do anything special to make it affect that file
335         # rather than this one (which is already compiled)
336
337         strict->import;
338         warnings->import;
339
340         my $did_init_meta;
341         for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
342             # init_meta can apply a role, which when loaded uses
343             # Moose::Exporter, which in turn sets $CALLER, so we need
344             # to protect against that.
345             local $CALLER = $CALLER;
346             $c->init_meta( for_class => $CALLER, metaclass => $metaclass );
347             $did_init_meta = 1;
348         }
349
350         if ( $did_init_meta && @{$traits} ) {
351             # The traits will use Moose::Role, which in turn uses
352             # Moose::Exporter, which in turn sets $CALLER, so we need
353             # to protect against that.
354             local $CALLER = $CALLER;
355             _apply_meta_traits( $CALLER, $traits );
356         }
357         elsif ( @{$traits} ) {
358             require Moose;
359             Moose->throw_error(
360                 "Cannot provide traits when $class does not have an init_meta() method"
361             );
362         }
363
364         goto $exporter;
365     };
366 }
367
368
369 sub _strip_traits {
370     my $idx = first_index { $_ eq '-traits' } @_;
371
372     return ( [], @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
373
374     my $traits = $_[ $idx + 1 ];
375
376     splice @_, $idx, 2;
377
378     $traits = [ $traits ] unless ref $traits;
379
380     return ( $traits, @_ );
381 }
382
383 sub _strip_metaclass {
384     my $idx = first_index { $_ eq '-metaclass' } @_;
385
386     return ( undef, @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
387
388     my $metaclass = $_[ $idx + 1 ];
389
390     splice @_, $idx, 2;
391
392     return ( $metaclass, @_ );
393 }
394
395 sub _apply_meta_traits {
396     my ( $class, $traits ) = @_;
397
398     return unless @{$traits};
399
400     my $meta = Class::MOP::class_of($class);
401
402     my $type = ( split /::/, ref $meta )[-1]
403         or Moose->throw_error(
404         'Cannot determine metaclass type for trait application . Meta isa '
405         . ref $meta );
406
407     my @resolved_traits
408         = map {
409             ref $_ ? $_ : Moose::Util::resolve_metatrait_alias( $type => $_ )
410         }
411         @$traits;
412
413     return unless @resolved_traits;
414
415     Moose::Util::MetaRole::apply_metaclass_roles(
416         for_class       => $class,
417         metaclass_roles => \@resolved_traits,
418     );
419 }
420
421 sub _get_caller {
422     # 1 extra level because it's called by import so there's a layer
423     # of indirection
424     my $offset = 1;
425
426     return
427           ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
428         : ( ref $_[1] && defined $_[1]->{into_level} )
429         ? caller( $offset + $_[1]->{into_level} )
430         : caller($offset);
431 }
432
433 sub _make_unimport_sub {
434     shift;
435     my $exporting_package = shift;
436     my $exports           = shift;
437     my $is_removable      = shift;
438     my $export_recorder   = shift;
439
440     return sub {
441         my $caller = scalar caller();
442         Moose::Exporter->_remove_keywords(
443             $caller,
444             [ keys %{$exports} ],
445             $is_removable,
446             $export_recorder,
447         );
448     };
449 }
450
451 sub _remove_keywords {
452     shift;
453     my $package          = shift;
454     my $keywords         = shift;
455     my $is_removable     = shift;
456     my $recorded_exports = shift;
457
458     no strict 'refs';
459
460     foreach my $name ( @{ $keywords } ) {
461         next unless $is_removable->{$name};
462
463         if ( defined &{ $package . '::' . $name } ) {
464             my $sub = \&{ $package . '::' . $name };
465
466             # make sure it is from us
467             next unless $recorded_exports->{$sub};
468
469             # and if it is from us, then undef the slot
470             delete ${ $package . '::' }{$name};
471         }
472     }
473 }
474
475 sub _make_init_meta {
476     shift;
477     my $class = shift;
478     my $args  = shift;
479
480     my %metaclass_roles;
481     for my $role (
482         map {"${_}_roles"}
483         qw(metaclass
484         attribute_metaclass
485         method_metaclass
486         wrapped_method_metaclass
487         instance_metaclass
488         constructor_class
489         destructor_class
490         error_class
491         application_to_class_class
492         application_to_role_class
493         application_to_instance_class)
494         ) {
495         $metaclass_roles{$role} = $args->{$role} if exists $args->{$role};
496     }
497
498     my %base_class_roles;
499     %base_class_roles = ( roles => $args->{base_class_roles} )
500         if exists $args->{base_class_roles};
501
502     return unless %metaclass_roles || %base_class_roles;
503
504     return sub {
505         shift;
506         my %options = @_;
507
508         return unless Class::MOP::class_of( $options{for_class} );
509
510         Moose::Util::MetaRole::apply_metaclass_roles(
511             for_class => $options{for_class},
512             %metaclass_roles,
513         );
514
515         Moose::Util::MetaRole::apply_base_class_roles(
516             for_class => $options{for_class},
517             %base_class_roles,
518             )
519             if Class::MOP::class_of( $options{for_class} )
520                 ->isa('Moose::Meta::Class');
521
522         return Class::MOP::class_of( $options{for_class} );
523     };
524 }
525
526 sub import {
527     strict->import;
528     warnings->import;
529 }
530
531 1;
532
533 __END__
534
535 =head1 NAME
536
537 Moose::Exporter - make an import() and unimport() just like Moose.pm
538
539 =head1 SYNOPSIS
540
541   package MyApp::Moose;
542
543   use Moose ();
544   use Moose::Exporter;
545
546   Moose::Exporter->setup_import_methods(
547       with_meta => [ 'has_rw', 'sugar2' ],
548       as_is     => [ 'sugar3', \&Some::Random::thing ],
549       also      => 'Moose',
550   );
551
552   sub has_rw {
553       my ( $meta, $name, %options ) = @_;
554       $meta->add_attribute(
555           $name,
556           is => 'rw',
557           %options,
558       );
559   }
560
561   # then later ...
562   package MyApp::User;
563
564   use MyApp::Moose;
565
566   has 'name';
567   has_rw 'size';
568   thing;
569
570   no MyApp::Moose;
571
572 =head1 DESCRIPTION
573
574 This module encapsulates the exporting of sugar functions in a
575 C<Moose.pm>-like manner. It does this by building custom C<import>,
576 C<unimport>, and C<init_meta> methods for your module, based on a spec you
577 provide.
578
579 It also lets you "stack" Moose-alike modules so you can export Moose's sugar
580 as well as your own, along with sugar from any random C<MooseX> module, as
581 long as they all use C<Moose::Exporter>. This feature exists to let you bundle
582 a set of MooseX modules into a policy module that developers can use directly
583 instead of using Moose itself.
584
585 To simplify writing exporter modules, C<Moose::Exporter> also imports
586 C<strict> and C<warnings> into your exporter module, as well as into
587 modules that use it.
588
589 =head1 METHODS
590
591 This module provides two public methods:
592
593 =over 4
594
595 =item  B<< Moose::Exporter->setup_import_methods(...) >>
596
597 When you call this method, C<Moose::Exporter> builds custom C<import>,
598 C<unimport>, and C<init_meta> methods for your module. The C<import> method
599 will export the functions you specify, and can also re-export functions
600 exported by some other module (like C<Moose.pm>).
601
602 The C<unimport> method cleans the caller's namespace of all the exported
603 functions.
604
605 If you pass any parameters for L<Moose::Util::MetaRole>, this method will
606 generate an C<init_meta> for you as well (see below for details). This
607 C<init_meta> will call C<Moose::Util::MetaRole::apply_metaclass_roles> and
608 C<Moose::Util::MetaRole::apply_base_class_roles> as needed.
609
610 Note that if any of these methods already exist, they will not be
611 overridden, you will have to use C<build_import_methods> to get the
612 coderef that would be installed.
613
614 This method accepts the following parameters:
615
616 =over 8
617
618 =item * with_meta => [ ... ]
619
620 This list of function I<names only> will be wrapped and then exported. The
621 wrapper will pass the metaclass object for the caller as its first argument.
622
623 Many sugar functions will need to use this metaclass object to do something to
624 the calling package.
625
626 =item * as_is => [ ... ]
627
628 This list of function names or sub references will be exported as-is. You can
629 identify a subroutine by reference, which is handy to re-export some other
630 module's functions directly by reference (C<\&Some::Package::function>).
631
632 If you do export some other package's function, this function will never be
633 removed by the C<unimport> method. The reason for this is we cannot know if
634 the caller I<also> explicitly imported the sub themselves, and therefore wants
635 to keep it.
636
637 =item * also => $name or \@names
638
639 This is a list of modules which contain functions that the caller
640 wants to export. These modules must also use C<Moose::Exporter>. The
641 most common use case will be to export the functions from C<Moose.pm>.
642 Functions specified by C<with_meta> or C<as_is> take precedence over
643 functions exported by modules specified by C<also>, so that a module
644 can selectively override functions exported by another module.
645
646 C<Moose::Exporter> also makes sure all these functions get removed
647 when C<unimport> is called.
648
649 =back
650
651 Any of the C<*_roles> options for
652 C<Moose::Util::MetaRole::apply_metaclass_roles> and
653 C<Moose::Util::MetaRole::base_class_roles> are also acceptable.
654
655 =item B<< Moose::Exporter->build_import_methods(...) >>
656
657 Returns two or three code refs, one for C<import>, one for
658 C<unimport>, and optionally one for C<init_meta>, if the appropriate
659 options are passed in.
660
661 Accepts the additional C<install> option, which accepts an arrayref of method
662 names to install into your exporting package. The valid options are C<import>,
663 C<unimport>, and C<init_meta>. Calling C<setup_import_methods> is equivalent
664 to calling C<build_import_methods> with C<< install => [qw(import unimport
665 init_meta)] >> except that it doesn't also return the methods.
666
667 Used by C<setup_import_methods>.
668
669 =back
670
671 =head1 IMPORTING AND init_meta
672
673 If you want to set an alternative base object class or metaclass class, see
674 above for details on how this module can call L<Moose::Util::MetaRole> for
675 you.
676
677 If you want to do something that is not supported by this module, simply
678 define an C<init_meta> method in your class. The C<import> method that
679 C<Moose::Exporter> generates for you will call this method (if it exists). It
680 will always pass the caller to this method via the C<for_class> parameter.
681
682 Most of the time, your C<init_meta> method will probably just call C<<
683 Moose->init_meta >> to do the real work:
684
685   sub init_meta {
686       shift; # our class name
687       return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
688   }
689
690 Keep in mind that C<build_import_methods> will return an C<init_meta>
691 method for you, which you can also call from within your custom
692 C<init_meta>:
693
694   my ( $import, $unimport, $init_meta ) =
695       Moose::Exporter->build_import_methods( ... );
696
697   sub import {
698      my $class = shift;
699
700      ...
701
702      $class->$import(...);
703
704      ...
705   }
706
707   sub unimport { goto &$unimport }
708
709   sub init_meta {
710      my $class = shift;
711
712      ...
713
714      $class->$init_meta(...);
715
716      ...
717   }
718
719 =head1 METACLASS TRAITS
720
721 The C<import> method generated by C<Moose::Exporter> will allow the
722 user of your module to specify metaclass traits in a C<-traits>
723 parameter passed as part of the import:
724
725   use Moose -traits => 'My::Meta::Trait';
726
727   use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
728
729 These traits will be applied to the caller's metaclass
730 instance. Providing traits for an exporting class that does not create
731 a metaclass for the caller is an error.
732
733 =head1 AUTHOR
734
735 Dave Rolsky E<lt>autarch@urth.orgE<gt>
736
737 This is largely a reworking of code in Moose.pm originally written by
738 Stevan Little and others.
739
740 =head1 COPYRIGHT AND LICENSE
741
742 Copyright 2009 by Infinity Interactive, Inc.
743
744 L<http://www.iinteractive.com>
745
746 This library is free software; you can redistribute it and/or modify
747 it under the same terms as Perl itself.
748
749 =cut