Class: Ruote::Exp::CursorExpression

Inherits:
CommandedExpression show all
Defined in:
lib/ruote/exp/fe_cursor.rb

Overview

This class implements the 'cursor' and the 'repeat' (loop) expressions.

The cursor expression is a kind of enhanced 'sequence'. Like a sequence it will execute its child expression one by one, sequentially. Unlike a sequence though, it will obey 'commands'.

cursor do
  author
  reviewer
  rewind :if => '${f:not_ok}'
  publisher
end

In this simplistic example, the process will flow from author to reviewer and back until the reviewer sets the workitem field 'not_ok' to something else than the value 'true'.

There are two ways to pass commands to a cursor either directly from the process definition with a cursor command expression, either via the workitem '__command__' [special] field.

cursor commands

The commands that a cursor understands are listed here. The most powerful ones are 'rewind' and 'jump'.

rewind

Rewinds the cursor up to its first child expression.

cursor do
  author
  reviewer
  rewind :if => '${f:not_ok}'
  publisher
end

reset

Whereas 'rewind' places the cursor back to the initial step with the current workitem, 'reset' will rewind it and start again but with the workitem as it was when it reached the cursor/repeat.

stop, over & break

Exits the cursor.

cursor do
  author
  reviewer
  rewind :if => '${f:review} == fix'
  stop :if => '${f:review} == abort'
  publisher
end

'_break' or 'over' can be used instead of 'stop'.

skip & back

Those two commands jump forth and back respectively. By default, they skip 1 child, but they accept a numeric parameter holding the number of children to skip.

cursor do
  author
  reviewer
  rewind :if => '${f:review} == fix'
  skip 2 :if => '${f:review} == publish'
  reviewer2
  rewind :if => '${f:review} == fix'
  publisher
end

jump

Jump is probably the most powerful of the cursor commands. It allows to jump to a specified expression that is a direct child of the cursor.

cursor do
  author
  reviewer
  jump :to => 'author', :if => '${f:review} == fix'
  jump :to => 'publisher', :if => '${f:review} == publish'
  reviewer2
  jump :to => 'author', :if => '${f:review} == fix'
  publisher
end

Note that the :to accepts the name of an expression or the value of its :ref attribute or the value of its :tag attribute.

cursor do
  participant :ref => 'author'
  participant :ref => 'reviewer'
  jump :to => 'author', :if => '${f:review} == fix'
  participant :ref => 'publisher'
end

cursor command with :ref

It's OK to tag a cursor/repeat/loop with the :tag attribute and then point a command to it via :ref :

concurrence do

  cursor :tag => 'main' do
    author
    editor
    publisher
  end

  # meanwhile ...

  sequence do
    sponsor
    rewind :ref => 'main', :if => '${f:stop}'
  end
end

This :ref technique may also be used with nested cursor/loop/iterator constructs :

cursor :tag => 'main' do
  cursor do
    author
    editor
    rewind :if => '${f:not_ok}'
    _break :ref => 'main', :if => '${f:abort_everything}'
  end
  head_of_edition
  rewind :if => '${f:not_ok}'
  publisher
end

this example features two nested cursors. There is a “_break” in the inner cursor, but it will break the main 'cursor' (and thus break the whole review process).

cursor command in the workitem

The command expressions are merely setting the workitem field '__command__' with an array value [ command, arg ].

For example,

jump :to => 'author'
  # is equivalent to
set 'field:__command__' => 'author'

It is entirely OK to have a participant implementation that sets __command__ by itself.

class Reviewer
  include Ruote::LocalParticipant

  def consume(workitem)
    # somehow review the book
    if review == 'bad'
      #workitem.fields['__command__'] = [ 'rewind' ] # old style
      workitem.command = 'rewind' # new style
    else
      # let it go
    end
    reply_to_engine(workitem)
  end

  def cancel(fei, flavour)
    # cancel if review is still going on...
  end
end

This example uses the Ruote::Workitem#command= method which can be fed strings like 'rewind', 'skip 2', 'jump to author' or the equivalent arrays [ 'rewind' ], [ 'skip', 2 ], [ 'jump', 'author' ].

:break_if / :rewind_if

As an attribute of the cursor/repeat expression, you can set a :break_if. It tells the cursor (loop) if it has to break.

cursor :break_if => '${f:completed}' do
  participant 'alpha'
  participant 'bravo'
  participant 'charly'
end

If alpha or bravo replies and the field 'completed' is set to true, this cursor will break.

:break_unless is accepted. :over_if and :over_unless are synonyms for :break_if and :break_unless respectively.

:rewind_if / :rewind_unless behave the same, but the cursor/loop, instead of breaking, is put back in its first step.

repeat (loop)

A 'cursor' expression exits implicitely as soon as its last child replies to it. a 'repeat' expression will apply (again) the first child after the last child replied. A 'break' cursor command might be necessary to exit the loop (or a cancel_process, but that exits the whole process instance).

sequence do
  repeat do
    author
    reviewer
    _break :if => '${f:review} == ok'
  end
  publisher
end

Constant Summary

Constant Summary

Constants included from CommandMixin

Ruote::Exp::CommandMixin::ATT_COMMANDS, Ruote::Exp::CommandMixin::F_COMMAND

Constants inherited from FlowExpression

FlowExpression::COMMON_ATT_KEYS

Instance Attribute Summary

Attributes inherited from FlowExpression

#context, #error

Instance Method Summary collapse

Methods inherited from CommandedExpression

#reply

Methods inherited from FlowExpression

#ancestor?, #applied_workitem, #att, #att_text, #attribute, #attribute_text, #attributes, #await, #cancel, #cancel_flanks, #cfei_at, #child_id, #child_ids, #compile_atts, #compile_variables, #debug_id, #deflate, #do, do_action, #do_apply, #do_cancel, #do_fail, #do_pause, #do_persist, #do_reply, #do_reply_to_parent, #do_resume, #do_unpersist, dummy, #fei, fetch, from_h, #handle_on_error, #has_attribute, #initial_persist, #initialize, #is_concurrent?, #iterative_var_lookup, #launch_sub, #lookup_val, #lookup_val_prefix, #lookup_variable, #name, names, #parent, #parent_id, #pause_on_apply, #persist_or_raise, #reply, #reply_to_parent, #root, #root_id, #set_variable, #tree, #tree_children, #try_persist, #try_unpersist, #unpersist_or_raise, #unset_variable, #update_tree, #variables, #wfid

Methods included from WithMeta

#class_def, included

Methods included from WithH

#h, #h=, included, #to_h

Constructor Details

This class inherits a constructor from Ruote::Exp::FlowExpression

Instance Method Details

#applyObject



250
251
252
253
# File 'lib/ruote/exp/fe_cursor.rb', line 250

def apply

  move_on
end