summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/puppet/parser/ast/leaf.rb6
-rw-r--r--lib/puppet/parser/scope.rb53
-rwxr-xr-xtest/language/scope.rb53
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