Refactor Moose::Exporter commands (-metaclass, -traits, -extends)
[gitmo/Moose.git] / lib / Moose / Exporter.pm
CommitLineData
e606ae5f 1package Moose::Exporter;
2
3use strict;
4use warnings;
5
b9e554fa 6our $VERSION = '0.89';
ae18d5ec 7$VERSION = eval $VERSION;
8our $AUTHORITY = 'cpan:STEVAN';
9
e606ae5f 10use Class::MOP;
038fd1ae 11use List::MoreUtils qw( uniq );
e606ae5f 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
038fd1ae 350sub _strip_command {
351 my($args, %commands) = @_;
352
353 for (my $i = 0; $i < @{$args}; $i++) {
354 if ( my $slot_ref = $commands{$args->[$i]} ) {
355 my $arg = $args->[$i+1];
356 splice @{$args}, $i, 2;
357
358 if ( ref($slot_ref) eq 'ARRAY' ) {
359 @{$slot_ref} = ref($arg) eq 'ARRAY' ? @{$arg} : $arg;
360 }
361 else {
362 ${$slot_ref} = $arg;
363 }
364 }
365 }
366 return;
367}
368
96bb13ea 369sub _make_import_sub {
370 shift;
371 my $exporting_package = shift;
372 my $exporter = shift;
373 my $exports_from = shift;
374 my $export_to_main = shift;
375
376 return sub {
377
378 # I think we could use Sub::Exporter's collector feature
379 # to do this, but that would be rather gross, since that
380 # feature isn't really designed to return a value to the
381 # caller of the exporter sub.
382 #
383 # Also, this makes sure we preserve backwards compat for
384 # _get_caller, so it always sees the arguments in the
385 # expected order.
96bb13ea 386
8f30b86e 387 my $metaclass;
038fd1ae 388 my @traits;
389 my @superclasses;
390
391 _strip_command(\@_,
392 -metaclass => \$metaclass,
393 -traits => \@traits,
394 -extends => \@superclasses,
395 );
396
8a8856de 397 $metaclass = Moose::Util::resolve_metaclass_alias(
398 'Class' => $metaclass
399 ) if defined $metaclass && length $metaclass;
8f30b86e 400
96bb13ea 401 # Normally we could look at $_[0], but in some weird cases
402 # (involving goto &Moose::import), $_[0] ends as something
403 # else (like Squirrel).
404 my $class = $exporting_package;
405
038fd1ae 406
96bb13ea 407 $CALLER = _get_caller(@_);
408
409 # this works because both pragmas set $^H (see perldoc
410 # perlvar) which affects the current compilation -
411 # i.e. the file who use'd us - which is why we don't need
412 # to do anything special to make it affect that file
413 # rather than this one (which is already compiled)
414
415 strict->import;
416 warnings->import;
417
418 # we should never export to main
419 if ( $CALLER eq 'main' && !$export_to_main ) {
420 warn
421 qq{$class does not export its sugar to the 'main' package.\n};
422 return;
423 }
e606ae5f 424
96bb13ea 425 my $did_init_meta;
426 for my $c ( grep { $_->can('init_meta') } $class, @{$exports_from} ) {
038fd1ae 427 # init_meta() can load classes using Moose or Moose::Role,
428 # which uses Moose::Exporter, which in turn sets $CALLER, so we need
816208bc 429 # to protect against that.
fdeb8354 430 local $CALLER = $CALLER;
89bcd625 431 $c->init_meta( for_class => $CALLER, metaclass => $metaclass );
96bb13ea 432 $did_init_meta = 1;
433 }
e606ae5f 434
038fd1ae 435 if ( @superclasses ) {
436 if ( $did_init_meta ) {
437 # superclasses() can load classes using Moose or Moose::Role,
438 # which uses Moose::Exporter, which in turn sets $CALLER, so we need
439 # to protect against that.
440 local $CALLER = $CALLER;
441 $CALLER->meta->superclasses(@superclasses);
e0abefb7 442 }
038fd1ae 443 else {
e0abefb7 444 require Moose;
038fd1ae 445 Moose->throw_error(
446 "Cannot provide -extends when $class does not have an init_meta() method"
447 );
e0abefb7 448 }
449 }
450
038fd1ae 451 if ( @traits ) {
452 if ( $did_init_meta ) {
453 # _apply_meta_traits() can load classes using Moose or Moose::Role,
454 # which uses Moose::Exporter, which in turn sets $CALLER, so we need
455 # to protect against that.
456 local $CALLER = $CALLER;
457 _apply_meta_traits( $CALLER, \@traits );
458 }
459 else {
460 require Moose;
461 Moose->throw_error(
462 "Cannot provide traits when $class does not have an init_meta() method"
463 );
464 }
96bb13ea 465 }
e606ae5f 466
96bb13ea 467 goto $exporter;
468 };
e606ae5f 469}
470
e606ae5f 471sub _apply_meta_traits {
472 my ( $class, $traits ) = @_;
473
474 return unless @{$traits};
475
2571a16d 476 my $meta = Class::MOP::class_of($class);
e606ae5f 477
478 my $type = ( split /::/, ref $meta )[-1]
c245d69b 479 or Moose->throw_error(
e606ae5f 480 'Cannot determine metaclass type for trait application . Meta isa '
4c0b3599 481 . ref $meta );
e606ae5f 482
483 my @resolved_traits
386c056b 484 = map {
485 ref $_ ? $_ : Moose::Util::resolve_metatrait_alias( $type => $_ )
486 }
e606ae5f 487 @$traits;
488
489 return unless @resolved_traits;
490
491 Moose::Util::MetaRole::apply_metaclass_roles(
492 for_class => $class,
493 metaclass_roles => \@resolved_traits,
494 );
495}
496
497sub _get_caller {
498 # 1 extra level because it's called by import so there's a layer
499 # of indirection
500 my $offset = 1;
501
502 return
503 ( ref $_[1] && defined $_[1]->{into} ) ? $_[1]->{into}
504 : ( ref $_[1] && defined $_[1]->{into_level} )
505 ? caller( $offset + $_[1]->{into_level} )
506 : caller($offset);
507}
508
509sub _make_unimport_sub {
510 shift;
511 my $exporting_package = shift;
512 my $exports = shift;
e05fb8ae 513 my $is_removable = shift;
e606ae5f 514 my $export_recorder = shift;
515
516 return sub {
517 my $caller = scalar caller();
518 Moose::Exporter->_remove_keywords(
519 $caller,
520 [ keys %{$exports} ],
e05fb8ae 521 $is_removable,
e606ae5f 522 $export_recorder,
523 );
524 };
525}
526
527sub _remove_keywords {
528 shift;
529 my $package = shift;
530 my $keywords = shift;
e05fb8ae 531 my $is_removable = shift;
e606ae5f 532 my $recorded_exports = shift;
533
534 no strict 'refs';
535
536 foreach my $name ( @{ $keywords } ) {
e05fb8ae 537 next unless $is_removable->{$name};
e606ae5f 538
539 if ( defined &{ $package . '::' . $name } ) {
540 my $sub = \&{ $package . '::' . $name };
541
542 # make sure it is from us
543 next unless $recorded_exports->{$sub};
544
545 # and if it is from us, then undef the slot
546 delete ${ $package . '::' }{$name};
547 }
548 }
549}
550
e2fa092d 551sub import {
552 strict->import;
553 warnings->import;
554}
555
e606ae5f 5561;
557
558__END__
559
560=head1 NAME
561
562Moose::Exporter - make an import() and unimport() just like Moose.pm
563
564=head1 SYNOPSIS
565
566 package MyApp::Moose;
567
e606ae5f 568 use Moose ();
569 use Moose::Exporter;
570
571 Moose::Exporter->setup_import_methods(
82ad7804 572 with_caller => [ 'has_rw', 'sugar2' ],
e606ae5f 573 as_is => [ 'sugar3', \&Some::Random::thing ],
574 also => 'Moose',
575 );
576
82ad7804 577 sub has_rw {
6daad0b9 578 my ($caller, $name, %options) = @_;
4a8a45bc 579 Class::MOP::class_of($caller)->add_attribute($name,
82ad7804 580 is => 'rw',
581 %options,
582 );
583 }
584
e606ae5f 585 # then later ...
586 package MyApp::User;
587
588 use MyApp::Moose;
589
590 has 'name';
6daad0b9 591 has_rw 'size';
e606ae5f 592 thing;
593
594 no MyApp::Moose;
595
596=head1 DESCRIPTION
597
fd7ab111 598This module encapsulates the exporting of sugar functions in a
599C<Moose.pm>-like manner. It does this by building custom C<import> and
600C<unimport> methods for your module, based on a spec you provide.
e606ae5f 601
24aef5e1 602It also lets you "stack" Moose-alike modules so you can export
e606ae5f 603Moose's sugar as well as your own, along with sugar from any random
604C<MooseX> module, as long as they all use C<Moose::Exporter>.
605
10e0127a 606To simplify writing exporter modules, C<Moose::Exporter> also imports
607C<strict> and C<warnings> into your exporter module, as well as into
608modules that use it.
609
e606ae5f 610=head1 METHODS
611
612This module provides two public methods:
613
4b68e0de 614=over 4
615
616=item B<< Moose::Exporter->setup_import_methods(...) >>
e606ae5f 617
618When you call this method, C<Moose::Exporter> build custom C<import>
619and C<unimport> methods for your module. The import method will export
620the functions you specify, and you can also tell it to export
621functions exported by some other module (like C<Moose.pm>).
622
623The C<unimport> method cleans the callers namespace of all the
624exported functions.
625
626This method accepts the following parameters:
627
4b68e0de 628=over 8
e606ae5f 629
630=item * with_caller => [ ... ]
631
632This a list of function I<names only> to be exported wrapped and then
633exported. The wrapper will pass the name of the calling package as the
634first argument to the function. Many sugar functions need to know
635their caller so they can get the calling package's metaclass object.
636
637=item * as_is => [ ... ]
638
639This a list of function names or sub references to be exported
640as-is. You can identify a subroutine by reference, which is handy to
641re-export some other module's functions directly by reference
642(C<\&Some::Package::function>).
643
e05fb8ae 644If you do export some other packages function, this function will
645never be removed by the C<unimport> method. The reason for this is we
646cannot know if the caller I<also> explicitly imported the sub
647themselves, and therefore wants to keep it.
648
e606ae5f 649=item * also => $name or \@names
650
651This is a list of modules which contain functions that the caller
652wants to export. These modules must also use C<Moose::Exporter>. The
653most common use case will be to export the functions from C<Moose.pm>.
ae8817b6 654Functions specified by C<with_caller> or C<as_is> take precedence over
655functions exported by modules specified by C<also>, so that a module
656can selectively override functions exported by another module.
e606ae5f 657
658C<Moose::Exporter> also makes sure all these functions get removed
659when C<unimport> is called.
660
661=back
662
4b68e0de 663=item B<< Moose::Exporter->build_import_methods(...) >>
e606ae5f 664
665Returns two code refs, one for import and one for unimport.
666
667Used by C<setup_import_methods>.
668
4b68e0de 669=back
670
e606ae5f 671=head1 IMPORTING AND init_meta
672
673If you want to set an alternative base object class or metaclass
674class, simply define an C<init_meta> method in your class. The
675C<import> method that C<Moose::Exporter> generates for you will call
676this method (if it exists). It will always pass the caller to this
677method via the C<for_class> parameter.
678
679Most of the time, your C<init_meta> method will probably just call C<<
680Moose->init_meta >> to do the real work:
681
682 sub init_meta {
683 shift; # our class name
684 return Moose->init_meta( @_, metaclass => 'My::Metaclass' );
685 }
686
687=head1 METACLASS TRAITS
688
689The C<import> method generated by C<Moose::Exporter> will allow the
690user of your module to specify metaclass traits in a C<-traits>
691parameter passed as part of the import:
692
693 use Moose -traits => 'My::Meta::Trait';
694
695 use Moose -traits => [ 'My::Meta::Trait', 'My::Other::Trait' ];
696
697These traits will be applied to the caller's metaclass
698instance. Providing traits for an exporting class that does not create
699a metaclass for the caller is an error.
700
701=head1 AUTHOR
702
703Dave Rolsky E<lt>autarch@urth.orgE<gt>
704
705This is largely a reworking of code in Moose.pm originally written by
706Stevan Little and others.
707
708=head1 COPYRIGHT AND LICENSE
709
2840a3b2 710Copyright 2009 by Infinity Interactive, Inc.
e606ae5f 711
712L<http://www.iinteractive.com>
713
714This library is free software; you can redistribute it and/or modify
715it under the same terms as Perl itself.
716
717=cut