make Moose::Exporter import strict and warnings
[gitmo/Moose.git] / lib / Moose / Exporter.pm
CommitLineData
e606ae5f 1package Moose::Exporter;
2
3use strict;
4use warnings;
5
75d2da34 6our $VERSION = '0.77';
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;
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
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
9f2230e9 187 my $sub = 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
8f30b86e 230 my $metaclass;
231 ( $metaclass, @_ ) = _strip_metaclass(@_);
232
96bb13ea 233 # Normally we could look at $_[0], but in some weird cases
234 # (involving goto &Moose::import), $_[0] ends as something
235 # else (like Squirrel).
236 my $class = $exporting_package;
237
238 $CALLER = _get_caller(@_);
239
240 # this works because both pragmas set $^H (see perldoc
241 # perlvar) which affects the current compilation -
242 # i.e. the file who use'd us - which is why we don't need
243 # to do anything special to make it affect that file
244 # rather than this one (which is already compiled)
245
246 strict->import;
247 warnings->import;
248
249 # we should never export to main
250 if ( $CALLER eq 'main' && !$export_to_main ) {
251 warn
252 qq{$class does not export its sugar to the 'main' package.\n};
253 return;
254 }
e606ae5f 255
96bb13ea 256 my $did_init_meta;
257 for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
816208bc 258 # init_meta can apply a role, which when loaded uses
259 # Moose::Exporter, which in turn sets $CALLER, so we need
260 # to protect against that.
fdeb8354 261 local $CALLER = $CALLER;
89bcd625 262 $c->init_meta( for_class => $CALLER, metaclass => $metaclass );
96bb13ea 263 $did_init_meta = 1;
264 }
e606ae5f 265
96bb13ea 266 if ( $did_init_meta && @{$traits} ) {
267 # The traits will use Moose::Role, which in turn uses
268 # Moose::Exporter, which in turn sets $CALLER, so we need
269 # to protect against that.
270 local $CALLER = $CALLER;
271 _apply_meta_traits( $CALLER, $traits );
272 }
273 elsif ( @{$traits} ) {
70ea9161 274 require Moose;
96bb13ea 275 Moose->throw_error(
276 "Cannot provide traits when $class does not have an init_meta() method"
277 );
278 }
e606ae5f 279
96bb13ea 280 goto $exporter;
281 };
e606ae5f 282}
283
96bb13ea 284
e606ae5f 285sub _strip_traits {
286 my $idx = first_index { $_ eq '-traits' } @_;
287
288 return ( [], @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
289
290 my $traits = $_[ $idx + 1 ];
291
292 splice @_, $idx, 2;
293
294 $traits = [ $traits ] unless ref $traits;
295
296 return ( $traits, @_ );
297}
298
8f30b86e 299sub _strip_metaclass {
300 my $idx = first_index { $_ eq '-metaclass' } @_;
301
302 return ( undef, @_ ) unless $idx >= 0 && $#_ >= $idx + 1;
303
304 my $metaclass = $_[ $idx + 1 ];
305
306 splice @_, $idx, 2;
307
308 return ( $metaclass, @_ );
309}
310
e606ae5f 311sub _apply_meta_traits {
312 my ( $class, $traits ) = @_;
313
314 return unless @{$traits};
315
2571a16d 316 my $meta = Class::MOP::class_of($class);
e606ae5f 317
318 my $type = ( split /::/, ref $meta )[-1]
c245d69b 319 or Moose->throw_error(
e606ae5f 320 'Cannot determine metaclass type for trait application . Meta isa '
4c0b3599 321 . ref $meta );
e606ae5f 322
323 my @resolved_traits
324 = map { Moose::Util::resolve_metatrait_alias( $type => $_ ) }
325 @$traits;
326
327 return unless @resolved_traits;
328
329 Moose::Util::MetaRole::apply_metaclass_roles(
330 for_class => $class,
331 metaclass_roles => \@resolved_traits,
332 );
333}
334
335sub _get_caller {
336 # 1 extra level because it's called by import so there's a layer
337 # of indirection
338 my $offset = 1;
339
340 return
341 ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
342 : ( ref $_[1] && defined $_[1]->{into_level} )
343 ? caller( $offset + $_[1]->{into_level} )
344 : caller($offset);
345}
346
347sub _make_unimport_sub {
348 shift;
349 my $exporting_package = shift;
350 my $exports = shift;
e05fb8ae 351 my $is_removable = shift;
e606ae5f 352 my $export_recorder = shift;
353
354 return sub {
355 my $caller = scalar caller();
356 Moose::Exporter->_remove_keywords(
357 $caller,
358 [ keys %{$exports} ],
e05fb8ae 359 $is_removable,
e606ae5f 360 $export_recorder,
361 );
362 };
363}
364
365sub _remove_keywords {
366 shift;
367 my $package = shift;
368 my $keywords = shift;
e05fb8ae 369 my $is_removable = shift;
e606ae5f 370 my $recorded_exports = shift;
371
372 no strict 'refs';
373
374 foreach my $name ( @{ $keywords } ) {
e05fb8ae 375 next unless $is_removable->{$name};
e606ae5f 376
377 if ( defined &{ $package . '::' . $name } ) {
378 my $sub = \&{ $package . '::' . $name };
379
380 # make sure it is from us
381 next unless $recorded_exports->{$sub};
382
383 # and if it is from us, then undef the slot
384 delete ${ $package . '::' }{$name};
385 }
386 }
387}
388
e2fa092d 389sub import {
390 strict->import;
391 warnings->import;
392}
393
e606ae5f 3941;
395
396__END__
397
398=head1 NAME
399
400Moose::Exporter - make an import() and unimport() just like Moose.pm
401
402=head1 SYNOPSIS
403
404 package MyApp::Moose;
405
406 use strict;
407 use warnings;
408
409 use Moose ();
410 use Moose::Exporter;
411
412 Moose::Exporter->setup_import_methods(
82ad7804 413 with_caller => [ 'has_rw', 'sugar2' ],
e606ae5f 414 as_is => [ 'sugar3', \&Some::Random::thing ],
415 also => 'Moose',
416 );
417
82ad7804 418 sub has_rw {
6daad0b9 419 my ($caller, $name, %options) = @_;
82ad7804 420 Class::MOP::Class->initialize($caller)->add_attribute($name,
421 is => 'rw',
422 %options,
423 );
424 }
425
e606ae5f 426 # then later ...
427 package MyApp::User;
428
429 use MyApp::Moose;
430
431 has 'name';
6daad0b9 432 has_rw 'size';
e606ae5f 433 thing;
434
435 no MyApp::Moose;
436
437=head1 DESCRIPTION
438
439This module encapsulates the logic to export sugar functions like
440C<Moose.pm>. It does this by building custom C<import> and C<unimport>
441methods for your module, based on a spec your provide.
442
443It also lets your "stack" Moose-alike modules so you can export
444Moose's sugar as well as your own, along with sugar from any random
445C<MooseX> module, as long as they all use C<Moose::Exporter>.
446
447=head1 METHODS
448
449This module provides two public methods:
450
4b68e0de 451=over 4
452
453=item B<< Moose::Exporter->setup_import_methods(...) >>
e606ae5f 454
455When you call this method, C<Moose::Exporter> build custom C<import>
456and C<unimport> methods for your module. The import method will export
457the functions you specify, and you can also tell it to export
458functions exported by some other module (like C<Moose.pm>).
459
460The C<unimport> method cleans the callers namespace of all the
461exported functions.
462
463This method accepts the following parameters:
464
4b68e0de 465=over 8
e606ae5f 466
467=item * with_caller => [ ... ]
468
469This a list of function I<names only> to be exported wrapped and then
470exported. The wrapper will pass the name of the calling package as the
471first argument to the function. Many sugar functions need to know
472their caller so they can get the calling package's metaclass object.
473
474=item * as_is => [ ... ]
475
476This a list of function names or sub references to be exported
477as-is. You can identify a subroutine by reference, which is handy to
478re-export some other module's functions directly by reference
479(C<\&Some::Package::function>).
480
e05fb8ae 481If you do export some other packages function, this function will
482never be removed by the C<unimport> method. The reason for this is we
483cannot know if the caller I<also> explicitly imported the sub
484themselves, and therefore wants to keep it.
485
e606ae5f 486=item * also => $name or \@names
487
488This is a list of modules which contain functions that the caller
489wants to export. These modules must also use C<Moose::Exporter>. The
490most common use case will be to export the functions from C<Moose.pm>.
ae8817b6 491Functions specified by C<with_caller> or C<as_is> take precedence over
492functions exported by modules specified by C<also>, so that a module
493can selectively override functions exported by another module.
e606ae5f 494
495C<Moose::Exporter> also makes sure all these functions get removed
496when C<unimport> is called.
497
498=back
499
4b68e0de 500=item B<< Moose::Exporter->build_import_methods(...) >>
e606ae5f 501
502Returns two code refs, one for import and one for unimport.
503
504Used by C<setup_import_methods>.
505
4b68e0de 506=back
507
e606ae5f 508=head1 IMPORTING AND init_meta
509
510If you want to set an alternative base object class or metaclass
511class, simply define an C<init_meta> method in your class. The
512C<import> method that C<Moose::Exporter> generates for you will call
513this method (if it exists). It will always pass the caller to this
514method via the C<for_class> parameter.
515
516Most of the time, your C<init_meta> method will probably just call C<<
517Moose->init_meta >> to do the real work:
518
519 sub init_meta {
520 shift; # our class name
521 return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
522 }
523
524=head1 METACLASS TRAITS
525
526The C<import> method generated by C<Moose::Exporter> will allow the
527user of your module to specify metaclass traits in a C<-traits>
528parameter passed as part of the import:
529
530 use Moose -traits => 'My::Meta::Trait';
531
532 use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
533
534These traits will be applied to the caller's metaclass
535instance. Providing traits for an exporting class that does not create
536a metaclass for the caller is an error.
537
538=head1 AUTHOR
539
540Dave Rolsky E<lt>autarch@urth.orgE<gt>
541
542This is largely a reworking of code in Moose.pm originally written by
543Stevan Little and others.
544
545=head1 COPYRIGHT AND LICENSE
546
2840a3b2 547Copyright 2009 by Infinity Interactive, Inc.
e606ae5f 548
549L<http://www.iinteractive.com>
550
551This library is free software; you can redistribute it and/or modify
552it under the same terms as Perl itself.
553
554=cut