add ensure_all_roles()
[gitmo/Moose.git] / lib / Moose / Exporter.pm
CommitLineData
e606ae5f 1package Moose::Exporter;
2
3use strict;
4use warnings;
5
0aca6c89 6our $VERSION = '0.74';
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;
13use Sub::Exporter;
14
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
e05fb8ae 41 my ( $exports, $is_removable )
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,
48 groups => { default => [':all'] }
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
f5d03831 79 die "Package in also ($exporting_package) does not seem to use Moose::Exporter"
e606ae5f 80 unless exists $EXPORT_SPEC{$exporting_package};
81
82 my $also = $EXPORT_SPEC{$exporting_package}{also};
83
84 return unless defined $also;
85
86 my @also = ref $also ? @{$also} : $also;
87
88 for my $package (@also)
89 {
f5d03831 90 die "Circular reference in also parameter to Moose::Exporter between $exporting_package and $package"
e606ae5f 91 if $seen->{$package};
92
93 $seen->{$package} = 1;
94 }
95
96 return @also, map { _follow_also_real($_) } @also;
97 }
98}
99
100sub _make_sub_exporter_params {
101 my $class = shift;
102 my $packages = shift;
103 my $export_recorder = shift;
104
105 my %exports;
e05fb8ae 106 my %is_removable;
e606ae5f 107
108 for my $package ( @{$packages} ) {
109 my $args = $EXPORT_SPEC{$package}
110 or die "The $package package does not use Moose::Exporter\n";
111
112 for my $name ( @{ $args->{with_caller} } ) {
113 my $sub = do {
114 no strict 'refs';
115 \&{ $package . '::' . $name };
116 };
117
118 my $fq_name = $package . '::' . $name;
119
120 $exports{$name} = $class->_make_wrapped_sub(
121 $fq_name,
122 $sub,
123 $export_recorder,
124 );
e05fb8ae 125
126 $is_removable{$name} = 1;
e606ae5f 127 }
128
129 for my $name ( @{ $args->{as_is} } ) {
130 my $sub;
131
132 if ( ref $name ) {
133 $sub = $name;
e05fb8ae 134
135 # Even though Moose re-exports things from Carp &
136 # Scalar::Util, we don't want to remove those at
137 # unimport time, because the importing package may
138 # have imported them explicitly ala
139 #
140 # use Carp qw( confess );
141 #
142 # This is a hack. Since we can't know whether they
143 # really want to keep these subs or not, we err on the
144 # safe side and leave them in.
145 my $coderef_pkg;
146 ( $coderef_pkg, $name ) = Class::MOP::get_code_info($name);
147
148 $is_removable{$name} = $coderef_pkg eq $package ? 1 : 0;
e606ae5f 149 }
150 else {
151 $sub = do {
152 no strict 'refs';
153 \&{ $package . '::' . $name };
154 };
e05fb8ae 155
156 $is_removable{$name} = 1;
e606ae5f 157 }
158
159 $export_recorder->{$sub} = 1;
160
161 $exports{$name} = sub {$sub};
162 }
163 }
164
e05fb8ae 165 return ( \%exports, \%is_removable );
e606ae5f 166}
167
96bb13ea 168our $CALLER;
169
170sub _make_wrapped_sub {
b4f00a34 171 my $self = shift;
96bb13ea 172 my $fq_name = shift;
173 my $sub = shift;
174 my $export_recorder = shift;
175
176 # We need to set the package at import time, so that when
177 # package Foo imports has(), we capture "Foo" as the
178 # package. This lets other packages call Foo::has() and get
179 # the right package. This is done for backwards compatibility
180 # with existing production code, not because this is a good
181 # idea ;)
182 return sub {
183 my $caller = $CALLER;
184
b4f00a34 185 my $wrapper = $self->_make_wrapper($caller, $sub, $fq_name);
186
187 my $sub = Class::MOP::subname($fq_name => $wrapper);
96bb13ea 188
189 $export_recorder->{$sub} = 1;
190
191 return $sub;
192 };
193}
e606ae5f 194
badbc528 195sub _make_wrapper {
196 my $class = shift;
b4f00a34 197 my $caller = shift;
198 my $sub = shift;
199 my $fq_name = shift;
200
2d7e979b 201 my $wrapper = sub { $sub->($caller, @_) };
badbc528 202 if (my $proto = prototype $sub) {
2d7e979b 203 # XXX - Perl's prototype sucks. Use & to make set_prototype
204 # ignore the fact that we're passing a "provate variable"
205 &Scalar::Util::set_prototype($wrapper, $proto);
badbc528 206 }
207 return $wrapper;
b4f00a34 208}
209
96bb13ea 210sub _make_import_sub {
211 shift;
212 my $exporting_package = shift;
213 my $exporter = shift;
214 my $exports_from = shift;
215 my $export_to_main = shift;
216
217 return sub {
218
219 # I think we could use Sub::Exporter's collector feature
220 # to do this, but that would be rather gross, since that
221 # feature isn't really designed to return a value to the
222 # caller of the exporter sub.
223 #
224 # Also, this makes sure we preserve backwards compat for
225 # _get_caller, so it always sees the arguments in the
226 # expected order.
227 my $traits;
228 ( $traits, @_ ) = _strip_traits(@_);
229
230 # Normally we could look at $_[0], but in some weird cases
231 # (involving goto &Moose::import), $_[0] ends as something
232 # else (like Squirrel).
233 my $class = $exporting_package;
234
235 $CALLER = _get_caller(@_);
236
237 # this works because both pragmas set $^H (see perldoc
238 # perlvar) which affects the current compilation -
239 # i.e. the file who use'd us - which is why we don't need
240 # to do anything special to make it affect that file
241 # rather than this one (which is already compiled)
242
243 strict->import;
244 warnings->import;
245
246 # we should never export to main
247 if ( $CALLER eq 'main' && !$export_to_main ) {
248 warn
249 qq{$class does not export its sugar to the 'main' package.\n};
250 return;
251 }
e606ae5f 252
96bb13ea 253 my $did_init_meta;
254 for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
816208bc 255 # init_meta can apply a role, which when loaded uses
256 # Moose::Exporter, which in turn sets $CALLER, so we need
257 # to protect against that.
fdeb8354 258 local $CALLER = $CALLER;
96bb13ea 259 $c->init_meta( for_class => $CALLER );
260 $did_init_meta = 1;
261 }
e606ae5f 262
96bb13ea 263 if ( $did_init_meta && @{$traits} ) {
264 # The traits will use Moose::Role, which in turn uses
265 # Moose::Exporter, which in turn sets $CALLER, so we need
266 # to protect against that.
267 local $CALLER = $CALLER;
268 _apply_meta_traits( $CALLER, $traits );
269 }
270 elsif ( @{$traits} ) {
70ea9161 271 require Moose;
96bb13ea 272 Moose->throw_error(
273 "Cannot provide traits when $class does not have an init_meta() method"
274 );
275 }
e606ae5f 276
96bb13ea 277 goto $exporter;
278 };
e606ae5f 279}
280
96bb13ea 281
e606ae5f 282sub _strip_traits {
283 my $idx = first_index { $_ eq '-traits' } @_;
284
285 return ( [], @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
286
287 my $traits = $_[ $idx + 1 ];
288
289 splice @_, $idx, 2;
290
291 $traits = [ $traits ] unless ref $traits;
292
293 return ( $traits, @_ );
294}
295
296sub _apply_meta_traits {
297 my ( $class, $traits ) = @_;
298
299 return unless @{$traits};
300
2571a16d 301 my $meta = Class::MOP::class_of($class);
e606ae5f 302
303 my $type = ( split /::/, ref $meta )[-1]
c245d69b 304 or Moose->throw_error(
e606ae5f 305 'Cannot determine metaclass type for trait application . Meta isa '
4c0b3599 306 . ref $meta );
e606ae5f 307
308 my @resolved_traits
309 = map { Moose::Util::resolve_metatrait_alias( $type => $_ ) }
310 @$traits;
311
312 return unless @resolved_traits;
313
314 Moose::Util::MetaRole::apply_metaclass_roles(
315 for_class => $class,
316 metaclass_roles => \@resolved_traits,
317 );
318}
319
320sub _get_caller {
321 # 1 extra level because it's called by import so there's a layer
322 # of indirection
323 my $offset = 1;
324
325 return
326 ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
327 : ( ref $_[1] && defined $_[1]->{into_level} )
328 ? caller( $offset + $_[1]->{into_level} )
329 : caller($offset);
330}
331
332sub _make_unimport_sub {
333 shift;
334 my $exporting_package = shift;
335 my $exports = shift;
e05fb8ae 336 my $is_removable = shift;
e606ae5f 337 my $export_recorder = shift;
338
339 return sub {
340 my $caller = scalar caller();
341 Moose::Exporter->_remove_keywords(
342 $caller,
343 [ keys %{$exports} ],
e05fb8ae 344 $is_removable,
e606ae5f 345 $export_recorder,
346 );
347 };
348}
349
350sub _remove_keywords {
351 shift;
352 my $package = shift;
353 my $keywords = shift;
e05fb8ae 354 my $is_removable = shift;
e606ae5f 355 my $recorded_exports = shift;
356
357 no strict 'refs';
358
359 foreach my $name ( @{ $keywords } ) {
e05fb8ae 360 next unless $is_removable->{$name};
e606ae5f 361
362 if ( defined &{ $package . '::' . $name } ) {
363 my $sub = \&{ $package . '::' . $name };
364
365 # make sure it is from us
366 next unless $recorded_exports->{$sub};
367
368 # and if it is from us, then undef the slot
369 delete ${ $package . '::' }{$name};
370 }
371 }
372}
373
3741;
375
376__END__
377
378=head1 NAME
379
380Moose::Exporter - make an import() and unimport() just like Moose.pm
381
382=head1 SYNOPSIS
383
384 package MyApp::Moose;
385
386 use strict;
387 use warnings;
388
389 use Moose ();
390 use Moose::Exporter;
391
392 Moose::Exporter->setup_import_methods(
82ad7804 393 with_caller => [ 'has_rw', 'sugar2' ],
e606ae5f 394 as_is => [ 'sugar3', \&Some::Random::thing ],
395 also => 'Moose',
396 );
397
82ad7804 398 sub has_rw {
6daad0b9 399 my ($caller, $name, %options) = @_;
82ad7804 400 Class::MOP::Class->initialize($caller)->add_attribute($name,
401 is => 'rw',
402 %options,
403 );
404 }
405
e606ae5f 406 # then later ...
407 package MyApp::User;
408
409 use MyApp::Moose;
410
411 has 'name';
6daad0b9 412 has_rw 'size';
e606ae5f 413 thing;
414
415 no MyApp::Moose;
416
417=head1 DESCRIPTION
418
419This module encapsulates the logic to export sugar functions like
420C<Moose.pm>. It does this by building custom C<import> and C<unimport>
421methods for your module, based on a spec your provide.
422
423It also lets your "stack" Moose-alike modules so you can export
424Moose's sugar as well as your own, along with sugar from any random
425C<MooseX> module, as long as they all use C<Moose::Exporter>.
426
427=head1 METHODS
428
429This module provides two public methods:
430
4b68e0de 431=over 4
432
433=item B<< Moose::Exporter->setup_import_methods(...) >>
e606ae5f 434
435When you call this method, C<Moose::Exporter> build custom C<import>
436and C<unimport> methods for your module. The import method will export
437the functions you specify, and you can also tell it to export
438functions exported by some other module (like C<Moose.pm>).
439
440The C<unimport> method cleans the callers namespace of all the
441exported functions.
442
443This method accepts the following parameters:
444
4b68e0de 445=over 8
e606ae5f 446
447=item * with_caller => [ ... ]
448
449This a list of function I<names only> to be exported wrapped and then
450exported. The wrapper will pass the name of the calling package as the
451first argument to the function. Many sugar functions need to know
452their caller so they can get the calling package's metaclass object.
453
454=item * as_is => [ ... ]
455
456This a list of function names or sub references to be exported
457as-is. You can identify a subroutine by reference, which is handy to
458re-export some other module's functions directly by reference
459(C<\&Some::Package::function>).
460
e05fb8ae 461If you do export some other packages function, this function will
462never be removed by the C<unimport> method. The reason for this is we
463cannot know if the caller I<also> explicitly imported the sub
464themselves, and therefore wants to keep it.
465
e606ae5f 466=item * also => $name or \@names
467
468This is a list of modules which contain functions that the caller
469wants to export. These modules must also use C<Moose::Exporter>. The
470most common use case will be to export the functions from C<Moose.pm>.
ae8817b6 471Functions specified by C<with_caller> or C<as_is> take precedence over
472functions exported by modules specified by C<also>, so that a module
473can selectively override functions exported by another module.
e606ae5f 474
475C<Moose::Exporter> also makes sure all these functions get removed
476when C<unimport> is called.
477
478=back
479
4b68e0de 480=item B<< Moose::Exporter->build_import_methods(...) >>
e606ae5f 481
482Returns two code refs, one for import and one for unimport.
483
484Used by C<setup_import_methods>.
485
4b68e0de 486=back
487
e606ae5f 488=head1 IMPORTING AND init_meta
489
490If you want to set an alternative base object class or metaclass
491class, simply define an C<init_meta> method in your class. The
492C<import> method that C<Moose::Exporter> generates for you will call
493this method (if it exists). It will always pass the caller to this
494method via the C<for_class> parameter.
495
496Most of the time, your C<init_meta> method will probably just call C<<
497Moose->init_meta >> to do the real work:
498
499 sub init_meta {
500 shift; # our class name
501 return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
502 }
503
504=head1 METACLASS TRAITS
505
506The C<import> method generated by C<Moose::Exporter> will allow the
507user of your module to specify metaclass traits in a C<-traits>
508parameter passed as part of the import:
509
510 use Moose -traits => 'My::Meta::Trait';
511
512 use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
513
514These traits will be applied to the caller's metaclass
515instance. Providing traits for an exporting class that does not create
516a metaclass for the caller is an error.
517
518=head1 AUTHOR
519
520Dave Rolsky E<lt>autarch@urth.orgE<gt>
521
522This is largely a reworking of code in Moose.pm originally written by
523Stevan Little and others.
524
525=head1 COPYRIGHT AND LICENSE
526
2840a3b2 527Copyright 2009 by Infinity Interactive, Inc.
e606ae5f 528
529L<http://www.iinteractive.com>
530
531This library is free software; you can redistribute it and/or modify
532it under the same terms as Perl itself.
533
534=cut