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