lib/openwfe/expressions/raw.rb in ruote-0.9.19 vs lib/openwfe/expressions/raw.rb in ruote-0.9.20
- old
+ new
@@ -1,47 +1,32 @@
-#
#--
-# Copyright (c) 2006-2008, John Mettraux, OpenWFE.org
-# All rights reserved.
+# Copyright (c) 2006-2009, John Mettraux, jmettraux@gmail.com
#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
+# 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:
#
-# . Redistributions of source code must retain the above copyright notice, this
-# list of conditions and the following disclaimer.
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
#
-# . 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.
+# 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.
#
-# . 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.
#++
-#
-#
-# "made in Japan"
-#
-# John Mettraux at openwfe.org
-#
-require 'openwfe/exceptions'
-require 'openwfe/expressions/flowexpression'
require 'openwfe/rudefinitions'
+require 'openwfe/expressions/flowexpression'
module OpenWFE
#
@@ -52,12 +37,11 @@
class RawExpression < FlowExpression
#
# A [static] method for creating new RawExpression instances.
#
- def self.new_raw (
- fei, parent_id, env_id, app_context, raw_representation)
+ def self.new_raw (fei, parent_id, env_id, app_context, raw_tree)
re = self.new
re.fei = fei
re.parent_id = parent_id
@@ -65,95 +49,30 @@
re.application_context = app_context
re.attributes = nil
re.children = []
re.apply_time = nil
- re.raw_representation = raw_representation
+ re.raw_representation = raw_tree
re
end
- #--
- # A duplication method that duplicates everything, except
- # the application context
#
- #def dup
- # self.class.new_raw(
- # @fei.dup,
- # @parent_id ? @parent_id.dup : nil,
- # @environment_id ? @environment_id.dup : nil,
- # @application_context,
- # raw_representation)
- #end
- #alias :fulldup :dup
- #++
-
- def instantiate_real_expression (
- workitem, exp_name=nil, exp_class=nil, attributes=nil)
-
- exp_name ||= expression_name
- exp_class ||= expression_class
-
- raise "unknown expression '#{exp_name}'" \
- unless exp_class
-
- #ldebug do
- # "instantiate_real_expression() exp_class is #{exp_class}"
- #end
-
- attributes ||= raw_representation[1]
-
- exp = exp_class.new
- exp.fei = @fei
- exp.parent_id = @parent_id
- exp.environment_id = @environment_id
- exp.application_context = @application_context
- exp.attributes = attributes
-
- exp.raw_representation = raw_representation
- exp.raw_rep_updated = raw_rep_updated
- #
- # keeping track of how the expression look at apply /
- # instantiation time
-
- consider_tag workitem, exp
-
- exp.children = extract_children \
- unless exp_class.uses_template?
-
- exp
- end
-
- #
# When a raw expression is applied, it gets turned into the
# real expression which then gets applied.
#
def apply (workitem)
- exp_name, exp_class, attributes = determine_real_expression
+ exp_class, val = determine_real_expression_class
- expression = instantiate_real_expression(
- workitem, exp_name, exp_class, attributes)
+ expression = instantiate_real_expression(workitem, exp_class, val)
expression.apply_time = Time.now
expression.store_itself
- expression.apply workitem
+ expression.apply(workitem)
end
- #
- # This method is called by the expression pool when it is about
- # to launch a process, it will interpret the 'parameter' statements
- # in the process definition and raise an exception if the requirements
- # are not met.
- #
- def check_parameters (workitem)
-
- extract_parameters.each do |param|
- param.check(workitem)
- end
- end
-
#--
#def reply (workitem)
# no implementation necessary
#end
#++
@@ -191,356 +110,221 @@
#
# This method has been made public in order to have quick look
# at the attributes of an expression before it's really
# 'instantiated'.
#
+ # (overriden by ExpExpression)
+ #
def extract_attributes
raw_representation[1]
end
- protected
+ #
+ # This method is called by the expression pool when it is about
+ # to launch a process, it will interpret the 'parameter' statements
+ # in the process definition and raise an exception if the requirements
+ # are not met.
+ #
+ def check_parameters (workitem)
- #
- # looks up a participant in the participant map, considers
- # "my-participant" and "my_participant" as the same
- # (by doing two lookups).
- #
- def lookup_participant (name)
+ #extract_parameters.each { |param| param.check(workitem) }
+ ExpressionTree.check_parameters(raw_representation, workitem)
+ end
- p = get_participant_map.lookup_participant(name)
+ protected
- unless p
- name = OpenWFE::to_underscore(name)
- p = get_participant_map.lookup_participant(name)
- end
+ #
+ # Looks up a key as a variable or a participant.
+ #
+ def lookup (kind, key, underscore=false)
- return name if p
+ val = (kind == :variable) ?
+ lookup_variable(key) : get_participant_map.lookup_participant(key)
- nil
- end
+ return lookup(:participant, val) || lookup(:variable, val) \
+ if kind == :variable and val.is_a?(String) # alias lookup
- #
- # Determines if this raw expression points to a classical
- # expression, a participant or a subprocess, or nothing at all...
- #
- def determine_real_expression
+ return val, key if val
- exp_name = expression_name()
- exp_class = expression_class()
- var_value = lookup_variable exp_name
- attributes = extract_attributes
+ return nil if underscore
- unless var_value
- #
- # accomodating "sub_process_name" and "sub-process-name"
- #
- alt = OpenWFE::to_underscore exp_name
- var_value = lookup_variable(alt) if alt != exp_name
+ lookup(kind, OpenWFE::to_underscore(key), true)
+ end
- exp_name = alt if var_value
- end
+ #
+ # Determines if this raw expression points to a classical
+ # expression, a participant or a subprocess, or nothing at all...
+ #
+ def determine_real_expression_class
- var_value = exp_name \
- if (not exp_class and not var_value)
+ exp_name = expression_name()
- if var_value.is_a?(String)
+ val, key =
+ lookup(:variable, exp_name) ||
+ expression_class() ||
+ lookup(:participant, exp_name)
+ # priority to variables
- participant_name = lookup_participant var_value
+ if val.is_a?(Array)
- if participant_name
- exp_name = participant_name
- exp_class = ParticipantExpression
- attributes['ref'] = participant_name
- end
+ [ SubProcessRefExpression, val ]
- elsif var_value.is_a?(FlowExpressionId) \
- or var_value.is_a?(RawExpression)
+ elsif val.respond_to?(:consume)
- exp_class = SubProcessRefExpression
- attributes['ref'] = exp_name
- end
- # else, it's a standard expression
+ [ ParticipantExpression, key ]
- [ exp_name, exp_class, attributes ]
+ else
+
+ [ val, nil ]
end
+ end
- def extract_children
+ def instantiate_real_expression (workitem, exp_class, val)
- i = 0
- result = []
- raw_representation.last.each do |child|
+ raise "unknown expression '#{expression_name}'" unless exp_class
- if is_not_a_node?(child)
+ exp = exp_class.new
+ exp.fei = @fei
+ exp.parent_id = @parent_id
+ exp.environment_id = @environment_id
+ exp.application_context = @application_context
+ exp.attributes = extract_attributes()
- result << child
- else
+ exp.raw_representation = @raw_representation
+ exp.raw_rep_updated = @raw_rep_updated
- cname = child.first.intern
+ consider_tag(workitem, exp)
+ consider_on_error(workitem, exp)
+ consider_on_cancel(workitem, exp)
- next if cname == :param
- next if cname == :parameter
- #next if cname == :description
+ if val
+ class << exp
+ attr_accessor :hint
+ end
+ exp.hint = val
+ end # later sparing a variable/participant lookup
- cfei = @fei.dup
- cfei.expression_name = child.first
- cfei.expression_id = "#{cfei.expression_id}.#{i}"
+ exp
+ end
- efei = @environment_id
+ #
+ # Expressions can get tagged. Tagged expressions can easily
+ # be cancelled (undone) or redone.
+ #
+ def consider_tag (workitem, new_expression)
- rawexp = RawExpression.new_raw(
- cfei, @fei, efei, @application_context, child)
+ tagname = new_expression.lookup_string_attribute(:tag, workitem)
- get_expression_pool.update rawexp
+ return unless tagname
- i = i + 1
+ #ldebug { "consider_tag() tag is '#{tagname}'" }
- result << rawexp.fei
- end
- end
- result
- end
+ set_variable(tagname, Tag.new(self, workitem))
+ #
+ # keep copy of raw expression and workitem as applied
- def extract_parameters
+ new_expression.attributes['tag'] = tagname
+ #
+ # making sure that the value of tag doesn't change anymore
+ end
- r = []
- raw_representation.last.each do |child|
+ #
+ # A small class wrapping a tag (a raw expression and the workitem
+ # it received at apply time.
+ #
+ class Tag
- #next unless child.is_a?(SimpleExpRepresentation)
- #next unless child.is_a?(Array)
- next if is_not_a_node?(child)
+ attr_reader :raw_expression, :workitem
- name = child.first.to_sym
- next unless (name == :parameter or name == :param)
-
- attributes = child[1]
-
- r << Parameter.new(
- attributes['field'],
- attributes['match'],
- attributes['default'],
- attributes['type'])
- end
- r
+ def flow_expression_id
+ @raw_expression.fei
end
+ alias :fei :flow_expression_id
- def is_not_a_node? (child)
+ def initialize (raw_expression, workitem)
- (( ! child.is_a?(Array)) ||
- child.size != 3 ||
- ( ! child.first.is_a?(String)))
+ @raw_expression = raw_expression.dup
+ @workitem = workitem.dup
end
+ end
- #
- # Expressions can get tagged. Tagged expressions can easily
- # be cancelled (undone) or redone.
- #
- def consider_tag (workitem, new_expression)
+ #
+ # manages 'on-error' expression tags
+ #
+ def consider_on_error (workitem, new_expression)
- tagname = new_expression.lookup_string_attribute :tag, workitem
+ on_error = new_expression.lookup_string_attribute(:on_error, workitem)
- return unless tagname
+ return unless on_error
- ldebug { "consider_tag() tag is '#{tagname}'" }
+ on_error = on_error.to_s
- set_variable tagname, Tag.new(self, workitem)
- #
- # keep copy of raw expression and workitem as applied
+ handlers = lookup_variable('error_handlers') || []
- new_expression.attributes["tag"] = tagname
- #
- # making sure that the value of tag doesn't change anymore
- end
+ handlers << [ fei.dup, on_error ]
+ # not using a hash to preserve insertion order
+ # "deeper last"
- #
- # A small class wrapping a tag (a raw expression and the workitem
- # it received at apply time.
- #
- class Tag
+ set_variable('error_handlers', handlers)
- attr_reader \
- :raw_expression,
- :workitem
+ new_expression.attributes['on_error'] = on_error
+ #
+ # making sure that the value of tag doesn't change anymore
+ end
- def flow_expression_id
- @raw_expression.fei
- end
- alias :fei :flow_expression_id
+ #
+ # manages 'on-cancel'
+ #
+ def consider_on_cancel (workitem, new_expression)
- def initialize (raw_expression, workitem)
+ on_cancel = new_expression.lookup_string_attribute(:on_cancel, workitem)
- @raw_expression = raw_expression.dup
- @workitem = workitem.dup
- end
- end
+ return unless on_cancel
- #
- # Encapsulating
- # <parameter field="x" default="y" type="z" match="m" />
- #
- # Somehow I have that : OpenWFEru is not a strongly typed language
- # ... Anyway I implemented that to please Pat.
- #
- class Parameter
-
- def initialize (field, match, default, type)
-
- @field = to_s field
- @match = to_s match
- @default = to_s default
- @type = to_s type
- end
-
+ new_expression.attributes['on_cancel'] = [ on_cancel, workitem.dup ]
#
- # Will raise an exception if this param requirement is not
- # met by the workitem.
+ # storing the on_cancel value (a participant name or a subprocess
+ # name along with a copy of the workitem as applied among the
+ # attributes of the new expression)
#
- def check (workitem)
-
- unless @field
- raise \
- OpenWFE::ParameterException,
- "'parameter'/'param' without a 'field' attribute"
- end
-
- field_value = workitem.attributes[@field]
- field_value = @default unless field_value
-
- unless field_value
- raise \
- OpenWFE::ParameterException,
- "field '#{@field}' is missing" \
- end
-
- check_match(field_value)
-
- enforce_type(workitem, field_value)
- end
-
- protected
-
- #
- # Used in the constructor to flatten everything to strings.
- #
- def to_s (o)
- return nil unless o
- o.to_s
- end
-
- #
- # Will raise an exception if it cannot coerce the type
- # of the value to the one desired.
- #
- def enforce_type (workitem, value)
-
- value = if not @type
- value
- elsif @type == "string"
- value.to_s
- elsif @type == "int" or @type == "integer"
- Integer(value)
- elsif @type == "float"
- Float(value)
- else
- raise
- "unknown type '#{@type}' for field '#{@field}'"
- end
-
- workitem.attributes[@field] = value
- end
-
- def check_match (value)
-
- return unless @match
-
- unless value.to_s.match(@match)
- raise \
- OpenWFE::ParameterException,
- "value of field '#{@field}' doesn't match"
- end
- end
- end
- end
-
- #
- # This class is only present to ensure that OpenWFEru 0.9.17 can read
- # previous (<= 0.9.16) expools.
- #
- class ProgRawExpression < RawExpression
-
- def raw_representation
-
- @raw_representation.to_a
+ # (note 'on_cancel' and not 'on-cancel' as we're specifically storing
+ # more info and not just the initial string value of the attribute)
end
end
+ private
+
#
- # This class is only present to ensure that OpenWFEru 0.9.17 can read
- # previous (<= 0.9.16) expools.
+ # OpenWFE process definitions do use some
+ # Ruby keywords... The workaround is to put an underscore
+ # just before the name to 'escape' it.
#
- class XmlRawExpression < RawExpression
+ # 'undo' isn't reserved by Ruby, but lets keep it in line
+ # with 'do' and 'redo' that are.
+ #
+ KEYWORDS = [
+ :if, :do, :redo, :undo, :print, :sleep, :loop, :break, :when
+ #:until, :while
+ ]
- def raw_representation
-
- get_def_parser.parse @raw_representation_s
- end
- end
-
#
- # This class is only present to ensure that OpenWFEru 0.9.17 can read
- # previous (<= 0.9.16) expools.
+ # Ensures the method name is not conflicting with Ruby keywords
+ # and turn dashes to underscores.
#
- class SimpleExpRepresentation
+ def OpenWFE.make_safe (method_name)
- def to_a
+ method_name = OpenWFE::to_underscore(method_name)
- children = @children.collect do |c|
- if c.is_a?(SimpleExpRepresentation)
- c.to_a
- else
- c
- end
- end
-
- a = [ @name, @attributes, children ]
- end
+ KEYWORDS.include?(method_name.to_sym) ? "_#{method_name}" : method_name
end
- private
+ def OpenWFE.to_expression_name (method_name)
- #
- # OpenWFE process definitions do use some
- # Ruby keywords... The workaround is to put an underscore
- # just before the name to 'escape' it.
- #
- # 'undo' isn't reserved by Ruby, but lets keep it in line
- # with 'do' and 'redo' that are.
- #
- KEYWORDS = [
- :if, :do, :redo, :undo, :print, :sleep, :loop, :break, :when
- #:until, :while
- ]
-
- #
- # Ensures the method name is not conflicting with Ruby keywords
- # and turn dashes to underscores.
- #
- def OpenWFE.make_safe (method_name)
-
- method_name = OpenWFE::to_underscore(method_name)
-
- return "_" + method_name \
- if KEYWORDS.include? eval(":"+method_name)
-
- method_name
- end
-
- def OpenWFE.to_expression_name (method_name)
-
- method_name = method_name.to_s
- method_name = method_name[1..-1] if method_name[0, 1] == "_"
- method_name = OpenWFE::to_dash(method_name)
- method_name
- end
+ method_name = method_name.to_s
+ method_name = method_name[1..-1] if method_name[0, 1] == '_'
+ method_name = OpenWFE::to_dash(method_name)
+ method_name
+ end
end