lib/ruote/exp/fe_inc.rb in ruote-2.2.0 vs lib/ruote/exp/fe_inc.rb in ruote-2.3.0
- old
+ new
@@ -1,7 +1,7 @@
#--
-# Copyright (c) 2005-2011, John Mettraux, jmettraux@gmail.com
+# Copyright (c) 2005-2012, 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
@@ -21,13 +21,10 @@
#
# Made in Japan.
#++
-require 'ruote/exp/fe_set'
-
-
module Ruote::Exp
#
# Increments or decrements the value found in a process variable or
# a workitem field.
@@ -73,12 +70,12 @@
#
# sequence do
# set 'v:x' => %w[ a b c d ]
# repeat do
# dec 'v:x', :pos => 'head'
- # _break :unless => '${v:d}'
- # participant '${v:d}'
+ # _break :unless => '${__result__}'
+ # participant '${__result__}'
# end
# end
#
# is equivalent to
#
@@ -106,100 +103,170 @@
#
# set 'v:x' => [ 'alfred', 'bryan', 'carl' ]
# dec 'v:x', :val => 'bryan'
# # the variable 'x' now holds [ 'alfred', 'carl' ]
#
- # 'dec' places the removed value in the local variable named 'd'. This trick
+ # 'dec' places the removed value in workitem field '__result__'. This trick
# was used in the above iterator example.
#
# A specific variable or field can be specified via the :to_var / :to_field
# attributes :
#
# dec 'v:x', :to_v => 'a'
# participant :ref => '${v:a}'
#
- class IncExpression < SetExpression
+ #
+ # == nested value
+ #
+ # (Since ruote 2.3.0)
+ #
+ # If nested expressions are provided the __result__ workitem field is
+ # used for inc.
+ #
+ # inc 'v:x' do
+ # set '__result__' => 3
+ # end
+ #
+ # will increase the value of the variable x by 3.
+ #
+ #
+ # == push and pop
+ #
+ # push and pop are aliases for inc and dec respectively. There is a major
+ # difference though: they'll force the target value into an array.
+ #
+ # sequence do
+ # set 'v:x' => 2
+ # push 'v:x' => 3
+ # end
+ #
+ # will result in a variable x holding [ 2, 3 ] as value.
+ #
+ # Likewise,
+ #
+ # pop 'v:x'
+ #
+ # will force a value of [] into the variable x if it wasn't previously set
+ # or its value was not an array with more than one element.
+ #
+ class IncExpression < SequenceExpression
- names :inc, :dec, :increment, :decrement
+ names :inc, :dec, :increment, :decrement, :push, :pop
def apply
- if var_key = has_attribute(:v, :var, :variable)
+ h.variables ||= {} # ensures a local scope
+ reply(h.applied_workitem)
+ end
+
+ def reply_to_parent(workitem)
+
+ h.applied_workitem['fields'] = workitem['fields']
+
+ key, value = if var_key = has_attribute(:v, :var, :variable)
+
var = attribute(var_key)
- set_v(var, new_value(:var, var))
+ [ "v:#{var}", new_value(:var, var, nil) ]
+
elsif field_key = has_attribute(:f, :fld, :field)
field = attribute(field_key)
- set_f(field, new_value(:field, field))
- else
+ [ field, new_value(:field, field, nil) ]
- k = attribute_text
+ elsif k = att_text
- raise(
- ArgumentError.new('no variable or field to increment/decrement')
- ) if k.length < 1
+ [ k, new_value(nil, k, nil) ]
- set_vf(k, new_value(nil, k))
+ elsif kv = find_kv
- #else
- # raise ArgumentError.new(
- # "missing a variable or field target in #{tree.inspect}")
+ k, v = kv
+
+ [ k, new_value(nil, k, v) ]
+
+ else
+
+ raise(ArgumentError.new('no variable or field to increment/decrement'))
end
- reply_to_parent(h.applied_workitem)
- end
+ h.variables = nil
+ # the local scope is over,
+ # variables set here will be set in the parent scope
- def reply(workitem)
+ if dec? && value.is_a?(Array)
+ k, car, value = value
+ set_vf(k || '__result__', car)
+ end
- # never called
+ set_vf(key, value)
+
+ super(h.applied_workitem)
end
protected
- def new_value(type, key)
+ def find_kv
- dec = name.match(/^dec/)
+ compile_atts.reject { |k, v|
+ COMMON_ATT_KEYS.include?(k) ||
+ k.match(/^to_/)
+ }.first
+ end
+ def dec?
+
+ @dec ||= !!(name.match(/^dec/) or name == 'pop')
+ end
+
+ def new_value(type, key, increment)
+
if type == nil && m = PREFIX_REGEX.match(key)
type = (m[1][0, 1] == 'f' ? :field : :var)
key = m[2]
end
- delta = lookup_val
+ delta = increment.nil? ? lookup_val : increment
+ if delta.nil? && @msg && @msg['action'] == 'reply'
+ delta = h.applied_workitem['fields']['__result__']
+ end
+
ndelta = Ruote.narrow_to_number(delta || 1)
- ndelta = -ndelta if dec && ndelta
+ ndelta = -ndelta if dec? && ndelta
value = type == :var ?
lookup_variable(key) :
Ruote.lookup(h.applied_workitem['fields'], key)
+ value = case value
+ when NilClass then []
+ when Array then value
+ else [ value ]
+ end if (name == 'push' || name == 'pop')
+
pos = attribute(:position) || attribute(:pos)
return ((value || 0) + ndelta) if ndelta && (not value.is_a?(Array))
pos ||= 'tail'
value ||= []
- return (pos == 'tail' ? value + [ delta ] : [ delta ] + value) unless dec
+ return (pos == 'tail' ? value + [ delta ] : [ delta ] + value) unless dec?
- to_v, to_f = determine_tos
- to_v = 'd' if to_v.nil? && to_f.nil?
-
car, cdr = if delta != nil
(value.delete(delta) != nil ) ? [ delta, value ] : [ nil, value ]
elsif pos == 'tail'
[ value[-1], value[0..-2] ]
else
[ value[0], value[1..-1] ]
end
- to_v ? set_v(to_v, car) : set_f(to_f, car)
+ to_v, to_f = determine_tos
+ key = to_v ? "v:#{to_v}" : to_f
- cdr
+ [ key, car, cdr ]
end
end
end