X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FMeta%2FAttribute.pm;h=d7347d071960a86f681f02d9b2529f2a5bf8c625;hb=cbeacd38c90812d602c262cb67dec8f128061be9;hp=155f9a0570833d1bfb271d18fc4861d579c2dc2a;hpb=93cc8330c689c1eb92171550e5fabb628a8759a6;p=gitmo%2FMoose.git diff --git a/lib/Moose/Meta/Attribute.pm b/lib/Moose/Meta/Attribute.pm index 155f9a0..d7347d0 100644 --- a/lib/Moose/Meta/Attribute.pm +++ b/lib/Moose/Meta/Attribute.pm @@ -8,7 +8,7 @@ use Scalar::Util 'blessed', 'weaken'; use Carp 'confess'; use overload (); -our $VERSION = '0.54'; +our $VERSION = '0.57'; our $AUTHORITY = 'cpan:STEVAN'; use Moose::Meta::Method::Accessor; @@ -116,22 +116,54 @@ sub interpolate_class { return ( wantarray ? ( $class, @traits ) : $class ); } -# you can change default, required, coerce, documentation, lazy, handles, builder, type_constraint (explicitly or using isa/does), metaclass and traits -sub legal_options_for_inheritance { - return qw(default coerce required documentation lazy handles builder - type_constraint); -} - +# ... + +my @legal_options_for_inheritance = qw( + default coerce required + documentation lazy handles + builder type_constraint +); + +sub legal_options_for_inheritance { @legal_options_for_inheritance } + +# NOTE/TODO +# This method *must* be able to handle +# Class::MOP::Attribute instances as +# well. Yes, I know that is wrong, but +# apparently we didn't realize it was +# doing that and now we have some code +# which is dependent on it. The real +# solution of course is to push this +# feature back up into Class::MOP::Attribute +# but I not right now, I am too lazy. +# However if you are reading this and +# looking for something to do,.. please +# be my guest. +# - stevan sub clone_and_inherit_options { my ($self, %options) = @_; + my %copy = %options; + my %actual_options; - foreach my $legal_option ($self->legal_options_for_inheritance) { + + # NOTE: + # we may want to extends a Class::MOP::Attribute + # in which case we need to be able to use the + # core set of legal options that have always + # been here. But we allows Moose::Meta::Attribute + # instances to changes them. + # - SL + my @legal_options = $self->can('legal_options_for_inheritance') + ? $self->legal_options_for_inheritance + : @legal_options_for_inheritance; + + foreach my $legal_option (@legal_options) { if (exists $options{$legal_option}) { $actual_options{$legal_option} = $options{$legal_option}; delete $options{$legal_option}; } - } + } if ($options{isa}) { my $type_constraint; @@ -344,13 +376,8 @@ sub initialize_instance_slot { $value_is_set = 1; } elsif ($self->has_builder) { - if (my $builder = $instance->can($self->builder)){ - $val = $instance->$builder; - $value_is_set = 1; - } - else { - confess(blessed($instance)." does not support builder method '".$self->builder."' for attribute '" . $self->name . "'"); - } + $val = $self->_call_builder($instance); + $value_is_set = 1; } } @@ -373,6 +400,22 @@ sub initialize_instance_slot { if ref $val && $self->is_weak_ref; } +sub _call_builder { + my ( $self, $instance ) = @_; + + my $builder = $self->builder(); + + return $instance->$builder() + if $instance->can( $self->builder ); + + confess( blessed($instance) + . " does not support builder method '" + . $self->builder + . "' for attribute '" + . $self->name + . "'" ); +} + ## Slot management # FIXME: @@ -457,25 +500,22 @@ sub get_value { if ($self->is_lazy) { unless ($self->has_value($instance)) { + my $value; if ($self->has_default) { - my $default = $self->default($instance); - $self->set_initial_value($instance, $default); + $value = $self->default($instance); } elsif ( $self->has_builder ) { - if (my $builder = $instance->can($self->builder)){ - $self->set_initial_value($instance, $instance->$builder); - } - else { - confess(blessed($instance) - . " does not support builder method '" - . $self->builder - . "' for attribute '" - . $self->name - . "'"); - } - } - else { - $self->set_initial_value($instance, undef); + $value = $self->_call_builder($instance); + } + if ($self->has_type_constraint) { + my $type_constraint = $self->type_constraint; + $value = $type_constraint->coerce($value) + if ($self->should_coerce); + $type_constraint->check($value) + || confess "Attribute (" . $self->name + . ") does not pass the type constraint because: " + . $type_constraint->get_message($value); } + $self->set_initial_value($instance, $value); } } @@ -523,12 +563,10 @@ sub install_delegation { # this will sort out any details and always # return an hash of methods which we want # to delagate to, see that method for details - my %handles = $self->_canonicalize_handles(); + my %handles = $self->_canonicalize_handles; # find the accessor method for this attribute - my $accessor = $self->get_read_method_ref; - # then unpack it if we need too ... - $accessor = $accessor->body if blessed $accessor; + my $accessor = $self->_get_delegate_accessor; # install the delegation ... my $associated_class = $self->associated_class; @@ -577,6 +615,16 @@ sub install_delegation { # private methods to help delegation ... +sub _get_delegate_accessor { + my $self = shift; + # find the accessor method for this attribute + my $accessor = $self->get_read_method_ref; + # then unpack it if we need too ... + $accessor = $accessor->body if blessed $accessor; + # return the accessor + return $accessor; +} + sub _canonicalize_handles { my $self = shift; my $handles = $self->handles; @@ -642,9 +690,9 @@ sub _get_delegate_method_list { my $self = shift; my $meta = $self->_find_delegate_metaclass; if ($meta->isa('Class::MOP::Class')) { - return map { $_->{name} } # NOTE: !never! delegate &meta - grep { $_->{class} ne 'Moose::Object' && $_->{name} ne 'meta' } - $meta->compute_all_applicable_methods; + return map { $_->name } # NOTE: !never! delegate &meta + grep { $_->package_name ne 'Moose::Object' && $_->name ne 'meta' } + $meta->get_all_methods; } elsif ($meta->isa('Moose::Meta::Role')) { return $meta->get_method_list; @@ -721,7 +769,7 @@ Any coercion to convert values is done before checking the type constraint. To check a value against a type constraint before setting it, fetch the attribute instance using L, fetch the type_constraint from the attribute using L -and call L. See L +and call L. See L for an example. =back @@ -793,14 +841,14 @@ and predicate options for you using the following convention. #If your attribute name starts with an underscore: has '_foo' => (lazy_build => 1); #is the same as - has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo); + has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo'); # or has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', default => sub{shift->_build__foo}); #If your attribute name does not start with an underscore: has 'foo' => (lazy_build => 1); #is the same as - has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo); + has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo'); # or has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', default => sub{shift->_build_foo});