bump version to 0.89
[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         # Normally we could look at $_[0], but in some weird cases
377         # (involving goto &Moose::import), $_[0] ends as something
378         # else (like Squirrel).
379         my $class = $exporting_package;
380
381         $CALLER = _get_caller(@_);
382
383         # this works because both pragmas set $^H (see perldoc
384         # perlvar) which affects the current compilation -
385         # i.e. the file who use'd us - which is why we don't need
386         # to do anything special to make it affect that file
387         # rather than this one (which is already compiled)
388
389         strict->import;
390         warnings->import;
391
392         # we should never export to main
393         if ( $CALLER eq 'main' && !$export_to_main ) {
394             warn
395                 qq{$class does not export its sugar to the 'main' package.\n};
396             return;
397         }
398
399         my $did_init_meta;
400         for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
401             # init_meta can apply a role, which when loaded uses
402             # Moose::Exporter, which in turn sets $CALLER, so we need
403             # to protect against that.
404             local $CALLER = $CALLER;
405             $c->init_meta( for_class => $CALLER, metaclass => $metaclass );
406             $did_init_meta = 1;
407         }
408
409         if ( $did_init_meta && @{$traits} ) {
410             # The traits will use Moose::Role, which in turn uses
411             # Moose::Exporter, which in turn sets $CALLER, so we need
412             # to protect against that.
413             local $CALLER = $CALLER;
414             _apply_meta_traits( $CALLER, $traits );
415         }
416         elsif ( @{$traits} ) {
417             require Moose;
418             Moose->throw_error(
419                 "Cannot provide traits when $class does not have an init_meta() method"
420             );
421         }
422
423         goto $exporter;
424     };
425 }
426
427
428 sub _strip_traits {
429     my $idx = first_index { $_ eq '-traits' } @_;
430
431     return ( [], @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
432
433     my $traits = $_[ $idx + 1 ];
434
435     splice @_, $idx, 2;
436
437     $traits = [ $traits ] unless ref $traits;
438
439     return ( $traits, @_ );
440 }
441
442 sub _strip_metaclass {
443     my $idx = first_index { $_ eq '-metaclass' } @_;
444
445     return ( undef, @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
446
447     my $metaclass = $_[ $idx + 1 ];
448
449     splice @_, $idx, 2;
450
451     return ( $metaclass, @_ );
452 }
453
454 sub _apply_meta_traits {
455     my ( $class, $traits ) = @_;
456
457     return unless @{$traits};
458
459     my $meta = Class::MOP::class_of($class);
460
461     my $type = ( split /::/, ref $meta )[-1]
462         or Moose->throw_error(
463         'Cannot determine metaclass type for trait application . Meta isa '
464         . ref $meta );
465
466     my @resolved_traits
467         = map {
468             ref $_ ? $_ : Moose::Util::resolve_metatrait_alias( $type => $_ )
469         }
470         @$traits;
471
472     return unless @resolved_traits;
473
474     Moose::Util::MetaRole::apply_metaclass_roles(
475         for_class       => $class,
476         metaclass_roles => \@resolved_traits,
477     );
478 }
479
480 sub _get_caller {
481     # 1 extra level because it's called by import so there's a layer
482     # of indirection
483     my $offset = 1;
484
485     return
486           ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
487         : ( ref $_[1] && defined $_[1]->{into_level} )
488         ? caller( $offset + $_[1]->{into_level} )
489         : caller($offset);
490 }
491
492 sub _make_unimport_sub {
493     shift;
494     my $exporting_package = shift;
495     my $exports           = shift;
496     my $is_removable      = shift;
497     my $export_recorder   = shift;
498
499     return sub {
500         my $caller = scalar caller();
501         Moose::Exporter->_remove_keywords(
502             $caller,
503             [ keys %{$exports} ],
504             $is_removable,
505             $export_recorder,
506         );
507     };
508 }
509
510 sub _remove_keywords {
511     shift;
512     my $package          = shift;
513     my $keywords         = shift;
514     my $is_removable     = shift;
515     my $recorded_exports = shift;
516
517     no strict 'refs';
518
519     foreach my $name ( @{ $keywords } ) {
520         next unless $is_removable->{$name};
521
522         if ( defined &{ $package . '::' . $name } ) {
523             my $sub = \&{ $package . '::' . $name };
524
525             # make sure it is from us
526             next unless $recorded_exports->{$sub};
527
528             # and if it is from us, then undef the slot
529             delete ${ $package . '::' }{$name};
530         }
531     }
532 }
533
534 sub import {
535     strict->import;
536     warnings->import;
537 }
538
539 1;
540
541 __END__
542
543 =head1 NAME
544
545 Moose::Exporter - make an import() and unimport() just like Moose.pm
546
547 =head1 SYNOPSIS
548
549   package MyApp::Moose;
550
551   use Moose ();
552   use Moose::Exporter;
553
554   Moose::Exporter->setup_import_methods(
555       with_caller => [ 'has_rw', 'sugar2' ],
556       as_is       => [ 'sugar3', \&Some::Random::thing ],
557       also        => 'Moose',
558   );
559
560   sub has_rw {
561       my ($caller, $name, %options) = @_;
562       Class::MOP::class_of($caller)->add_attribute($name,
563           is => 'rw',
564           %options,
565       );
566   }
567
568   # then later ...
569   package MyApp::User;
570
571   use MyApp::Moose;
572
573   has 'name';
574   has_rw 'size';
575   thing;
576
577   no MyApp::Moose;
578
579 =head1 DESCRIPTION
580
581 This module encapsulates the exporting of sugar functions in a
582 C<Moose.pm>-like manner. It does this by building custom C<import> and
583 C<unimport> methods for your module, based on a spec you provide.
584
585 It also lets you "stack" Moose-alike modules so you can export
586 Moose's sugar as well as your own, along with sugar from any random
587 C<MooseX> module, as long as they all use C<Moose::Exporter>.
588
589 To simplify writing exporter modules, C<Moose::Exporter> also imports
590 C<strict> and C<warnings> into your exporter module, as well as into
591 modules that use it.
592
593 =head1 METHODS
594
595 This module provides two public methods:
596
597 =over 4
598
599 =item  B<< Moose::Exporter->setup_import_methods(...) >>
600
601 When you call this method, C<Moose::Exporter> build custom C<import>
602 and C<unimport> methods for your module. The import method will export
603 the functions you specify, and you can also tell it to export
604 functions exported by some other module (like C<Moose.pm>).
605
606 The C<unimport> method cleans the callers namespace of all the
607 exported functions.
608
609 This method accepts the following parameters:
610
611 =over 8
612
613 =item * with_caller => [ ... ]
614
615 This a list of function I<names only> to be exported wrapped and then
616 exported. The wrapper will pass the name of the calling package as the
617 first argument to the function. Many sugar functions need to know
618 their caller so they can get the calling package's metaclass object.
619
620 =item * as_is => [ ... ]
621
622 This a list of function names or sub references to be exported
623 as-is. You can identify a subroutine by reference, which is handy to
624 re-export some other module's functions directly by reference
625 (C<\&Some::Package::function>).
626
627 If you do export some other packages function, this function will
628 never be removed by the C<unimport> method. The reason for this is we
629 cannot know if the caller I<also> explicitly imported the sub
630 themselves, and therefore wants to keep it.
631
632 =item * also => $name or \@names
633
634 This is a list of modules which contain functions that the caller
635 wants to export. These modules must also use C<Moose::Exporter>. The
636 most common use case will be to export the functions from C<Moose.pm>.
637 Functions specified by C<with_caller> or C<as_is> take precedence over
638 functions exported by modules specified by C<also>, so that a module
639 can selectively override functions exported by another module.
640
641 C<Moose::Exporter> also makes sure all these functions get removed
642 when C<unimport> is called.
643
644 =back
645
646 =item B<< Moose::Exporter->build_import_methods(...) >>
647
648 Returns two code refs, one for import and one for unimport.
649
650 Used by C<setup_import_methods>.
651
652 =back
653
654 =head1 IMPORTING AND init_meta
655
656 If you want to set an alternative base object class or metaclass
657 class, simply define an C<init_meta> method in your class. The
658 C<import> method that C<Moose::Exporter> generates for you will call
659 this method (if it exists). It will always pass the caller to this
660 method via the C<for_class> parameter.
661
662 Most of the time, your C<init_meta> method will probably just call C<<
663 Moose->init_meta >> to do the real work:
664
665   sub init_meta {
666       shift; # our class name
667       return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
668   }
669
670 =head1 METACLASS TRAITS
671
672 The C<import> method generated by C<Moose::Exporter> will allow the
673 user of your module to specify metaclass traits in a C<-traits>
674 parameter passed as part of the import:
675
676   use Moose -traits => 'My::Meta::Trait';
677
678   use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
679
680 These traits will be applied to the caller's metaclass
681 instance. Providing traits for an exporting class that does not create
682 a metaclass for the caller is an error.
683
684 =head1 AUTHOR
685
686 Dave Rolsky E<lt>autarch@urth.orgE<gt>
687
688 This is largely a reworking of code in Moose.pm originally written by
689 Stevan Little and others.
690
691 =head1 COPYRIGHT AND LICENSE
692
693 Copyright 2009 by Infinity Interactive, Inc.
694
695 L<http://www.iinteractive.com>
696
697 This library is free software; you can redistribute it and/or modify
698 it under the same terms as Perl itself.
699
700 =cut