my $simple = $self->_generate_simple_get('$_[0]', $name);
my ($lazy, $default, $builder) = @{$spec}{qw(lazy default builder)};
return $simple unless $lazy and ($default or $builder);
- 'do { '.$self->_generate_default(
- '$_[0]', $name, $default, $builder,
+ 'do { '.$self->_generate_use_default(
+ '$_[0]', $name, $spec,
$self->_generate_simple_has('$_[0]', $name),
).'; '.$simple.' }';
}
"exists ${me}->{${\perlstring $name}}";
}
-sub _generate_default {
- my ($self, $me, $name, $default, $builder, $test) = @_;
+sub generate_get_default {
+ my $self = shift;
+ local $self->{captures} = {};
+ my $code = $self->_generate_get_default(@_);
+ return ($code, $self->{captures});
+}
+
+sub _generate_use_default {
+ my ($self, $me, $name, $spec, $test) = @_;
$self->_generate_simple_set(
- $me, $name, (
- $default
- ? $self->_generate_call_code($name, 'default', $me, $default)
- : "${me}->${builder}"
- )
+ $me, $name, $self->_generate_get_default($me, $name, $spec)
).' unless '.$test;
}
+sub _generate_get_default {
+ my ($self, $me, $name, $spec) = @_;
+ $spec->{default}
+ ? $self->_generate_call_code($name, 'default', $me, $spec->{default})
+ : "${me}->${\$spec->{builder}}"
+}
+
sub generate_simple_get {
shift->_generate_simple_get(@_);
}
return "${cap_name}->(${values})";
}
+sub generate_simple_set {
+ my $self = shift;
+ local $self->{captures} = {};
+ my $code = $self->_generate_simple_set(@_);
+ return ($code, $self->{captures});
+}
+
sub _generate_simple_set {
my ($self, $me, $name, $value) = @_;
my $name_str = perlstring $name;
NAME: foreach my $name (sort keys %$spec) {
my $attr_spec = $spec->{$name};
next NAME unless defined(my $i = $attr_spec->{init_arg});
- if ($attr_spec->{lazy}) {
+ if ($attr_spec->{lazy} or $attr_spec->{default} or $attr_spec->{builder}) {
$test{$name} = $i;
next NAME;
}
push @init, $i;
push @slots, $name;
}
- return '' unless @init;
+ return '' unless @init or %test;
join '', (
@init
? ' @{$new}{qw('.join(' ',@slots).')}'
: ''
), map {
my $arg_key = perlstring($test{$_});
- " \$new->{${\perlstring($_)}} = \$args->{$arg_key}\n"
- ." if exists \$args->{$arg_key};\n"
+ my $ag = $self->accessor_generator;
+ my $test = "exists \$args->{$arg_key}";
+ my $source = "\$args->{$arg_key}";
+ my $attr_spec = $spec->{$_};
+ my ($code, $add_captures);
+ if (!$attr_spec->{lazy} and
+ ($attr_spec->{default} or $attr_spec->{builder})) {
+ my $get_captures;
+ ($code, $add_captures) = $ag->generate_simple_set(
+ '$new', $_,
+ "(\n ${test}\n ? ${source}\n : "
+ .do {
+ (my $get, $get_captures) = $ag->generate_get_default(
+ '$new', $_, $attr_spec
+ );
+ $get;
+ }
+ ."\n )"
+ );
+ @{$add_captures}{keys %$get_captures} = values %$get_captures;
+ $code .= ";\n";
+ } else {
+ ($code, $add_captures) = $ag->generate_simple_set(
+ '$new', $_, "\$args->{$arg_key}"
+ );
+ $code .= " if ${test};\n";
+ }
+ @{$self->{captures}}{keys %$add_captures} = values %$add_captures;
+ ' '.$code;
} sort keys %test;
}
$name, "\$args->{${init_str}}", $isa
);
@{$captures}{keys %$add_captures} = values %$add_captures;
- $check .= " ${code} if exists \$args->{${init_str}};\n";
+ $check .= " ${code}".(
+ (not($spec->{lazy}) and ($spec->{default} or $spec->{builder})
+ ? ";\n"
+ : "if exists \$args->{${init_str}};\n"
+ )
+ );
}
return $check;
}
has two => (is => 'ro', lazy => 1, builder => '_build_two');
sub _build_two { {} }
has three => (is => 'ro', default => quote_sub q{ {} });
- has four => (is => 'ro', default => '_build_four');
+ has four => (is => 'ro', builder => '_build_four');
sub _build_four { {} }
}
check two => map Foo->new->two, 1..2;
+check three => map Foo->new->{three}, 1..2;
+
+check four => map Foo->new->{four}, 1..2;
+
done_testing;