add alias resolution for "use Moose -metaclass"
[gitmo/Moose.git] / lib / Moose / Exporter.pm
CommitLineData
e606ae5f 1package Moose::Exporter;
2
3use strict;
4use warnings;
5
6fdf3dfa 6our $VERSION = '0.88';
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
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
30sub 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
45975bce 41 my ( $exports, $is_removable, $groups )
e05fb8ae 42 = $class->_make_sub_exporter_params(
f44ec924 43 [ @exports_from, $exporting_package ], $export_recorder );
e606ae5f 44
45 my $exporter = Sub::Exporter::build_exporter(
46 {
47 exports => $exports,
45975bce 48 groups => { default => [':all'], %$groups }
e606ae5f 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,
e05fb8ae 59 $is_removable, $export_recorder );
e606ae5f 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
ba1a3c2f 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 }
e606ae5f 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 {
f5d03831 95 die "Circular reference in also parameter to Moose::Exporter between $exporting_package and $package"
e606ae5f 96 if $seen->{$package};
97
98 $seen->{$package} = 1;
99 }
100
101 return @also, map { _follow_also_real($_) } @also;
102 }
103}
104
105sub _make_sub_exporter_params {
106 my $class = shift;
107 my $packages = shift;
108 my $export_recorder = shift;
109
45975bce 110 my %groups;
e606ae5f 111 my %exports;
e05fb8ae 112 my %is_removable;
e606ae5f 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
45975bce 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
e606ae5f 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 );
e05fb8ae 140
141 $is_removable{$name} = 1;
e606ae5f 142 }
143
45975bce 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
e606ae5f 161 for my $name ( @{ $args->{as_is} } ) {
162 my $sub;
163
164 if ( ref $name ) {
165 $sub = $name;
e05fb8ae 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;
e606ae5f 181 }
182 else {
183 $sub = do {
184 no strict 'refs';
185 \&{ $package . '::' . $name };
186 };
e05fb8ae 187
188 $is_removable{$name} = 1;
e606ae5f 189 }
190
191 $export_recorder->{$sub} = 1;
192
193 $exports{$name} = sub {$sub};
194 }
45975bce 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 }
e606ae5f 212 }
213
45975bce 214 return ( \%exports, \%is_removable, \%groups );
e606ae5f 215}
216
96bb13ea 217our $CALLER;
218
219sub _make_wrapped_sub {
b4f00a34 220 my $self = shift;
96bb13ea 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
6de00734 234 my $wrapper = $self->_curry_wrapper($sub, $fq_name, $caller);
b4f00a34 235
9f2230e9 236 my $sub = subname($fq_name => $wrapper);
96bb13ea 237
238 $export_recorder->{$sub} = 1;
239
240 return $sub;
241 };
242}
e606ae5f 243
45975bce 244sub _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
264sub _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
6de00734 314sub _curry_wrapper {
badbc528 315 my $class = shift;
b4f00a34 316 my $sub = shift;
317 my $fq_name = shift;
6de00734 318 my @extra = @_;
b4f00a34 319
6de00734 320 my $wrapper = sub { $sub->(@extra, @_) };
badbc528 321 if (my $proto = prototype $sub) {
2d7e979b 322 # XXX - Perl's prototype sucks. Use & to make set_prototype
6de00734 323 # ignore the fact that we're passing "private variables"
2d7e979b 324 &Scalar::Util::set_prototype($wrapper, $proto);
badbc528 325 }
326 return $wrapper;
b4f00a34 327}
328
45975bce 329sub _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
96bb13ea 350sub _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
8f30b86e 370 my $metaclass;
371 ( $metaclass, @_ ) = _strip_metaclass(@_);
8a8856de 372 $metaclass = Moose::Util::resolve_metaclass_alias(
373 'Class' => $metaclass
374 ) if defined $metaclass && length $metaclass;
8f30b86e 375
96bb13ea 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 }
e606ae5f 398
96bb13ea 399 my $did_init_meta;
400 for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
816208bc 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.
fdeb8354 404 local $CALLER = $CALLER;
89bcd625 405 $c->init_meta( for_class => $CALLER, metaclass => $metaclass );
96bb13ea 406 $did_init_meta = 1;
407 }
e606ae5f 408
96bb13ea 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} ) {
70ea9161 417 require Moose;
96bb13ea 418 Moose->throw_error(
419 "Cannot provide traits when $class does not have an init_meta() method"
420 );
421 }
e606ae5f 422
96bb13ea 423 goto $exporter;
424 };
e606ae5f 425}
426
96bb13ea 427
e606ae5f 428sub _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
8f30b86e 442sub _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
e606ae5f 454sub _apply_meta_traits {
455 my ( $class, $traits ) = @_;
456
457 return unless @{$traits};
458
2571a16d 459 my $meta = Class::MOP::class_of($class);
e606ae5f 460
461 my $type = ( split /::/, ref $meta )[-1]
c245d69b 462 or Moose->throw_error(
e606ae5f 463 'Cannot determine metaclass type for trait application . Meta isa '
4c0b3599 464 . ref $meta );
e606ae5f 465
466 my @resolved_traits
467 = map { Moose::Util::resolve_metatrait_alias( $type => $_ ) }
468 @$traits;
469
470 return unless @resolved_traits;
471
472 Moose::Util::MetaRole::apply_metaclass_roles(
473 for_class => $class,
474 metaclass_roles => \@resolved_traits,
475 );
476}
477
478sub _get_caller {
479 # 1 extra level because it's called by import so there's a layer
480 # of indirection
481 my $offset = 1;
482
483 return
484 ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
485 : ( ref $_[1] && defined $_[1]->{into_level} )
486 ? caller( $offset + $_[1]->{into_level} )
487 : caller($offset);
488}
489
490sub _make_unimport_sub {
491 shift;
492 my $exporting_package = shift;
493 my $exports = shift;
e05fb8ae 494 my $is_removable = shift;
e606ae5f 495 my $export_recorder = shift;
496
497 return sub {
498 my $caller = scalar caller();
499 Moose::Exporter->_remove_keywords(
500 $caller,
501 [ keys %{$exports} ],
e05fb8ae 502 $is_removable,
e606ae5f 503 $export_recorder,
504 );
505 };
506}
507
508sub _remove_keywords {
509 shift;
510 my $package = shift;
511 my $keywords = shift;
e05fb8ae 512 my $is_removable = shift;
e606ae5f 513 my $recorded_exports = shift;
514
515 no strict 'refs';
516
517 foreach my $name ( @{ $keywords } ) {
e05fb8ae 518 next unless $is_removable->{$name};
e606ae5f 519
520 if ( defined &{ $package . '::' . $name } ) {
521 my $sub = \&{ $package . '::' . $name };
522
523 # make sure it is from us
524 next unless $recorded_exports->{$sub};
525
526 # and if it is from us, then undef the slot
527 delete ${ $package . '::' }{$name};
528 }
529 }
530}
531
e2fa092d 532sub import {
533 strict->import;
534 warnings->import;
535}
536
e606ae5f 5371;
538
539__END__
540
541=head1 NAME
542
543Moose::Exporter - make an import() and unimport() just like Moose.pm
544
545=head1 SYNOPSIS
546
547 package MyApp::Moose;
548
e606ae5f 549 use Moose ();
550 use Moose::Exporter;
551
552 Moose::Exporter->setup_import_methods(
82ad7804 553 with_caller => [ 'has_rw', 'sugar2' ],
e606ae5f 554 as_is => [ 'sugar3', \&Some::Random::thing ],
555 also => 'Moose',
556 );
557
82ad7804 558 sub has_rw {
6daad0b9 559 my ($caller, $name, %options) = @_;
4a8a45bc 560 Class::MOP::class_of($caller)->add_attribute($name,
82ad7804 561 is => 'rw',
562 %options,
563 );
564 }
565
e606ae5f 566 # then later ...
567 package MyApp::User;
568
569 use MyApp::Moose;
570
571 has 'name';
6daad0b9 572 has_rw 'size';
e606ae5f 573 thing;
574
575 no MyApp::Moose;
576
577=head1 DESCRIPTION
578
fd7ab111 579This module encapsulates the exporting of sugar functions in a
580C<Moose.pm>-like manner. It does this by building custom C<import> and
581C<unimport> methods for your module, based on a spec you provide.
e606ae5f 582
24aef5e1 583It also lets you "stack" Moose-alike modules so you can export
e606ae5f 584Moose's sugar as well as your own, along with sugar from any random
585C<MooseX> module, as long as they all use C<Moose::Exporter>.
586
10e0127a 587To simplify writing exporter modules, C<Moose::Exporter> also imports
588C<strict> and C<warnings> into your exporter module, as well as into
589modules that use it.
590
e606ae5f 591=head1 METHODS
592
593This module provides two public methods:
594
4b68e0de 595=over 4
596
597=item B<< Moose::Exporter->setup_import_methods(...) >>
e606ae5f 598
599When you call this method, C<Moose::Exporter> build custom C<import>
600and C<unimport> methods for your module. The import method will export
601the functions you specify, and you can also tell it to export
602functions exported by some other module (like C<Moose.pm>).
603
604The C<unimport> method cleans the callers namespace of all the
605exported functions.
606
607This method accepts the following parameters:
608
4b68e0de 609=over 8
e606ae5f 610
611=item * with_caller => [ ... ]
612
613This a list of function I<names only> to be exported wrapped and then
614exported. The wrapper will pass the name of the calling package as the
615first argument to the function. Many sugar functions need to know
616their caller so they can get the calling package's metaclass object.
617
618=item * as_is => [ ... ]
619
620This a list of function names or sub references to be exported
621as-is. You can identify a subroutine by reference, which is handy to
622re-export some other module's functions directly by reference
623(C<\&Some::Package::function>).
624
e05fb8ae 625If you do export some other packages function, this function will
626never be removed by the C<unimport> method. The reason for this is we
627cannot know if the caller I<also> explicitly imported the sub
628themselves, and therefore wants to keep it.
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>.
ae8817b6 635Functions specified by C<with_caller> or C<as_is> take precedence over
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
4b68e0de 644=item B<< Moose::Exporter->build_import_methods(...) >>
e606ae5f 645
646Returns two code refs, one for import and one for unimport.
647
648Used by C<setup_import_methods>.
649
4b68e0de 650=back
651
e606ae5f 652=head1 IMPORTING AND init_meta
653
654If you want to set an alternative base object class or metaclass
655class, simply define an C<init_meta> method in your class. The
656C<import> method that C<Moose::Exporter> generates for you will call
657this method (if it exists). It will always pass the caller to this
658method via the C<for_class> parameter.
659
660Most of the time, your C<init_meta> method will probably just call C<<
661Moose->init_meta >> to do the real work:
662
663 sub init_meta {
664 shift; # our class name
665 return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
666 }
667
668=head1 METACLASS TRAITS
669
670The C<import> method generated by C<Moose::Exporter> will allow the
671user of your module to specify metaclass traits in a C<-traits>
672parameter passed as part of the import:
673
674 use Moose -traits => 'My::Meta::Trait';
675
676 use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
677
678These traits will be applied to the caller's metaclass
679instance. Providing traits for an exporting class that does not create
680a metaclass for the caller is an error.
681
682=head1 AUTHOR
683
684Dave Rolsky E<lt>autarch@urth.orgE<gt>
685
686This is largely a reworking of code in Moose.pm originally written by
687Stevan Little and others.
688
689=head1 COPYRIGHT AND LICENSE
690
2840a3b2 691Copyright 2009 by Infinity Interactive, Inc.
e606ae5f 692
693L<http://www.iinteractive.com>
694
695This library is free software; you can redistribute it and/or modify
696it under the same terms as Perl itself.
697
698=cut