'default' => $options->{default},
'initializer' => $options->{initializer},
'definition_context' => $options->{definition_context},
+ 'lazy' => $options->{lazy},
# keep a weakened link to the
# class we are associated with
'associated_class' => undef,
return bless { %{$self}, %options } => ref($self);
}
+sub _call_builder {
+ my ( $self, $instance ) = @_;
+
+ my $builder = $self->builder();
+
+ return $instance->$builder()
+ if $instance->can( $self->builder );
+
+ $self->throw_error( blessed($instance)
+ . " does not support builder method '"
+ . $self->builder
+ . "' for attribute '"
+ . $self->name
+ . "'",
+ object => $instance,
+ );
+}
+
sub initialize_instance_slot {
my ($self, $meta_instance, $instance, $params) = @_;
my $init_arg = $self->{'init_arg'};
+ my ($val, $value_is_set);
# try to fetch the init arg from the %params ...
# if nothing was in the %params, we can use the
# attribute's default value (if it has one)
if(defined $init_arg and exists $params->{$init_arg}){
- $self->_set_initial_slot_value(
- $meta_instance,
- $instance,
- $params->{$init_arg},
- );
- }
- elsif (defined $self->{'default'}) {
- $self->_set_initial_slot_value(
- $meta_instance,
- $instance,
- $self->default($instance),
- );
- }
- elsif (defined( my $builder = $self->{'builder'})) {
- if ($builder = $instance->can($builder)) {
- $self->_set_initial_slot_value(
- $meta_instance,
- $instance,
- $instance->$builder,
- );
- }
- else {
- confess(ref($instance)." does not support builder method '". $self->{'builder'} ."' for attribute '" . $self->name . "'");
+ $val = $params->{$init_arg};
+ $value_is_set = 1;
+ } else {
+ return if $self->is_lazy;
+
+ if($self->has_default){
+ $val = $self->default($instance);
+ $value_is_set = 1;
+ } elsif($self->has_builder){
+ $val = $self->_call_builder($instance);
+ $value_is_set = 1;
}
}
+
+ return unless $value_is_set;
+
+ $self->_set_initial_slot_value(
+ $meta_instance,
+ $instance,
+ $val,
+ );
+
}
sub _set_initial_slot_value {
sub definition_context { $_[0]->{'definition_context'} }
sub insertion_order { $_[0]->{'insertion_order'} }
sub _set_insertion_order { $_[0]->{'insertion_order'} = $_[1] }
+sub is_lazy { $_[0]->{'lazy'} }
# end bootstrapped away method section.
# (all methods below here are kept intact)
sub get_raw_value {
my ($self, $instance) = @_;
+ if($self->is_lazy && !$self->has_value($instance)){
+ my $val;
+
+ if($self->has_default){
+ $val = $self->default($instance);
+ } elsif($self->has_builder){
+ $val = $self->_call_builder($instance);
+ }
+
+ $self->set_initial_value(
+ $instance,
+ $val,
+ );
+ }
+
Class::MOP::Class->initialize(ref($instance))
->get_meta_instance
->get_slot_value($instance, $self->name);
--- /dev/null
+use strict;
+use warnings;
+
+use Scalar::Util 'reftype', 'blessed';
+
+use Test::More tests => 6;
+use Test::Exception;
+
+use Class::MOP;
+use Class::MOP::Attribute;
+use Class::MOP::Method;
+
+
+{
+ package Foo;
+ use metaclass;
+
+ Foo->meta->add_attribute(
+ bar => (
+ lazy => 1,
+ default => 'haha',
+ )
+ );
+ Foo->meta->add_attribute(
+ baz => (
+ lazy => 1,
+ builder => 'buildit',
+ )
+ );
+
+ sub buildit { 'built' }
+}
+
+{
+ use Devel::Sub::Which qw(:universal);
+
+ my $obj = Foo->meta->new_object();
+ my $attrs = $obj->meta->get_attribute_map();
+
+ my $bar_attr = $attrs->{bar};
+ ok(!$bar_attr->has_value($obj), '... $attr has not had value set');
+ is($bar_attr->get_value($obj), 'haha', '... $attr value is correct');
+ ok($bar_attr->has_value($obj), '... $attr has had value set');
+
+ my $baz_attr = $attrs->{baz};
+ ok(!$baz_attr->has_value($obj), '... $attr has not had value set');
+ is($baz_attr->get_value($obj), 'built', '... $attr value is correct');
+ ok($baz_attr->has_value($obj), '... $attr has had value set');
+}
+
+
+
+