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