pervasive type constraints
[scpubgit/DX.git] / lib / DX / ActionBuilder / BoundValue.pm
1 package DX::ActionBuilder::BoundValue;
2
3 use DX::Action::SetBoundValue;
4 use DX::Action::AddBoundValue;
5 use DX::Utils qw(:event_types);
6 use DX::Class;
7
8 with 'DX::Role::ActionBuilder';
9
10 has target_path => (is => 'ro', required => 1, isa => ValuePath);
11
12 has rebind_path => (is => 'ro', required => 1, isa => ValuePath);
13
14 has bound_to_path => (is => 'ro', required => 1, isa => ValuePath);
15
16 has inner_action_builder => (
17   is => 'ro', required => 1, isa => ActionBuilder
18 );
19
20 sub can_set_value { shift->inner_action_builder->can_set_value }
21
22 sub aperture_for_set_value {
23   my ($self) = @_;
24   return [] unless $self->can_set_value;
25   [
26     [ VALUE_SET ,=> @{$self->target_path} ],
27     @{$self->inner_action_builder->aperture_for_set_value},
28   ]
29 }
30
31 sub action_for_set_value {
32   my ($self, $value) = @_;
33   my $inner_action = $self->inner_action_builder->action_for_set_value($value);
34   return undef unless $inner_action;
35   DX::Action::SetBoundValue->new(
36     target_path => $self->target_path,
37     bound_to_path => $self->bound_to_path,
38     rebind_path => $self->rebind_path,
39     new_value => $value,
40     inner_action => $inner_action,
41   )
42 }
43
44 sub can_add_member { shift->inner_action_builder->can_add_member }
45
46 sub aperture_for_add_member {
47   my ($self, $at) = @_;
48   return [] unless $self->can_add_member;
49   [
50     [ VALUE_SET ,=> @{$self->target_path} ],
51     @{$self->inner_action_builder->aperture_for_add_member($at)},
52   ]
53 }
54
55 sub action_for_add_member {
56   my ($self, $at, $value) = @_;
57   $at = $at->string_value if ref($at);
58   my $inner_action = $self->inner_action_builder
59                           ->action_for_add_member($at, $value);
60   return undef unless $inner_action;
61   DX::Action::AddBoundValue->new(
62     target_path => [ @{$self->target_path}, $at ],
63     bound_to_path => [ @{$self->bound_to_path}, $at ],
64     rebind_path => $self->rebind_path,
65     new_value => $value,
66     inner_action => $inner_action
67   );
68 }
69
70 sub apply_to_value {
71   my ($self, $value, $inner_value) = @_;
72   my $new_value = $value->but_set_action_builder($self);
73   return $new_value unless $new_value->isa('DX::Value::Dict');
74   my %m = %{$new_value->members};
75   return $new_value->but(
76     members => {
77       map {
78         my $this_inner = $inner_value->get_member_at($_);
79         ($_ => $self->but(
80                  target_path => [ @{$self->target_path}, $_ ],
81                  bound_to_path => [ @{$self->bound_to_path}, $_ ],
82                  inner_action_builder => $this_inner->action_builder,
83                )->apply_to_value($m{$_}, $this_inner))
84       } keys %m
85     },
86   );
87 }
88
89 1;