refactor action stuff to be recursive on dicts
Matt S Trout [Sat, 12 Mar 2016 11:13:37 +0000 (11:13 +0000)]
lib/DX/Action/SetBoundValue.pm
lib/DX/ActionBuilder/BoundValue.pm
lib/DX/ActionBuilder/Normal.pm
lib/DX/ActionBuilder/UnsetValue.pm

index 5771eb7..614ec36 100644 (file)
@@ -7,6 +7,8 @@ with 'DX::Role::Action';
 
 has target_path => (is => 'ro', required => 1);
 
+has bound_to_path => (is => 'ro', required => 1);
+
 has rebind_path => (is => 'ro', required => 1);
 
 has new_value => (is => 'ro', required => 1);
@@ -20,10 +22,22 @@ sub dry_run {
       action_applications => [ @{$hyp->action_applications}, $self ],
     ),
   );
+  my $new_bound_to = do {
+    my $targ = $outer_hyp->scope;
+    $targ = $targ->get_member_at($_) for @{$self->bound_to_path};
+    $targ;
+  };
+  my $new_ab = DX::ActionBuilder::BoundValue->new(
+    target_path => $self->target_path,
+    rebind_path => $self->rebind_path,
+    bound_to_path => $self->bound_to_path,
+    inner_action_builder => $new_bound_to->action_builder
+  );
+  my $value_with_ab = $new_ab->apply_to_value($self->new_value, $new_bound_to);
   my ($scope, @events) = $outer_hyp->scope->apply_updates(
                            DX::Update::SetValue->new(
                              target_path => $self->target_path,
-                             new_value => $self->new_value,
+                             new_value => $value_with_ab,
                            )
                          );
   my $new_bound = do {
index 8454992..9138dbe 100644 (file)
@@ -20,11 +20,31 @@ sub action_for_set_value {
   return undef unless $inner_action;
   DX::Action::SetBoundValue->new(
     target_path => $self->target_path,
+    bound_to_path => $self->bound_to_path,
     rebind_path => $self->rebind_path,
-    new_value => $value->but_set_action_builder($self)
-                       ->but_set_identity_path($self->bound_to_path),
+    new_value => $value,
     inner_action => $inner_action,
   )
 }
 
+sub apply_to_value {
+  my ($self, $value, $inner_value) = @_;
+  my $new_value = $value->but_set_action_builder($self)
+                        ->but_set_identity_path($inner_value->identity_path);
+  return $new_value unless $new_value->isa('DX::Value::Dict');
+  my %m = %{$new_value->members};
+  return $new_value->but(
+    members => {
+      map {
+        my $this_inner = $inner_value->get_member_at($_);
+        ($_ => $self->but(
+                 target_path => [ @{$self->target_path}, $_ ],
+                 bound_to_path => [ @{$self->bound_to_path}, $_ ],
+                 inner_action_builder => $this_inner->action_builder,
+               )->apply_to_value($m{$_}, $this_inner))
+      } keys %m
+    },
+  );
+}
+
 1;
index c950758..45e5abd 100644 (file)
@@ -12,22 +12,43 @@ sub action_for_set_value {
   my ($self, $value) = @_;
   DX::Action::SetValue->new(
     target_path => $self->target_path,
-    new_value => $value->but_set_action_builder($self)
-                       ->but_set_identity_path($self->target_path)
+    new_value => $self->apply_to_value($value),
   );
 }
 
 sub action_for_add_member {
   my ($self, $at, $value) = @_;
-  my @add_path = (@{$self->target_path}, ref($at) ? $at->string_value : $at);
+  my $ab = $self->specialize_for_member($at);
   DX::Action::AddValue->new(
-    target_path => \@add_path,
-    new_value => $value->but_set_action_builder(
-                   $self->but(target_path => \@add_path)
-                 )->but_set_identity_path(\@add_path)
+    target_path => $ab->target_path,
+    new_value => $ab->apply_to_value($value),
   );
 }
 
 sub action_for_remove_member { die 'WHUT' }
 
+sub apply_to_value {
+  my ($self, $value) = @_;
+  my $new_value = $value->but_set_action_builder($self)
+                        ->but_set_identity_path($self->target_path);
+  return $new_value unless $new_value->isa('DX::Value::Dict');
+  my %m = %{$new_value->members};
+  return $new_value->but(
+    members => {
+      map +($_ => $self->specialize_for_member($_)->apply_to_value($m{$_})),
+        keys %m,
+    },
+  );
+}
+
+sub specialize_for_member {
+  my ($self, $at) = @_;
+  $self->but(
+    target_path => [
+      @{$self->target_path},
+      (ref($at) ? $at->string_value : $at)
+    ],
+  );
+}
+
 1;
index acc9306..95eecf5 100644 (file)
@@ -21,17 +21,12 @@ sub action_for_set_value {
     );
     return DX::Action::BindValue->new(
       target_path => $self->target_path,
-      new_value => $value->but_set_action_builder($ab),
+      new_value => $ab->apply_to_value($value, $value),
     )
   }
-  my $ab = DX::ActionBuilder::Normal->new(
+  DX::ActionBuilder::Normal->new(
     target_path => $self->target_path,
-  );
-  DX::Action::SetValue->new(
-    target_path => $self->target_path,
-    new_value => $value->but_set_action_builder($ab)
-                       ->but_set_identity_path($self->target_path),
-  );
+  )->action_for_set_value($value);
 }
 
 1;