Class: Ruote::Exp::SubprocessExpression

Inherits:
FlowExpression show all
Defined in:
lib/ruote/exp/fe_subprocess.rb

Overview

An expression for invoking a subprocess.

pdef = Ruote.process_definition do
  sequence do
    subprocess :ref => 'delivering'
    subprocess 'invoicing'
    refill_stock :if => '${v:stock_size} < 10'
  end
  define 'delivering' do
    # ...
  end
  define 'invoicing' do
    # ...
  end
  define 'refill_stock' do
    # ...
  end
end

passing attributes as variables

The attributes of the subprocess expression are passed as variables of the new subprocess instance.

Ruote.define do
  subprocess 'sub0', :a => 'A', :b => 'B'
  define :sub0 do
    echo '${v:a}:${v:b}'
  end
end

This example (and useless) process example will output “A:B” to STDOUT.

Ruote.define :name => 'whatever' do

  call :who => 'the cops', :when => 'if I\'m not back at 3'

  define 'call' do
    participant :ref => '${v:who}', :msg => 'this is a call'
  end
end

This binds the variables 'who' and 'when' in the subprocess instance.

Of course you can combine parameters and blocks passing.

Using a “f:” or “field:” prefix is OK to pass arguments as workitem fields instead of process variables:

Ruote.define do
  set 'address' => { 'city' => 'boston' }
  sub0(
    'f:a' => 'fa',
    'field:b' => 'mi',
    'var:c' => 'sol',
    'f:address.city' => 'nyc')
  define 'sub0' do
    echo '${a} ${b} ${v:c} ${address.city}'
  end
end
  #
  # will output 'fa mi sol nyc'

passing 'blocks' to subprocesses

When the subprocess expression has children, the first of them is passed to the subprocess instance as the 'tree' variable, readily available for an 'apply' expression.

Ruote.process_definition :name => 'double review' do
  sequence do
    sub0 do
      review_board
    end
    sub0 do
      review_board
    end
  end
  define 'sub0' do
    concurrence do
      apply :i => 0
      apply :i => 1
      apply :i => 2
    end
  end
end

This example will send 2 x 3 concurrent workitems to the participant named 'review_board' (note that it could also be the name of another subprocess).

pointing to subprocesses via their URI

It's OK to invoke subprocesses via a URI

subprocess :ref => 'pdefs/definition1.rb'

or

subprocess :ref => 'http://pdefs.example.org/account/def1.xml'

Remember that the 'remote_definition_allowed' option of the engine has to be set to true for the latter to work, else the engine will refuse to load definitions over HTTP.

Shorter :

subprocess 'http://pdefs.example.org/account/def1.xml'

subprocess URIs bound at engine level

There is a class of variables accessible to process instances in read-only mode : engine level variables.

They can be set via the engine's initialization code (or later) like in this example :

engine.variables['inventory_check'] = 'http://pdefs.example.com/ic0.rb'

All the process instance in the engine may then trigger this process in these 3 ways :

subprocess :ref => 'inventory_check'
subprocess 'inventory_check'
inventory_check

The latter may make process definitions quite readable (but blur the distinction between expressions, call to participants or to subprocesses).

subprocess trees bound at engine level

It's OK to place a process tree directly in an engine variable :

engine.variables['inventory_check'] = Ruote.process_definition do
  cursor do
    manager :task => 'hire inventory team'
    floor_manager :task => 'lead inventory'
    manager :task => 'check results'
    rewind :unless => '${inventory_successful}'
  end
end

Then, from the main process :

sequence do
  # ...
  inventory_check
  # ...
end

Constant Summary

Constants inherited from FlowExpression

FlowExpression::COMMON_ATT_KEYS

Instance Attribute Summary

Attributes inherited from FlowExpression

#context, #error

Instance Method Summary collapse

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


190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/ruote/exp/fe_subprocess.rb', line 190

def apply

  return invoke_engine_participant if attribute(:engine)

  ref = attribute(:ref) || attribute_text

  raise "no subprocess referred in #{tree}" unless ref

  pos, subtree = Ruote.lookup_subprocess(self, ref)

  fs, vs = compile_atts.partition { |k, v| k.match(/^f(ield)?:./) }

  fields = h.applied_workitem['fields']
  fs.each { |k, v| Ruote.set(fields, k.split(':', 2).last, v) }

  vars = Hash[vs.collect { |k, v| [ k.split(':', 2).last, v ] }]

  vars.merge!('tree' => tree_children.first)
    # NOTE : we're taking the first child here...

  launch_sub(pos, subtree, :variables => vars)
end