use Moo;
our @RULES = (
- [ has_action => [ qw(Thing Action) ],
- [ prop => 'Thing', \'required_action', 'Action' ] ],
[ path_status => [ qw(PS) ],
[ member_of => 'PS', \'path_status' ] ],
[ path => [ qw(PS P) ],
--- /dev/null
+package DX::Op::HasAction;
+
+use Safe::Isa;
+use Moo;
+
+has arg_spec => (is => 'ro', required => 1);
+
+with 'DX::Role::Op';
+
+sub run {
+ my ($self, $state) = @_;
+ my @arg_spec = @{$self->arg_spec};
+ ($state, my %vars) = $self->_expand_args(
+ $state, Thing => $arg_spec[0], Action => $arg_spec[1]
+ );
+ die "Thing must be bound" unless $vars{Thing}->is_bound;
+ my $thing = $state->resolve_value($vars{Thing});
+ if ($thing->$_does('DX::Role::Fact') and $thing->has_required_action) {
+ return $state->bind_value(
+ $vars{Action}->id,
+ $state->actions->{$thing->required_action}
+ )->add_dependencies($vars{Action}->id => $vars{Thing}->id)
+ ->then($self->next);
+ }
+ return $state->backtrack;
+}
+
+1;
package DX::Op::ModifyAction;
+use Safe::Isa;
use DX::ObservationRequired;
use Moo;
my ($self, $state) = @_;
($state, my %args) = $self->_expand_args($state, %{$self->_arg_map});
my ($subject, @vars) = @args{sort keys %args};
- die "Can't alter action on $subject" unless
- my $orig_action = $state->resolve_value($subject)->required_action;
+ my $subject_fact = $state->resolve_value($subject);
+ die "Subject not a fact" unless $subject_fact->$_does('DX::Role::Fact');
+ die "Subject has no action" unless $subject_fact->has_required_action;
+ my $orig_action = $state->actions->{$subject_fact->required_action};
my @deps = $state->action_dependencies(
@{$orig_action->dependencies},
map $_->id, @vars
my $action = $self->builder->(@builder_args)
->but(dependencies => \@deps);
my ($fact_type, $value) = $action->expected_effect;
- my $final_value = $value->but(required_action => $action);
+ my $final_value = $value->but(required_action => $action->id);
my $fact_set = $state->facts->{$fact_type}->with_value($final_value);
- $state->but(facts => { %{$state->facts}, $fact_type => $fact_set })
+ $state->but(
+ facts => { %{$state->facts}, $fact_type => $fact_set },
+ actions => { %{$state->actions}, $action->id => $action },
+ )
->then($self->next);
}
my @deps = $state->action_dependencies(map $_->id, @vars);
my $action = $self->builder->(map $state->resolve_value($_), @vars)
->but(dependencies => \@deps);
+ my ($rec_state, $action_id) = $state->record_action($action);
my ($fact_type, $value) = $action->expected_effect;
- my $final_value = $value->but(required_action => $action);
+ my $final_value = $value->but(required_action => $action_id);
my $fact_set = $state->facts->{$fact_type}->with_value($final_value);
- $state->but(facts => { %{$state->facts}, $fact_type => $fact_set })
- ->then($self->next);
+ $rec_state->but(facts => { %{$state->facts}, $fact_type => $fact_set })
+ ->then($self->next);
}
1;
sub actions {
my ($self) = @_;
my $state = $self->_state;
- my $by_id = $self->_state->by_id;
- return map $_->required_action,
- grep $_->has_required_action,
- grep $_->$_does('DX::Role::Fact'),
- map $state->resolve_value($_),
- values %$by_id;
+ my $actions = $state->actions;
+ my @act = @{$actions}{sort keys %$actions};
+ return @act; # separate array to get correct scalar context return
}
sub independent_actions {
use Moo::Role;
+has id => (is => 'ro');
+
has dependencies => (is => 'ro', default => sub { [] });
has was_run => (is => 'rw');
use DX::Op::Prop;
use DX::Op::Exists;
use DX::Op::Predicate;
+use DX::Op::HasAction;
use List::Util qw(reduce);
has rules => (is => 'ro', default => sub { {} });
);
}
+sub _expand_op_has_action {
+ my ($self, @args) = @_;
+ DX::Op::HasAction->new(arg_spec => \@args);
+}
+
1;
has dependencies => (is => 'ro', default => sub { {} });
+has actions => (is => 'ro', default => sub { {} });
+
sub scope_var {
my ($self, $name) = @_;
$self->by_id->{$self->scope->{$name}};
), %vars;
}
+sub record_action {
+ my ($self, $action) = @_;
+ my %id_gen = %{$self->id_gen};
+ my ($type) = (ref($action) =~ /([^:]+)$/);
+ my $id = join('_', $type, ++($id_gen{$type}||='000'));
+ my $recorded = $action->but(id => $id);
+ $self->but(
+ id_gen => \%id_gen,
+ actions => { %{$self->actions}, $id => $recorded }
+ ), $id;
+}
+
sub assign_vars {
my ($self, %vars) = @_;
my ($state, %expanded) = $self->expand_vars(%vars);
while (my $id = shift @queue) {
$seen{$id}++;
my $value = $self->resolve_value($by_id->{$id});
- push @found, $id if $value->$_does('DX::Role::Fact')
- and $value->has_required_action;
+ push @found, $value if $value->$_does('DX::Role::Fact')
+ and $value->has_required_action;
push @queue, grep !$seen{$_}, keys %{$deps->{$id}};
}
- return @found;
+ return map $_->required_action, @found;
}
sub copy_vars {