lib/ruote/exp/fe_await.rb in ruote-2.3.0.1 vs lib/ruote/exp/fe_await.rb in ruote-2.3.0.2
- old
+ new
@@ -1,7 +1,7 @@
#--
-# Copyright (c) 2005-2012, John Mettraux, jmettraux@gmail.com
+# Copyright (c) 2005-2013, John Mettraux, jmettraux@gmail.com
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
@@ -210,63 +210,73 @@
# # workitem = incoming.merge(awaiting)
#
# Note: the :where guard is always about the event's workitem (not the
# workitem as it reached the 'await' expression).
#
+ #
+ # == note: the "await" attribute
+ #
+ # (since ruote 3.2.1)
+ #
+ # "listen" and "await" are both ruote expressions. There is also an
+ # attribute common to all the expressions: :await.
+ #
+ # concurrence do
+ # sequence do
+ # alice
+ # sequence :tag => 'stage2' do
+ # bob
+ # end
+ # end
+ # sequence do
+ # charly
+ # diana :await => 'left_tag:stage2'
+ # eliza
+ # end
+ # frank
+ # end
+ #
+ # The expressions with an await attribute suspends its application until
+ # the awaited event happens.
+ #
+ # This await attribute, defaults to "left_tag:", so
+ #
+ # diana :await => 'stage2'
+ # # is equivalent to
+ # diana :await => 'left_tag:stage2'
+ #
class AwaitExpression < FlowExpression
names :await
- INS = %w[ in entered reached]
- OUTS = %w[ out left ]
-
- SPLIT_R = /^(#{(INS + OUTS).join('|')})_(tag|participant)s?$/
- SINGLE_R = /^(tag)s|(participant|error)s?$/ # not 'tag' alone
-
def apply
#
# gathering info
- direction, type, value = attributes.collect { |k, v|
- if m = SPLIT_R.match(k)
- [ m[1], m[2], v ]
- elsif m = SINGLE_R.match(k)
- [ 'in', m[1] || m[2], v ]
- else
- nil
- end
- }.compact.first
+ action, condition = self.class.extract_await_ac(attributes)
raise ArgumentError.new(
"couldn't determine which event to listen to from: " +
attributes.inspect
- ) unless direction
+ ) unless action
global = (attribute(:global).to_s == 'true')
- global = false if type == 'error'
+ global = false if action == 'error_intercepted'
h.amerge = attribute(:merge).to_s
- action = if type == 'tag'
- INS.include?(direction) ? 'entered_tag' : 'left_tag'
- elsif type == 'participant'
- INS.include?(direction) ? 'dispatch' : 'receive'
- else # error
- 'error_intercepted'
- end
-
persist_or_raise
#
# adding a new tracker
@context.tracker.add_tracker(
global ? nil : h.fei['wfid'],
action,
Ruote.to_storage_id(h.fei),
- determine_condition(type, value),
+ condition,
{ 'action' => 'reply',
'fei' => h.fei,
'workitem' => 'replace',
'flavour' => 'await' })
end
@@ -282,16 +292,17 @@
#
# merge
wi = h.applied_workitem.dup
- wi['fields'] = case h.amerge
- when 'ignore', 'drop' then wi['fields']
- when 'incoming' then wi['fields'].merge(workitem['fields'])
- when 'awaiting' then workitem['fields'].merge(wi['fields'])
- else workitem['fields'] # 'override'
- end
+ wi['fields'] =
+ case h.amerge
+ when 'ignore', 'drop' then wi['fields']
+ when 'incoming' then wi['fields'].merge(workitem['fields'])
+ when 'awaiting' then workitem['fields'].merge(wi['fields'])
+ else workitem['fields'] # 'override'
+ end
#
# actual trigger
if tree_children.any?
@@ -321,37 +332,75 @@
@context.tracker.remove_tracker(h.fei)
super(workitem)
end
- # Matches Ruby class names, like "Ruote::ForcedError" or "::ArgumentError"
- #
- KLASS_R = /^(::)?([A-Z][a-z]+)+(::([A-Z][a-z]+)+)*$/
+ INS = %w[ in entered reached ]
+ OUTS = %w[ out left ]
- # Builds the condition used by the tracker service to filter msgs.
+ SPLIT_R =
+ /^(?:(#{(INS + OUTS).join('|')})_)?(tag|participant|error)s?$/
+
+ # attribute wait regex
+ AAWAIT_R =
+ /^(?:(#{(INS + OUTS).join('|')})_)?(tag|participant)s?\s*:\s*(.+)$/
+
+ # matches Ruby class names, like "Ruote::ForcedError" or "::ArgumentError"
+ KLASS_R =
+ /^(::)?([A-Z][a-z]+)+(::([A-Z][a-z]+)+)*$/
+
+ # Made into a class method, so that the :await common attribute can
+ # use it when parsing :await...
#
- def determine_condition(type, value)
+ def self.extract_await_ac(atts)
+ direction, type, value =
+ atts.collect { |k, v|
+ if k == :await && m = AAWAIT_R.match(v)
+ [ m[1] || 'in', m[2], m[3] ]
+ elsif k == :await && v.index(':').nil?
+ [ 'left', 'tag', v ]
+ elsif m = SPLIT_R.match(k)
+ [ m[1] || 'in', m[2], v ]
+ else
+ nil
+ end
+ }.compact.first
+
+ return nil if direction == nil
+
+ action =
+ if type == 'tag'
+ INS.include?(direction) ? 'entered_tag' : 'left_tag'
+ elsif type == 'participant'
+ INS.include?(direction) ? 'dispatch' : 'receive'
+ else # error
+ 'error_intercepted'
+ end
+
value = Ruote.comma_split(value)
- if type == 'participant'
+ condition =
+ if type == 'participant'
- { 'participant_name' => value }
+ { 'participant_name' => value }
- elsif type == 'error'
+ elsif type == 'error'
- # array or comma string or string ?
+ # array or comma string or string ?
- h = { 'class' => [], 'message' => [] }
+ h = { 'class' => [], 'message' => [] }
- value.each { |e| (KLASS_R.match(e) ? h['class'] : h['message']) << e }
+ value.each { |e| (KLASS_R.match(e) ? h['class'] : h['message']) << e }
- h.delete_if { |k, v| v == nil or v == [] }
+ h.delete_if { |k, v| v == nil or v == [] }
- else # 'tag'
+ else # 'tag'
- { (value.first.to_s.match(/\//) ? 'full_tag' : 'tag') => value }
- end
+ { (value.first.to_s.match(/\//) ? 'full_tag' : 'tag') => value }
+ end
+
+ [ action, condition ]
end
end
end