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