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