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