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