basic return stack usage
Matt S Trout [Mon, 20 Jan 2014 12:25:53 +0000 (12:25 +0000)]
lib/DX/State.pm
t/basic.t

index 4815ab2..66287dd 100644 (file)
@@ -54,12 +54,28 @@ sub then {
   $self->new(%$self, next_op => $then);
 }
 
+sub select_next_op {
+  my ($self) = @_;
+  return $self->next_op || do {
+    if (my @stack = @{$self->return_stack}) {
+      my $top = pop @stack;
+      DX::Op::FromCode->new(
+        code => sub {
+          $_[1]->new(%{$_[1]}, return_stack => \@stack, next_op => $top)
+        }
+      );
+    } else {
+      undef;
+    }
+  };
+}
+
 sub run {
   my ($state) = @_;
   with_return {
     my ($return) = @_;
     local our $No_Options_Handler = $return;
-    while (my $op = $state->next_op) {
+    while (my $op = $state->select_next_op) {
       $state = $op->run($state);
     }
     return $state;
index 1655c85..d3c636a 100644 (file)
--- a/t/basic.t
+++ b/t/basic.t
@@ -105,4 +105,43 @@ is_deeply(
   'Complex stream'
 );
 
+my $call_op = FromCode->new(
+  code => sub {
+    my ($self, $state) = @_;
+    my @rst = @{$state->return_stack};
+    my $save_scope = $state->scope;
+    my %scope = (S => $save_scope->{S});
+    my $ret_op = FromCode->new(
+      code => sub { $_[1]->new(%{$_[1]}, scope => $save_scope, next_op => $_[0]->next) },
+      next => $self->next,
+    );
+    $state->new(%$state,
+      scope => \%scope,
+      return_stack => [ @rst, $ret_op ],
+      next_op => $op
+    );
+  },
+  next => FromCode->new(
+    code => bind_array(P => \@shells),
+    next => FromCode->new(
+      code => test_values([ qw(S P) ], sub { $shells{$_[1]}{$_[0]} }),
+    )
+  )
+);
+
+my $callstream = DX::ResultStream->new(
+  for_state => make_state([ qw(S P) ], $call_op)
+);
+
+is_deeply(
+  [ $callstream->results ],
+  [
+    { P => 'csh', S => 'jim.example.com' },
+    { P => 'csh', S => 'joe.example.com' },
+    { P => 'bash', S => 'joe.example.com' },
+    { P => 'csh', S => 'bob.example.com' },
+  ],
+  'Call stream'
+);
+
 done_testing;