#
#--
# Copyright (c) 2006-2008, John Mettraux, OpenWFE.org
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# . Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# . Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# . Neither the name of the "OpenWFE" nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#++
#
#
# "made in Japan"
#
# John Mettraux at openwfe.org
#
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 @children.length < 1
#workitem.set_result test if test
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
# a warning
maxchildren = (test == nil) ? 3 : 2
lwarn {
"apply() 'if' with more than #{maxchildren} children"
} if @children.size > maxchildren
# apply next step
if test != nil
#
# apply then or else (condition result known)
#
apply_consequence test, workitem, 0
else
#
# apply condition
#
get_expression_pool.apply @children.first, workitem
end
end
def reply (workitem)
return reply_to_parent(workitem) \
if @condition_replied
result = workitem.attributes[FIELD_RESULT]
@condition_replied = true
store_itself
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 >= @children.length
reply_to_parent workitem
else
get_expression_pool.apply @children[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
result = workitem.get_boolean_result
#ldebug { "reply() result : '#{result.to_s}' (#{result.class})" }
trigger_child workitem, !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 @children[@offset]
reply_to_parent workitem
return
end
@evaluating_condition = is_condition
store_itself
get_expression_pool.apply(@children[@offset], workitem)
end
end
end