Show working example code in the MooseX::Types example.
[gitmo/Moose.git] / lib / Moose / Exporter.pm
CommitLineData
e606ae5f 1package Moose::Exporter;
2
3use strict;
4use warnings;
5
9039e8ec 6our $VERSION = '0.89_01';
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
386c056b 467 = map {
468 ref $_ ? $_ : Moose::Util::resolve_metatrait_alias( $type => $_ )
469 }
e606ae5f 470 @$traits;
471
472 return unless @resolved_traits;
473
474 Moose::Util::MetaRole::apply_metaclass_roles(
475 for_class => $class,
476 metaclass_roles => \@resolved_traits,
477 );
478}
479
480sub _get_caller {
481 # 1 extra level because it's called by import so there's a layer
482 # of indirection
483 my $offset = 1;
484
485 return
486 ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
487 : ( ref $_[1] && defined $_[1]->{into_level} )
488 ? caller( $offset + $_[1]->{into_level} )
489 : caller($offset);
490}
491
492sub _make_unimport_sub {
493 shift;
494 my $exporting_package = shift;
495 my $exports = shift;
e05fb8ae 496 my $is_removable = shift;
e606ae5f 497 my $export_recorder = shift;
498
499 return sub {
500 my $caller = scalar caller();
501 Moose::Exporter->_remove_keywords(
502 $caller,
503 [ keys %{$exports} ],
e05fb8ae 504 $is_removable,
e606ae5f 505 $export_recorder,
506 );
507 };
508}
509
510sub _remove_keywords {
511 shift;
512 my $package = shift;
513 my $keywords = shift;
e05fb8ae 514 my $is_removable = shift;
e606ae5f 515 my $recorded_exports = shift;
516
517 no strict 'refs';
518
519 foreach my $name ( @{ $keywords } ) {
e05fb8ae 520 next unless $is_removable->{$name};
e606ae5f 521
522 if ( defined &{ $package . '::' . $name } ) {
523 my $sub = \&{ $package . '::' . $name };
524
525 # make sure it is from us
526 next unless $recorded_exports->{$sub};
527
528 # and if it is from us, then undef the slot
529 delete ${ $package . '::' }{$name};
530 }
531 }
532}
533
e2fa092d 534sub import {
535 strict->import;
536 warnings->import;
537}
538
e606ae5f 5391;
540
541__END__
542
543=head1 NAME
544
545Moose::Exporter - make an import() and unimport() just like Moose.pm
546
547=head1 SYNOPSIS
548
549 package MyApp::Moose;
550
e606ae5f 551 use Moose ();
552 use Moose::Exporter;
553
554 Moose::Exporter->setup_import_methods(
82ad7804 555 with_caller => [ 'has_rw', 'sugar2' ],
e606ae5f 556 as_is => [ 'sugar3', \&Some::Random::thing ],
557 also => 'Moose',
558 );
559
82ad7804 560 sub has_rw {
6daad0b9 561 my ($caller, $name, %options) = @_;
4a8a45bc 562 Class::MOP::class_of($caller)->add_attribute($name,
82ad7804 563 is => 'rw',
564 %options,
565 );
566 }
567
e606ae5f 568 # then later ...
569 package MyApp::User;
570
571 use MyApp::Moose;
572
573 has 'name';
6daad0b9 574 has_rw 'size';
e606ae5f 575 thing;
576
577 no MyApp::Moose;
578
579=head1 DESCRIPTION
580
fd7ab111 581This module encapsulates the exporting of sugar functions in a
582C<Moose.pm>-like manner. It does this by building custom C<import> and
583C<unimport> methods for your module, based on a spec you provide.
e606ae5f 584
24aef5e1 585It also lets you "stack" Moose-alike modules so you can export
e606ae5f 586Moose's sugar as well as your own, along with sugar from any random
587C<MooseX> module, as long as they all use C<Moose::Exporter>.
588
10e0127a 589To simplify writing exporter modules, C<Moose::Exporter> also imports
590C<strict> and C<warnings> into your exporter module, as well as into
591modules that use it.
592
e606ae5f 593=head1 METHODS
594
595This module provides two public methods:
596
4b68e0de 597=over 4
598
599=item B<< Moose::Exporter->setup_import_methods(...) >>
e606ae5f 600
601When you call this method, C<Moose::Exporter> build custom C<import>
602and C<unimport> methods for your module. The import method will export
603the functions you specify, and you can also tell it to export
604functions exported by some other module (like C<Moose.pm>).
605
606The C<unimport> method cleans the callers namespace of all the
607exported functions.
608
609This method accepts the following parameters:
610
4b68e0de 611=over 8
e606ae5f 612
613=item * with_caller => [ ... ]
614
615This a list of function I<names only> to be exported wrapped and then
616exported. The wrapper will pass the name of the calling package as the
617first argument to the function. Many sugar functions need to know
618their caller so they can get the calling package's metaclass object.
619
620=item * as_is => [ ... ]
621
622This a list of function names or sub references to be exported
623as-is. You can identify a subroutine by reference, which is handy to
624re-export some other module's functions directly by reference
625(C<\&Some::Package::function>).
626
e05fb8ae 627If you do export some other packages function, this function will
628never be removed by the C<unimport> method. The reason for this is we
629cannot know if the caller I<also> explicitly imported the sub
630themselves, and therefore wants to keep it.
631
e606ae5f 632=item * also => $name or \@names
633
634This is a list of modules which contain functions that the caller
635wants to export. These modules must also use C<Moose::Exporter>. The
636most common use case will be to export the functions from C<Moose.pm>.
ae8817b6 637Functions specified by C<with_caller> or C<as_is> take precedence over
638functions exported by modules specified by C<also>, so that a module
639can selectively override functions exported by another module.
e606ae5f 640
641C<Moose::Exporter> also makes sure all these functions get removed
642when C<unimport> is called.
643
644=back
645
4b68e0de 646=item B<< Moose::Exporter->build_import_methods(...) >>
e606ae5f 647
648Returns two code refs, one for import and one for unimport.
649
650Used by C<setup_import_methods>.
651
4b68e0de 652=back
653
e606ae5f 654=head1 IMPORTING AND init_meta
655
656If you want to set an alternative base object class or metaclass
657class, simply define an C<init_meta> method in your class. The
658C<import> method that C<Moose::Exporter> generates for you will call
659this method (if it exists). It will always pass the caller to this
660method via the C<for_class> parameter.
661
662Most of the time, your C<init_meta> method will probably just call C<<
663Moose->init_meta >> to do the real work:
664
665 sub init_meta {
666 shift; # our class name
667 return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
668 }
669
670=head1 METACLASS TRAITS
671
672The C<import> method generated by C<Moose::Exporter> will allow the
673user of your module to specify metaclass traits in a C<-traits>
674parameter passed as part of the import:
675
676 use Moose -traits => 'My::Meta::Trait';
677
678 use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
679
680These traits will be applied to the caller's metaclass
681instance. Providing traits for an exporting class that does not create
682a metaclass for the caller is an error.
683
684=head1 AUTHOR
685
686Dave Rolsky E<lt>autarch@urth.orgE<gt>
687
688This is largely a reworking of code in Moose.pm originally written by
689Stevan Little and others.
690
691=head1 COPYRIGHT AND LICENSE
692
2840a3b2 693Copyright 2009 by Infinity Interactive, Inc.
e606ae5f 694
695L<http://www.iinteractive.com>
696
697This library is free software; you can redistribute it and/or modify
698it under the same terms as Perl itself.
699
700=cut