X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMouse%2FAttribute.pm;h=1a971bfa4edd0a2006b86b48a3a9b6b3fb563d15;hb=010a2b16f8ed60a3dcca43e80ec75daee135447e;hp=1e60e214abd27bb2226aaaa68cb234dcf772f5bd;hpb=2434d21b71b6770a7d1a8a6ea5abebab3e4602be;p=gitmo%2FMouse.git diff --git a/lib/Mouse/Attribute.pm b/lib/Mouse/Attribute.pm index 1e60e21..1a971bf 100644 --- a/lib/Mouse/Attribute.pm +++ b/lib/Mouse/Attribute.pm @@ -4,6 +4,7 @@ use strict; use warnings; use Carp 'confess'; +use Scalar::Util 'blessed'; sub new { my $class = shift; @@ -35,8 +36,6 @@ sub has_default { exists $_[0]->{default} } sub has_predicate { exists $_[0]->{predicate} } sub has_clearer { exists $_[0]->{clearer} } sub has_handles { exists $_[0]->{handles} } -sub has_weak_ref { exists $_[0]->{weak_ref} } -sub has_init_arg { exists $_[0]->{init_arg} } sub has_type_constraint { exists $_[0]->{type_constraint} } sub has_trigger { exists $_[0]->{trigger} } sub has_builder { exists $_[0]->{builder} } @@ -50,6 +49,7 @@ sub generate_accessor { my $trigger = $attribute->trigger; my $type = $attribute->type_constraint; my $constraint = $attribute->find_type_constraint; + my $builder = $attribute->builder; my $accessor = 'sub { my $self = shift;'; @@ -82,9 +82,13 @@ sub generate_accessor { if ($attribute->is_lazy) { $accessor .= '$self->{$key} = '; - $accessor .= ref($default) eq 'CODE' - ? '$default->($self)' - : '$default'; + + $accessor .= $attribute->has_builder + ? '$self->$builder' + : ref($default) eq 'CODE' + ? '$default->($self)' + : '$default'; + $accessor .= ' if !exists($self->{$key});'; } @@ -136,7 +140,7 @@ sub create { my ($self, $class, $name, %args) = @_; confess "You must specify a default for lazy attribute '$name'" - if $args{lazy} && !exists($args{default}); + if $args{lazy} && !exists($args{default}) && !exists($args{builder}); confess "Trigger is not allowed on read-only attribute '$name'" if $args{trigger} && $args{is} ne 'rw'; @@ -145,15 +149,11 @@ sub create { if ref($args{default}) && ref($args{default}) ne 'CODE'; - $args{handles} = { map { $_ => $_ } @{ $args{handles} } } - if $args{handles} - && ref($args{handles}) eq 'ARRAY'; + $args{handles} = { $self->_canonicalize_handles($args{handles}) } + if $args{handles}; - confess "You must pass a HASH or ARRAY to handles" - if exists($args{handles}) - && ref($args{handles}) ne 'HASH'; - - $args{type_constraint} = delete $args{isa}; + $args{type_constraint} = delete $args{isa} + if exists $args{isa}; my $attribute = $self->new(%args, name => $name, class => $class); my $meta = $class->meta; @@ -197,7 +197,7 @@ sub find_type_constraint { my $checker = Mouse::TypeRegistry->optimized_constraints->{$type}; return $checker if $checker; - confess "Unable to parse type constraint '$type'"; + return sub { blessed($_) && blessed($_) eq $type }; } sub verify_type_constraint { @@ -206,8 +206,7 @@ sub verify_type_constraint { my $type = $self->type_constraint or return 1; - my $constraint = $self->find_type_constraint - or return 1; + my $constraint = $self->find_type_constraint; return 1 if $constraint->($_); @@ -216,6 +215,21 @@ sub verify_type_constraint { Carp::confess("Attribute ($name) does not pass the type constraint because: Validation failed for \'$type\' failed with value $_"); } +sub _canonicalize_handles { + my $self = shift; + my $handles = shift; + + if (ref($handles) eq 'HASH') { + return %$handles; + } + elsif (ref($handles) eq 'ARRAY') { + return map { $_ => $_ } @$handles; + } + else { + confess "Unable to canonicalize the 'handles' option with $handles"; + } +} + 1; __END__ @@ -239,18 +253,42 @@ installed. Some error checking is done. =head2 class -> OwnerClass -=head2 default -> Value +=head2 is_required -> Bool + +=head2 default -> Item + +=head2 has_default -> Bool + +=head2 is_lazy -> Bool -=head2 predicate -> MethodName +=head2 predicate -> MethodName | Undef -=head2 clearer -> MethodName +=head2 has_predicate -> Bool + +=head2 clearer -> MethodName | Undef + +=head2 has_clearer -> Bool =head2 handles -> { LocalName => RemoteName } +=head2 has_handles -> Bool + =head2 weak_ref -> Bool =head2 init_arg -> Str +=head2 type_constraint -> Str + +=head2 has_type_constraint -> Bool + +=head2 trigger => CODE | Undef + +=head2 has_trigger -> Bool + +=head2 builder => MethodName | Undef + +=head2 has_builder -> Bool + Informational methods. =head2 generate_accessor -> CODE @@ -269,5 +307,15 @@ Creates a new code reference for the attribute's clearer. Creates a new code reference for each of the attribute's handles methods. +=head2 find_type_constraint -> CODE + +Returns a code reference which can be used to check that a given value passes +this attribute's type constraint; + +=head2 verify_type_constraint Item -> 1 | ERROR + +Checks that the given value passes this attribute's type constraint. Returns 1 +on success, otherwise Ces. + =cut