X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FUtil.pm;h=3e858c17dcbacd8c66b15780c652b7e257315eb8;hb=6e56c6e09ab419776522759fc65fb0e85af66538;hp=0d061af1122369f05f0623c07b5cb415508ea4c4;hpb=6302a7e870c9ed9bce511891a74e5bdd140fcc74;p=gitmo%2FMoose.git diff --git a/lib/Moose/Util.pm b/lib/Moose/Util.pm index 0d061af..3e858c1 100644 --- a/lib/Moose/Util.pm +++ b/lib/Moose/Util.pm @@ -3,18 +3,20 @@ package Moose::Util; use strict; use warnings; +use Data::OptList; use Sub::Exporter; use Scalar::Util 'blessed'; use Class::MOP 0.60; -our $VERSION = '0.73_02'; +our $VERSION = '0.89_02'; $VERSION = eval $VERSION; our $AUTHORITY = 'cpan:STEVAN'; my @exports = qw[ - find_meta + find_meta does_role - search_class_by_role + search_class_by_role + ensure_all_roles apply_all_roles get_all_init_args get_all_attribute_values @@ -22,6 +24,8 @@ my @exports = qw[ resolve_metaclass_alias add_method_modifier english_list + meta_attribute_alias + meta_class_alias ]; Sub::Exporter::setup_exporter({ @@ -39,7 +43,7 @@ sub does_role { my ($class_or_obj, $role) = @_; my $meta = find_meta($class_or_obj); - + return unless defined $meta; return unless $meta->can('does_role'); return 1 if $meta->does_role($role); @@ -48,14 +52,14 @@ sub does_role { sub search_class_by_role { my ($class_or_obj, $role_name) = @_; - + my $meta = find_meta($class_or_obj); return unless defined $meta; foreach my $class ($meta->class_precedence_list) { - - my $_meta = find_meta($class); + + my $_meta = find_meta($class); next unless defined $_meta; @@ -67,8 +71,22 @@ sub search_class_by_role { return; } +# this can possibly behave in unexpected ways because the roles being composed +# before being applied could differ from call to call; I'm not sure if or how +# to document this possible quirk. +sub ensure_all_roles { + my $applicant = shift; + _apply_all_roles($applicant, sub { !does_role($applicant, $_) }, @_); +} + sub apply_all_roles { my $applicant = shift; + _apply_all_roles($applicant, undef, @_); +} + +sub _apply_all_roles { + my $applicant = shift; + my $role_filter = shift; unless (@_) { require Moose; @@ -78,9 +96,10 @@ sub apply_all_roles { my $roles = Data::OptList::mkopt( [@_] ); foreach my $role (@$roles) { - my $meta = Class::MOP::load_class( $role->[0] ); + Class::MOP::load_class( $role->[0] ); + my $meta = Class::MOP::class_of( $role->[0] ); - unless ($meta->isa('Moose::Meta::Role') ) { + unless ($meta && $meta->isa('Moose::Meta::Role') ) { require Moose; Moose->throw_error( "You can only consume roles, " . $role->[0] @@ -88,6 +107,12 @@ sub apply_all_roles { } } + if ( defined $role_filter ) { + @$roles = grep { local $_ = $_->[0]; $role_filter->() } @$roles; + } + + return unless @$roles; + my $meta = ( blessed $applicant ? $applicant : find_meta($applicant) ); if ( scalar @$roles == 1 ) { @@ -116,7 +141,7 @@ sub get_all_init_args { return +{ map { $_->init_arg => $_->get_value($instance) } grep { $_->has_value($instance) } - grep { defined($_->init_arg) } + grep { defined($_->init_arg) } $class->get_all_attributes }; } @@ -125,6 +150,15 @@ sub resolve_metatrait_alias { return resolve_metaclass_alias( @_, trait => 1 ); } +sub _build_alias_package_name { + my ($type, $name, $trait) = @_; + return 'Moose::Meta::' + . $type + . '::Custom::' + . ( $trait ? 'Trait::' : '' ) + . $name; +} + { my %cache; @@ -135,12 +169,9 @@ sub resolve_metatrait_alias { return $cache{$cache_key}{$metaclass_name} if $cache{$cache_key}{$metaclass_name}; - my $possible_full_name - = 'Moose::Meta::' - . $type - . '::Custom::' - . ( $options{trait} ? "Trait::" : "" ) - . $metaclass_name; + my $possible_full_name = _build_alias_package_name( + $type, $metaclass_name, $options{trait} + ); my $loaded_class = Class::MOP::load_first_existing_class( $possible_full_name, @@ -156,7 +187,10 @@ sub resolve_metatrait_alias { sub add_method_modifier { my ( $class_or_obj, $modifier_name, $args ) = @_; - my $meta = find_meta($class_or_obj); + my $meta + = $class_or_obj->can('add_before_method_modifier') + ? $class_or_obj + : find_meta($class_or_obj); my $code = pop @{$args}; my $add_modifier_method = 'add_' . $modifier_name . '_method_modifier'; if ( my $method_modifier_type = ref( @{$args}[0] ) ) { @@ -186,6 +220,37 @@ sub english_list { return $list; } +sub _caller_info { + my $level = @_ ? ($_[0] + 1) : 2; + my %info; + @info{qw(package file line)} = caller($level); + return \%info; +} + +sub _create_alias { + my ($type, $name, $trait, $for) = @_; + my $package = _build_alias_package_name($type, $name, $trait); + Class::MOP::Class->initialize($package)->add_method( + register_implementation => sub { $for } + ); +} + +sub meta_attribute_alias { + my ($to, $from) = @_; + $from ||= caller; + my $meta = Class::MOP::class_of($from); + my $trait = $meta->isa('Moose::Meta::Role'); + _create_alias('Attribute', $to, $trait, $from); +} + +sub meta_class_alias { + my ($to, $from) = @_; + $from ||= caller; + my $meta = Class::MOP::class_of($from); + my $trait = $meta->isa('Moose::Meta::Role'); + _create_alias('Class', $to, $trait, $from); +} + 1; __END__ @@ -222,7 +287,7 @@ some of them may be useful for use in your own code. =item B This method takes a class name or object and attempts to find a -metaclass for the class, if one exists. It will not create one if it +metaclass for the class, if one exists. It will B create one if it does not yet exist. =item B @@ -246,8 +311,13 @@ applicant can be a role name, class name, or object. The C<$applicant> must already have a metaclass object. The list of C<@roles> should be a list of names, each of which can be -followed by an optional hash reference of options (C and -C). +followed by an optional hash reference of options (C<-excludes> and +C<-alias>). + +=item B + +This function is similar to L, but only applies roles that +C<$applicant> does not already consume. =item B @@ -274,8 +344,8 @@ when specifying the C or C option for an attribute: metaclass => "Bar", ); -The name resolution mechanism is covered in L. +The name resolution mechanism is covered in +L. =item B @@ -283,6 +353,14 @@ Given a list of scalars, turns them into a proper list in English ("one and two", "one, two, three, and four"). This is used to help us make nicer error messages. +=item B + +=item B + +Create an alias from the class C<$from> (or the current package, if +C<$from> is unspecified), so that +L works properly. + =back =head1 TODO @@ -299,7 +377,7 @@ Here is a list of possible functions to write =head1 BUGS -All complex software has bugs lurking in it, and this module is no +All complex software has bugs lurking in it, and this module is no exception. If you find a bug please either email me, or add the bug to cpan-RT.