diff options
-rw-r--r-- | lib/puppet/parser/ast/leaf.rb | 6 | ||||
-rw-r--r-- | lib/puppet/parser/scope.rb | 53 | ||||
-rwxr-xr-x | test/language/scope.rb | 53 |
3 files changed, 76 insertions, 36 deletions
diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index 298c0168f..ed02c4eef 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -41,14 +41,12 @@ class Puppet::Parser::AST # Interpolate the string looking for variables, and then return # the result. def evaluate(hash) - return hash[:scope].strinterp(@value) + return hash[:scope].strinterp(@value, @file, @line) end end - # The base string class. + # An uninterpreted string. class FlatString < AST::Leaf - # Interpolate the string looking for variables, and then return - # the result. def evaluate(hash) return @value end diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index bf4f7215e..6bb8872ee 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -4,6 +4,7 @@ require 'puppet/parser/parser' require 'puppet/parser/templatewrapper' require 'puppet/transportable' +require 'strscan' class Puppet::Parser::Scope require 'puppet/parser/resource' @@ -540,25 +541,53 @@ class Puppet::Parser::Scope end # Return an interpolated string. - def strinterp(string) + def strinterp(string, file = nil, line = nil) # Most strings won't have variables in them. - if string =~ /\$/ - string = string.gsub(/\\\$|\$\{(\w+)\}|\$(\w+)/) do |value| + ss = StringScanner.new(string) + out = "" + while not ss.eos? + if ss.scan(/^\$\{(\w+)\}|^\$(\w+)/) # If it matches the backslash, then just retun the dollar sign. - if value == '\\$' - '$' + if ss.matched == '\\$' + out << '$' else # look the variable up - lookupvar($1 || $2) + out << lookupvar(ss[1] || ss[2]) || "" end + elsif ss.scan(/^\\(.)/) + # Puppet.debug("Got escape: pos:%d; m:%s" % [ss.pos, ss.matched]) + case ss[1] + when 'n' + out << "\n" + when 't' + out << "\t" + when 's' + out << " " + when '\\' + out << '\\' + when '$' + out << '$' + else + Puppet.warning "Unrecognised escape sequence '#{ss.matched}'" + out << ss.matched + end + elsif ss.scan(/^\$/) + out << '$' + else + tmp = ss.scan(/[^\\$]+/) + # Puppet.debug("Got other: pos:%d; m:%s" % [ss.pos, tmp]) + unless tmp + error = Puppet::ParseError.new("Could not parse string %s" % + string.inspect) + {:file= => file, :line= => line}.each do |m,v| + error.send(m, v) if v + end + raise error + end + out << tmp end end - # And most won't have whitespace replacements. - if string =~ /\\/ - return string.gsub(/\\t/, "\t").gsub(/\\n/, "\n").gsub(/\\s/, "\s") - else - return string - end + return out end # Add a tag to our current list. These tags will be added to all diff --git a/test/language/scope.rb b/test/language/scope.rb index bf89dbba2..c2346dac5 100755 --- a/test/language/scope.rb +++ b/test/language/scope.rb @@ -201,31 +201,44 @@ class TestScope < Test::Unit::TestCase assert_nothing_raised { scope.setvar("test","value") } - val = nil - assert_nothing_raised { - val = scope.strinterp("string ${test}") + tests = { + "string ${test}" => "string value", + "string ${test} ${test} ${test}" => "string value value value", + "string $test ${test} $test" => "string value value value", + "string \\$test" => "string $test", + '\\$test string' => "$test string", + '$test string' => "value string", + 'a testing $' => "a testing $", + 'a testing \$' => "a testing $", + '\$' => "$", + '\s' => "\s", + '\t' => "\t", + '\n' => "\n" } - assert_equal("string value", val) - assert_nothing_raised { - val = scope.strinterp("string ${test} ${test} ${test}") - } - assert_equal("string value value value", val) + tests.each do |input, output| + assert_nothing_raised("Failed to scan %s" % input.inspect) do + assert_equal(output, scope.strinterp(input), + 'did not interpret %s correctly' % input) + end + end - assert_nothing_raised { - val = scope.strinterp("string $test ${test} $test") - } - assert_equal("string value value value", val) + logs = [] + Puppet::Util::Log.close + Puppet::Util::Log.newdestination(logs) - assert_nothing_raised { - val = scope.strinterp("string \\$test") - } - assert_equal("string $test", val) + # #523 + %w{d f h l w z}.each do |l| + string = "\\" + l + assert_nothing_raised do + assert_equal(string, scope.strinterp(string), + 'did not interpret %s correctly' % string) + end - assert_nothing_raised { - val = scope.strinterp("\\$test string") - } - assert_equal("$test string", val) + assert(logs.detect { |m| m.message =~ /Unrecognised escape/ }, + "Did not get warning about escape sequence with %s" % string) + logs.clear + end end def test_setclass |