working lazy default and builder
Matt S Trout [Sun, 7 Nov 2010 10:53:50 +0000 (10:53 +0000)]
lib/Method/Generate/Accessor.pm
lib/Method/Generate/Constructor.pm
t/accessor-default.t [new file with mode: 0644]

index c9b9dd5..6a0326b 100644 (file)
@@ -12,7 +12,7 @@ sub generate_method {
   local $self->{captures} = {};
   my $body = do {
     if ($is eq 'ro') {
-      $self->_generate_get($name)
+      $self->_generate_get($name, $spec)
     } elsif ($is eq 'rw') {
       $self->_generate_getset($name, $spec)
     } else {
@@ -26,8 +26,30 @@ sub generate_method {
 }
 
 sub _generate_get {
-  my ($self, $name) = @_;
-  $self->_generate_simple_get('$_[0]', $name);
+  my ($self, $name, $spec) = @_;
+  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,
+    $self->_generate_simple_has('$_[0]', $name),
+  ).'; '.$simple.' }';
+}
+
+sub _generate_simple_has {
+  my ($self, $me, $name) = @_;
+  "exists ${me}->{${\perlstring $name}}";
+}
+
+sub _generate_default {
+  my ($self, $me, $name, $default, $builder, $test) = @_;
+  $self->_generate_simple_set(
+    $me, $name, (
+      $default
+        ? $self->_generate_call_code($name, 'default', $me, $default)
+        : "${me}->${builder}"
+    )
+  ).' unless '.$test;
 }
 
 sub generate_simple_get {
@@ -42,7 +64,7 @@ sub _generate_simple_get {
 
 sub _generate_set {
   my ($self, $name, $value, $spec) = @_;
-  my $simple = $self->_generate_simple_set($name, $value);
+  my $simple = $self->_generate_simple_set('$_[0]', $name, $value);
   my ($trigger, $isa_check) = @{$spec}{qw(trigger isa)};
   return $simple unless $trigger or $isa_check;
   my $code = 'do {';
@@ -105,9 +127,9 @@ sub _generate_call_code {
 }
 
 sub _generate_simple_set {
-  my ($self, $name, $value) = @_;
+  my ($self, $me, $name, $value) = @_;
   my $name_str = perlstring $name;
-  "\$_[0]->{${name_str}} = ${value}";
+  "${me}->{${name_str}} = ${value}";
 }
 
 sub _generate_getset {
index 8e2b6b8..de3111f 100644 (file)
@@ -58,18 +58,28 @@ sub _generate_args {
 
 sub _assign_new {
   my ($self, $spec) = @_;
-  my (@init, @slots);
-  NAME: foreach my $name (keys %$spec) {
+  my (@init, @slots, %test);
+  NAME: foreach my $name (sort keys %$spec) {
     my $attr_spec = $spec->{$name};
-    push @init, do {
-      next NAME unless defined(my $i = $attr_spec->{init_arg});
-      $i;
-    };
+    next NAME unless defined(my $i = $attr_spec->{init_arg});
+    if ($attr_spec->{lazy}) {
+      $test{$name} = $i;
+      next NAME;
+    }
+    push @init, $i;
     push @slots, $name;
   }
   return '' unless @init;
-  '    @{$new}{qw('.join(' ',@slots).')} = @{$args}{qw('.join(' ',@init).')};'
-    ."\n";
+  join '', (
+    @init
+      ? '    @{$new}{qw('.join(' ',@slots).')}'
+        .' = @{$args}{qw('.join(' ',@init).')};'."\n"
+      : ''
+  ), map {
+    my $arg_key = perlstring($test{$_});
+    "    \$new->{${\perlstring($_)}} = \$args->{$arg_key}\n"
+    ."      if exists \$args->{$arg_key};\n"
+  } sort keys %test;
 }
 
 sub _check_required {
diff --git a/t/accessor-default.t b/t/accessor-default.t
new file mode 100644 (file)
index 0000000..af6e448
--- /dev/null
@@ -0,0 +1,30 @@
+use strictures 1;
+use Test::More;
+
+{
+  package Foo;
+
+  use Sub::Quote;
+  use Class::Tiny;
+
+  has one => (is => 'ro', lazy => 1, default => quote_sub q{ {} });
+  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');
+  sub _build_four { {} }
+}
+
+sub check {
+  my ($attr, @h) = @_;
+
+  is_deeply($h[$_], {}, "${attr}: empty hashref \$h[$_]") for 0..1;
+
+  isnt($h[0],$h[1], "${attr}: not the same hashref");
+}
+
+check one => map Foo->new->one, 1..2;
+
+check two => map Foo->new->two, 1..2;
+
+done_testing;