lib/ruote/svc/dollar_sub.rb in ruote-2.1.11 vs lib/ruote/svc/dollar_sub.rb in ruote-2.2.0
- old
+ new
@@ -1,7 +1,7 @@
#--
-# Copyright (c) 2005-2010, John Mettraux, jmettraux@gmail.com
+# Copyright (c) 2005-2011, 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
@@ -38,25 +38,28 @@
#
# It's OK to override this service with your own.
#
class DollarSubstitution
- def initialize (context)
+ def initialize(context)
@context = context
end
# Performs 'dollar substitution' on a piece of text with as input
# a flow expression and a workitem (fields and variables).
#
# With help from Nick Petrella (2008/03/20)
#
- def s (text, flow_expression, workitem)
+ def s(text, flow_expression, workitem)
if text.is_a?(String)
- Rufus.dsub(text, dict_class.new(flow_expression, workitem))
+ literal_sub(
+ Rufus.dsub(text, dict_class.new(flow_expression, workitem)),
+ flow_expression,
+ workitem)
elsif text.is_a?(Array)
text.collect { |e| s(e, flow_expression, workitem) }
@@ -80,10 +83,30 @@
#
def dict_class
::Ruote::Dollar::Dict
end
+
+ protected
+
+ # If the final text is of the form "$f:x" or "$v:y" will lookup the
+ # x field or the y variable. If the lookup is successful (not nil) will
+ # return the, not the text.
+ #
+ def literal_sub(s, fexp, wi)
+
+ result = case s
+ when /^\$([^{}:])$/, /^\$(?:field|fld|f):([^{}]+)$/
+ Ruote.lookup(wi['fields'], $~[1])
+ when /^\$(?:variable|var|v):([^{}]+)$/
+ fexp.lookup_variable($~[1])
+ else
+ s
+ end
+
+ result.nil? ? s : result
+ end
end
#
# A mini-namespace Ruote::Dollar for Dict and RubyContext, just to separate
@@ -98,22 +121,24 @@
class Dict
attr_reader :fexp
attr_reader :workitem
- def initialize (flowexpression, workitem)
+ def initialize(flowexpression, workitem)
@fexp = flowexpression
@workitem = workitem
end
- def [] (key)
+ def [](key)
return @fexp.fei.to_storage_id if key == 'fei'
return @fexp.fei.wfid if key == 'wfid'
- return @fexp.fei.sub_wfid if key == 'sub_wfid'
+ return @fexp.fei.subid if key == 'subid'
+ return @fexp.fei.subid if key == 'sub_wfid' # deprecated in 2.1.12
return @fexp.fei.expid if key == 'expid'
+ return @fexp.fei.engine_id if key == 'engine_id'
pr, k = extract_prefix(key)
# stage 0
@@ -126,11 +151,11 @@
return '' if pr.size < 2
lookup(pr[1, 1], k)
end
- def []= (key, value)
+ def []=(key, value)
pr, k = extract_prefix(key)
pr = pr[0, 1]
if pr == 'f'
@@ -141,32 +166,32 @@
@fexp.set_variable(k, value)
end
end
- def has_key? (key)
+ def has_key?(key)
pr, k = extract_prefix(key)
return true if pr == 'r'
(self[key] != nil)
end
protected
- def lookup (pr, key)
+ def lookup(pr, key)
case pr
when 'v' then @fexp.lookup_variable(key)
when 'f' then Ruote.lookup(@workitem['fields'], key)
when 'r' then ruby_eval(key)
else nil
end
end
- def extract_prefix (key)
+ def extract_prefix(key)
i = key.index(':')
return [ 'f', key ] if not i
# 'f' is the default prefix (field, not variable)
@@ -179,15 +204,19 @@
[ pr, key[i+1..-1] ]
end
# TODO : rdoc me
#
- def ruby_eval (ruby_code)
+ def ruby_eval(ruby_code)
- return '' if @fexp.context['ruby_eval_allowed'] != true
+ raise ArgumentError.new(
+ "'ruby_eval_allowed' is set to false, cannot evaluate >" +
+ ruby_code +
+ "< (http://ruote.rubyforge.org/dollar.html)"
+ ) if @fexp.context['ruby_eval_allowed'] != true
- @fexp.context.treechecker.check(ruby_code)
+ @fexp.context.treechecker.dollar_check(ruby_code)
RubyContext.new(self).instance_eval(ruby_code)
end
end
@@ -196,36 +225,40 @@
#
class RubyContext < Ruote::BlankSlate
attr_reader :workitem
- def initialize (dict)
+ def initialize(dict)
@dict = dict
@workitem = Ruote::Workitem.new(@dict.workitem)
end
# The FlowExpression for which the rendering/substitution is occurring.
#
def flow_expression
+
@dict.fexp
end
+
alias fe flow_expression
alias fexp flow_expression
# The FlowExpressionId of the expression for which the
# rendering/substitution is occurring.
#
def fei
+
@dict.fexp.fei
end
alias wi workitem
# The engine_id, if any.
#
def engine_id
+
@dict.fexp.context.engine_id
end
# This 'd' function can be called from inside ${r:...} notations.
#
@@ -236,11 +269,11 @@
# end
# end
#
# will yield "person".
#
- def d (s)
+ def d(s)
Rufus.dsub("${#{s}}", @dict)
end
# Given a workitem with the field "newspaper" set to "NYT",
@@ -249,10 +282,10 @@
# If the field "cars" hold the value [ "bmw", "volkswagen" ],
# "${r:cars[0]}" will eval to "bmw".
#
# Else the regular NoMethodError will be raised.
#
- def method_missing (m, *args)
+ def method_missing(m, *args)
if args.length < 1 && v = @workitem.fields[m.to_s]
return v
end