Parent

Class/Module Index [+]

Quicksearch

Ruote::Exp::CursorExpression

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

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).

: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

Public Instance Methods

apply() click to toggle source
# File lib/ruote/exp/fe_cursor.rb, line 206
def apply

  move_on
end

Protected Instance Methods

is_loop?() click to toggle source
# File lib/ruote/exp/fe_cursor.rb, line 239
def is_loop?

  name == 'loop' || name == 'repeat'
end
jump_to(workitem, position, arg) click to toggle source

Jumps to an integer position, or the name of an expression or a tag name of a ref name.

# File lib/ruote/exp/fe_cursor.rb, line 247
def jump_to (workitem, position, arg)

  pos = Integer(arg) rescue nil

  return pos if pos != nil

  tree_children.each_with_index do |c, i|

    exp_name = c[0]
    ref = c[1]['ref']
    tag = c[1]['tag']

    ref = Ruote.dosub(ref, self, workitem) if ref
    tag = Ruote.dosub(tag, self, workitem) if tag

    next if exp_name != arg && ref != arg && tag != arg

    pos = i
    break
  end

  pos ? pos : position
end
move_on(workitem=h.applied_workitem) click to toggle source
# File lib/ruote/exp/fe_cursor.rb, line 213
def move_on (workitem=h.applied_workitem)

  position = workitem['fei'] == h.fei ?
    -1 : Ruote::FlowExpressionId.child_id(workitem['fei'])

  position += 1

  com, arg = get_command(workitem)

  return reply_to_parent(workitem) if com == 'break'

  case com
    when 'rewind', 'continue' then position = 0
    when 'skip' then position += arg
    when 'jump' then position = jump_to(workitem, position, arg)
  end

  position = 0 if position >= tree_children.size && is_loop?

  if position < tree_children.size
    apply_child(position, workitem)
  else
    reply_to_parent(workitem)
  end
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.