#--
# Copyright (c) 2006-2009, 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
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Made in Japan.
#++
require 'openwfe/workitem'
require 'openwfe/flowexpressionid'
require 'openwfe/expressions/condition'
require 'openwfe/expressions/flowexpression'
#
# expressions like 'set' and 'unset' and their utility methods
#
module OpenWFE
#
# The 'if' expression.
#
#
#
#
#
#
# It accepts an 'else' clause :
#
#
#
#
#
#
#
# The 'test' attribute can be used instead of a condition child :
#
#
#
#
#
# The 'rtest' attribute can be used to embed a condition expressed directly
# in Ruby :
#
#
#
#
#
# (Note that 'rtest' may only be used if the :ruby_eval_allowed
# parameter has been set in the engine's application_context :
#
# engine.application_context[:ruby_eval_allowed] = true
#
# but this is dangerous if the origin of the process defintions to run
# are not trusted)
#
# Used alone with 'test' or 'rtest', the 'if' expression simply sets the
# the __result__ field of its workitem to the result of its attribute
# evaluation :
#
#
#
# will set the __result__ field of the workitem to 'false'.
#
class IfExpression < FlowExpression
include ConditionMixin
names :if
#
# This boolean is set to true when the conditional claused has
# been evaluated and the 'if' is waiting for the consequence's
# reply.
#
attr_accessor :condition_replied
def apply (workitem)
#workitem.unset_result
#
# since OpenWFEru 0.9.16 previous __result__ values
# are not erased before an 'if'.
test = eval_condition(:test, workitem, :not)
if raw_children.length < 1
workitem.set_result((test != nil and test != false))
reply_to_parent(workitem)
return
end
@condition_replied = (test != nil)
#
# if the "test" attribute is not used, test will be null
#store_itself
# now done in apply_*
# a warning
maxchildren = (test == nil) ? 3 : 2
lwarn {
"apply() 'if' with more than #{maxchildren} children"
} if raw_children.size > maxchildren
# apply next step
if test != nil
#
# apply then or else (condition result known)
#
apply_consequence(test, workitem, 0)
else
#
# apply condition
#
apply_child(0, workitem)
end
end
def reply (workitem)
return reply_to_parent(workitem) \
if @condition_replied
result = workitem.attributes[FIELD_RESULT]
@condition_replied = true
#store_itself
# now done in apply_c*
apply_consequence(result, workitem)
end
#
# This reply_to_parent takes care of cleaning all the children
# before replying to the parent expression, this is important
# because only the 'then' or the 'else' child got evaluated, the
# remaining one has to be cleaned out here.
#
def reply_to_parent (workitem)
clean_children
super(workitem)
end
protected
def apply_consequence (index, workitem, offset=1)
if index == true
index = 0
elsif index == false
index = 1
elsif index == nil
index = 1
elsif not index.integer?
index = 0
end
index = index + offset
if index >= raw_children.length
reply_to_parent(workitem)
else
apply_child(index, workitem)
end
end
end
#
# The 'case' expression.
#
#
#
#
#
#
#
#
#
#
#
#
#
# A generalized 'if'. Will evaluate its children, expecting the order :
#
# - condition
# - consequence
# - condition
# - consequence
# ...
# - else consequence (optional)
#
# The 'switch' nickname can be used for 'case'.
#
class CaseExpression < FlowExpression
names :case, :switch
#
# keeping track of where we are in the case iteration
#
attr_accessor :offset
#
# set to 'true' when the case expression is actually evaluating
# a condition (ie not triggering a consequence).
#
attr_accessor :evaluating_condition
def apply (workitem)
#workitem.unset_result
#
# since OpenWFEru 0.9.16 previous __result__ values
# are not erased before a 'case'.
@offset = nil
trigger_child(workitem, true)
end
def reply (workitem)
if @evaluating_condition
trigger_child(workitem, ( ! workitem.get_boolean_result))
else
reply_to_parent(workitem)
end
end
protected
def trigger_child (workitem, is_condition)
@offset = if !@offset
0
elsif is_condition
@offset + 2
else
@offset + 1
end
#ldebug { "trigger_child() is_condition ? #{is_condition}" }
#ldebug { "trigger_child() next offset is #{@offset}" }
unless raw_children[@offset]
reply_to_parent(workitem)
return
end
@evaluating_condition = is_condition
store_itself
#get_expression_pool.apply(@children[@offset], workitem)
apply_child(@offset, workitem)
end
end
end