closed
[gitmo/Class-MOP.git] / lib / Class / MOP / Attribute.pm
index cf12216..5352826 100644 (file)
@@ -98,14 +98,18 @@ sub init_arg  { $_[0]->{init_arg}  }
 # end bootstrapped away method section.
 # (all methods below here are kept intact)
 
+sub is_default_a_coderef { 
+    (reftype($_[0]->{default}) && reftype($_[0]->{default}) eq 'CODE')
+}
+
 sub default { 
-    my $self = shift;
-    if (reftype($self->{default}) && reftype($self->{default}) eq 'CODE') {
+    my ($self, $instance) = @_;
+    if ($instance && $self->is_default_a_coderef) {
         # if the default is a CODE ref, then 
         # we pass in the instance and default
         # can return a value based on that 
         # instance. Somewhat crude, but works.
-        return $self->{default}->(shift);
+        return $self->{default}->($instance);
     }           
     $self->{default};
 }
@@ -131,60 +135,111 @@ sub detach_from_class {
 ## Method generation helpers
 
 sub generate_accessor_method {
-    my $self = shift;
-    my $meta_class = $self->associated_class;    
+    my $self = shift; 
     my $attr_name  = $self->name;
     return sub {
-        my $meta_instance = $meta_class->initialize(Scalar::Util::blessed($_[0]))->get_meta_instance;
+        my $meta_instance = Class::MOP::Class->initialize(Scalar::Util::blessed($_[0]))->get_meta_instance;
         $meta_instance->set_slot_value($_[0], $attr_name, $_[1]) if scalar(@_) == 2;
         $meta_instance->get_slot_value($_[0], $attr_name);
     };
 }
 
+sub generate_accessor_method_inline {
+    my $self          = shift; 
+    my $attr_name     = $self->name;
+    my $meta_instance = $self->associated_class->instance_metaclass;
+
+    my $code = eval 'sub {'
+        . $meta_instance->inline_set_slot_value('$_[0]', "'$attr_name'", '$_[1]')  . ' if scalar(@_) == 2; '
+        . $meta_instance->inline_get_slot_value('$_[0]', "'$attr_name'")
+    . '}';
+    confess "Could not generate inline accessor because : $@" if $@;
+
+    return $code;
+}
+
 sub generate_reader_method {
     my $self = shift;
-    my $meta_class = $self->associated_class;    
     my $attr_name  = $self->name;
     return sub { 
         confess "Cannot assign a value to a read-only accessor" if @_ > 1;
-        $meta_class->initialize(Scalar::Util::blessed($_[0]))
-                   ->get_meta_instance
-                   ->get_slot_value($_[0], $attr_name); 
+        Class::MOP::Class->initialize(Scalar::Util::blessed($_[0]))
+                         ->get_meta_instance
+                         ->get_slot_value($_[0], $attr_name); 
     };   
 }
 
+sub generate_reader_method_inline {
+    my $self          = shift; 
+    my $attr_name     = $self->name;
+    my $meta_instance = $self->associated_class->instance_metaclass;
+
+    my $code = eval 'sub {'
+        . 'confess "Cannot assign a value to a read-only accessor" if @_ > 1;'
+        . $meta_instance->inline_get_slot_value('$_[0]', "'$attr_name'")
+    . '}';
+    confess "Could not generate inline accessor because : $@" if $@;
+
+    return $code;
+}
+
 sub generate_writer_method {
     my $self = shift;
-    my $meta_class = $self->associated_class;    
     my $attr_name  = $self->name;
     return sub { 
-        $meta_class->initialize(Scalar::Util::blessed($_[0]))
-                   ->get_meta_instance
-                   ->set_slot_value($_[0], $attr_name, $_[1]);
+        Class::MOP::Class->initialize(Scalar::Util::blessed($_[0]))
+                         ->get_meta_instance
+                         ->set_slot_value($_[0], $attr_name, $_[1]);
     };
 }
 
+sub generate_writer_method_inline {
+    my $self          = shift; 
+    my $attr_name     = $self->name;
+    my $meta_instance = $self->associated_class->instance_metaclass;
+
+    my $code = eval 'sub {'
+        . $meta_instance->inline_set_slot_value('$_[0]', "'$attr_name'", '$_[1]')
+    . '}';
+    confess "Could not generate inline accessor because : $@" if $@;
+
+    return $code;
+}
+
 sub generate_predicate_method {
     my $self = shift;
-    my $meta_class = $self->associated_class;    
     my $attr_name  = $self->name;
     return sub { 
-        defined $meta_class->initialize(Scalar::Util::blessed($_[0]))
-                           ->get_meta_instance
-                           ->get_slot_value($_[0], $attr_name) ? 1 : 0;
+        defined Class::MOP::Class->initialize(Scalar::Util::blessed($_[0]))
+                                 ->get_meta_instance
+                                 ->get_slot_value($_[0], $attr_name) ? 1 : 0;
     };
 }
 
+sub generate_predicate_method_inline {
+    my $self          = shift; 
+    my $attr_name     = $self->name;
+    my $meta_instance = $self->associated_class->instance_metaclass;
+
+    my $code = eval 'sub {'
+        . 'defined ' . $meta_instance->inline_get_slot_value('$_[0]', "'$attr_name'") . ' ? 1 : 0'
+    . '}';
+    confess "Could not generate inline accessor because : $@" if $@;
+
+    return $code;
+}
+
 sub process_accessors {
-    my ($self, $type, $accessor) = @_;
+    my ($self, $type, $accessor, $generate_as_inline_methods) = @_;
     if (reftype($accessor)) {
         (reftype($accessor) eq 'HASH')
             || confess "bad accessor/reader/writer/predicate format, must be a HASH ref";
-        my ($name, $method) = each %{$accessor};
+        my ($name, $method) = %{$accessor};
         return ($name, Class::MOP::Attribute::Accessor->wrap($method));        
     }
     else {
-        my $generator = $self->can('generate_' . $type . '_method');
+        my $inline_me = ($generate_as_inline_methods && $self->associated_class->instance_metaclass->is_inlinable); 
+        my $generator = $self->can('generate_' . $type . '_method' . ($inline_me ? '_inline' : ''));
         ($generator)
             || confess "There is no method generator for the type='$type'";
         if (my $method = $self->$generator($self->name)) {
@@ -195,24 +250,26 @@ sub process_accessors {
 }
 
 sub install_accessors {
-    my $self  = shift;
-    my $class = $self->associated_class;
+    my $self   = shift;
+    my $inline = shift;
+    my $class  = $self->associated_class;
     
     $class->add_method(
-        $self->process_accessors('accessor' => $self->accessor())
+        $self->process_accessors('accessor' => $self->accessor(), $inline)
     ) if $self->has_accessor();
 
     $class->add_method(            
-        $self->process_accessors('reader' => $self->reader())
+        $self->process_accessors('reader' => $self->reader(), $inline)
     ) if $self->has_reader();
 
     $class->add_method(
-        $self->process_accessors('writer' => $self->writer())
+        $self->process_accessors('writer' => $self->writer(), $inline)
     ) if $self->has_writer();
 
     $class->add_method(
-        $self->process_accessors('predicate' => $self->predicate())
+        $self->process_accessors('predicate' => $self->predicate(), $inline)
     ) if $self->has_predicate();
+    
     return;
 }
 
@@ -435,6 +492,8 @@ passed into C<new>. I think they are pretty much self-explanitory.
 
 =item B<init_arg>
 
+=item B<is_default_a_coderef>
+
 =item B<default (?$instance)>
 
 As noted in the documentation for C<new> above, if the I<default> 
@@ -519,6 +578,18 @@ use the custom method passed through the constructor.
 
 =back
 
+=over 4
+
+=item B<generate_accessor_method_inline>
+
+=item B<generate_predicate_method_inline>
+
+=item B<generate_reader_method_inline>
+
+=item B<generate_writer_method_inline>
+
+=back
+
 =item B<remove_accessors>
 
 This allows the attribute to remove the method for it's own