fixed
[gitmo/Class-MOP.git] / lib / Class / MOP / Attribute.pm
index 90f7d57..32931a9 100644 (file)
@@ -9,7 +9,7 @@ use Class::MOP::Method::Accessor;
 use Carp         'confess';
 use Scalar::Util 'blessed', 'reftype', 'weaken';
 
-our $VERSION   = '0.16';
+our $VERSION   = '0.19';
 our $AUTHORITY = 'cpan:STEVAN';
 
 use base 'Class::MOP::Object';
@@ -43,12 +43,12 @@ sub new {
             if ref $options{builder} || !(defined $options{builder});
         confess("Setting both default and builder is not allowed.")
             if exists $options{default};
+    } else {
+        (is_default_a_coderef(\%options))
+            || confess("References are not allowed as default values, you must ".
+                       "wrap then in a CODE reference (ex: sub { [] } and not [])")
+                if exists $options{default} && ref $options{default};
     }
-    (is_default_a_coderef(\%options))
-        || confess("References are not allowed as default values, you must ".
-                   "wrap then in a CODE reference (ex: sub { [] } and not [])")
-            if exists $options{default} && ref $options{default};
-
     bless {
         '$!name'      => $name,
         '$!accessor'  => $options{accessor},
@@ -85,20 +85,23 @@ sub initialize_instance_slot {
     my ($self, $meta_instance, $instance, $params) = @_;
     my $init_arg = $self->{'$!init_arg'};
     # try to fetch the init arg from the %params ...
-    my $val;
-    $val = $params->{$init_arg} if exists $params->{$init_arg};
+
     # if nothing was in the %params, we can use the
     # attribute's default value (if it has one)
-    if (!defined $val && defined $self->{'$!default'}) {
-        $val = $self->default($instance);
-    }
-    if (!defined $val && defined $self->{'$!builder'}) {
-        my $builder = $self->{'$!builder'};
-        confess(blessed($instance)." does not support builder method '$builder' for attribute '" . $self->name . "'")
-            unless $instance->can($builder);
-        $val = $instance->$builder;
+    if(exists $params->{$init_arg}){
+        $meta_instance->set_slot_value($instance, $self->name, $params->{$init_arg});
+    } 
+    elsif (defined $self->{'$!default'}) {
+        $meta_instance->set_slot_value($instance, $self->name, $self->default($instance));
+    } 
+    elsif (defined( my $builder = $self->{'$!builder'})) {
+        if ($builder = $instance->can($builder)) {
+            $meta_instance->set_slot_value($instance, $self->name, $instance->$builder);
+        } 
+        else {
+            confess(blessed($instance)." does not support builder method '". $self->{'$!builder'} ."' for attribute '" . $self->name . "'");
+        }
     }
-    $meta_instance->set_slot_value($instance, $self->name, $val);
 }
 
 # NOTE:
@@ -133,6 +136,26 @@ sub init_arg  { $_[0]->{'$!init_arg'}  }
 sub get_read_method  { $_[0]->reader || $_[0]->accessor }
 sub get_write_method { $_[0]->writer || $_[0]->accessor }
 
+sub get_read_method_ref {
+    my $self = shift;
+    if ((my $reader = $self->get_read_method) && $self->associated_class) {   
+        return $self->associated_class->get_method($reader);
+    }
+    else {
+        return sub { $self->get_value(@_) };
+    }
+}
+
+sub get_write_method_ref {
+    my $self = shift;    
+    if ((my $writer = $self->get_write_method) && $self->associated_class) {    
+        return $self->associated_class->get_method($writer);
+    }
+    else {
+        return sub { $self->set_value(@_) };
+    }
+}
+
 sub is_default_a_coderef {
     ('CODE' eq (reftype($_[0]->{'$!default'} || $_[0]->{default}) || ''))
 }
@@ -195,9 +218,9 @@ sub get_value {
 sub has_value {
     my ($self, $instance) = @_;
 
-    defined Class::MOP::Class->initialize(blessed($instance))
-                             ->get_meta_instance
-                             ->get_slot_value($instance, $self->name) ? 1 : 0;
+    Class::MOP::Class->initialize(blessed($instance))
+                     ->get_meta_instance
+                     ->is_slot_initialized($instance, $self->name);
 }
 
 sub clear_value {
@@ -543,9 +566,20 @@ just one, which is the name of the attribute.
 
 =item B<get_write_method>
 
-Return the name of a method suitable for reading / writing the value of the
-attribute in the associated class. Suitable for use whether C<reader> and
-C<writer> or C<accessor> was used.
+Return the name of a method name suitable for reading / writing the value 
+of the attribute in the associated class. Suitable for use whether 
+C<reader> and C<writer> or C<accessor> was used.
+
+=item B<get_read_method_ref>
+
+=item B<get_write_method_ref>
+
+Return the CODE reference of a method suitable for reading / writing the 
+value of the attribute in the associated class. Suitable for use whether 
+C<reader> and C<writer> or C<accessor> was specified or not.
+
+NOTE: If not reader/writer/accessor was specified, this will use the 
+attribute get_value/set_value methods, which can be very inefficient.
 
 =back
 
@@ -569,6 +603,8 @@ These are all basic predicate methods for the values passed into C<new>.
 
 =item B<has_default>
 
+=item B<has_builder>
+
 =back
 
 =head2 Class association