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