X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FExporter.pm;h=961d172ce4186194db2c636d6cfe160673915bcd;hb=e2a758ad2cda3f25747bd9692a46c921cad45f34;hp=8d418385a0aba96081ed40984298570c76885d2b;hpb=19ac4f065d22b4b61870c1968ccba160bc08eecb;p=gitmo%2FMoose.git diff --git a/lib/Moose/Exporter.pm b/lib/Moose/Exporter.pm index 8d41838..961d172 100644 --- a/lib/Moose/Exporter.pm +++ b/lib/Moose/Exporter.pm @@ -24,7 +24,7 @@ sub setup_import_methods { ); } -# A reminder to intreped Moose hackers +# A reminder to intrepid Moose hackers # there may be more than one level of exporter # don't make doy cry. -- perigrin @@ -133,44 +133,71 @@ sub _make_exporter { ); } -{ - my $seen = {}; +sub _follow_also { + my $class = shift; + my $exporting_package = shift; + + _die_if_cycle_found_in_also_list_for_package($exporting_package); - sub _follow_also { - my $class = shift; - my $exporting_package = shift; + return uniq( _follow_also_real($exporting_package) ); +} + +sub _follow_also_real { + my $exporting_package = shift; + my @also = _also_list_for_package($exporting_package); + + return map { $_, _follow_also_real($_) } @also; +} + +sub _also_list_for_package { + my $package = shift; - local %$seen = ( $exporting_package => 1 ); + if ( !exists $EXPORT_SPEC{$package} ) { + my $loaded = is_class_loaded($package); - return uniq( _follow_also_real($exporting_package) ); + die "Package in also ($package) does not seem to " + . "use Moose::Exporter" + . ( $loaded ? "" : " (is it loaded?)" ); } - sub _follow_also_real { - my $exporting_package = shift; + my $also = $EXPORT_SPEC{$package}{also}; - if ( !exists $EXPORT_SPEC{$exporting_package} ) { - my $loaded = is_class_loaded($exporting_package); + return unless defined $also; - die "Package in also ($exporting_package) does not seem to " - . "use Moose::Exporter" - . ( $loaded ? "" : " (is it loaded?)" ); - } + return ref $also ? @$also : $also; +} + +# this is no Tarjan algorithm, but for the list sizes expected, +# brute force will probably be fine (and more maintainable) +sub _die_if_cycle_found_in_also_list_for_package { + my $package = shift; + _die_if_also_list_cycles_back_to_existing_stack( + [ _also_list_for_package($package) ], + [$package], + ); +} - my $also = $EXPORT_SPEC{$exporting_package}{also}; +sub _die_if_also_list_cycles_back_to_existing_stack { + my ( $also_list, $existing_stack ) = @_; - return unless defined $also; + return unless @$also_list && @$existing_stack; - my @also = ref $also ? @{$also} : $also; + for my $also_member (@$also_list) { + for my $stack_member (@$existing_stack) { + next unless $also_member eq $stack_member; - for my $package (@also) { die - "Circular reference in 'also' parameter to Moose::Exporter between $exporting_package and $package" - if $seen->{$package}; - - $seen->{$package} = 1; + "Circular reference in 'also' parameter to Moose::Exporter between " + . join( + ', ', + @$existing_stack + ) . " and $also_member"; } - return @also, map { _follow_also_real($_) } @also; + _die_if_also_list_cycles_back_to_existing_stack( + [ _also_list_for_package($also_member) ], + [ $also_member, @$existing_stack ], + ); } } @@ -615,10 +642,11 @@ sub _apply_meta_traits { my $meta = $meta_lookup->($class); - my $type = ( split /::/, ref $meta )[-1] - or Moose->throw_error( - 'Cannot determine metaclass type for trait application . Meta isa ' - . ref $meta ); + my $type = $meta->isa('Moose::Meta::Role') ? 'Trait' + : $meta->isa('Class::MOP::Class') ? 'Class' + : Moose->throw_error('Cannot determine metaclass type for ' + . 'trait application. Meta isa ' + . ref $meta); my @resolved_traits = map { ref $_ @@ -737,7 +765,11 @@ sub _make_init_meta { return unless %new_style_roles || %old_style_roles || %base_class_roles; - return sub { }; + return sub { + shift; + my %opts = @_; + $meta_lookup->($opts{for_class}); + }; } sub import { @@ -787,9 +819,8 @@ __END__ =head1 DESCRIPTION This module encapsulates the exporting of sugar functions in a -C-like manner. It does this by building custom C, -C, and C methods for your module, based on a spec you -provide. +C-like manner. It does this by building custom C and +C methods for your module, based on a spec you provide. It also lets you "stack" Moose-alike modules so you can export Moose's sugar as well as your own, along with sugar from any random C module, as @@ -809,21 +840,20 @@ This module provides two public methods: =item B<< Moose::Exporter->setup_import_methods(...) >> -When you call this method, C builds custom C, -C, and C methods for your module. The C method +When you call this method, C builds custom C and +C methods for your module. The C method will export the functions you specify, and can also re-export functions -exported by some other module (like C). +exported by some other module (like C). If you pass any parameters +for L, the C method will also call +C and +C as needed, after making +sure the metaclass is initialized. The C method cleans the caller's namespace of all the exported functions. This includes any functions you re-export from other packages. However, if the consumer of your package also imports those functions from the original package, they will I be cleaned. -If you pass any parameters for L, this method will -generate an C for you as well (see below for details). This -C will call C and -C as needed. - Note that if any of these methods already exist, they will not be overridden, you will have to use C to get the coderef that would be installed. @@ -896,15 +926,13 @@ are "class_metaroles", "role_metaroles", and "base_class_roles". =item B<< Moose::Exporter->build_import_methods(...) >> -Returns two or three code refs, one for C, one for -C, and optionally one for C, if the appropriate -options are passed in. +Returns two code refs, one for C and one for C. Accepts the additional C option, which accepts an arrayref of method -names to install into your exporting package. The valid options are C, -C, and C. Calling C is equivalent -to calling C with C<< install => [qw(import unimport -init_meta)] >> except that it doesn't also return the methods. +names to install into your exporting package. The valid options are C +and C. Calling C is equivalent +to calling C with C<< install => [qw(import unimport)] >> +except that it doesn't also return the methods. The C method is built using L. This means that it can take a hashref of the form C<< { into => $package } >> to specify the package @@ -933,38 +961,6 @@ Moose->init_meta >> to do the real work: return Moose->init_meta( @_, metaclass => 'My::Metaclass' ); } -Keep in mind that C will return an C -method for you, which you can also call from within your custom -C: - - my ( $import, $unimport, $init_meta ) - = Moose::Exporter->build_import_methods(...); - - sub import { - my $class = shift; - - ... - - # You can either pass an explicit package to import into ... - $class->$import( { into => scalar(caller) }, ... ); - - ...; - } - - # ... or you can use 'goto' to provide the correct caller info to the - # generated method - sub unimport { goto &$unimport } - - sub init_meta { - my $class = shift; - - ... - - $class->$init_meta(...); - - ... - } - =head1 METACLASS TRAITS The C method generated by C will allow the