lib/puppet/parser/ast/leaf.rb in puppet-0.24.9 vs lib/puppet/parser/ast/leaf.rb in puppet-0.25.0

- old
+ new

@@ -8,12 +8,25 @@ # Return our value. def evaluate(scope) return @value end + # evaluate ourselves, and match + def evaluate_match(value, scope, options = {}) + obj = self.safeevaluate(scope) + if ! options[:sensitive] && obj.respond_to?(:downcase) + obj = obj.downcase + end + obj == value + end + + def match(value) + @value == value + end + def to_s - return @value + return @value.to_s unless @value.nil? end end # The boolean class. True or false. Converts the string it receives # to a Ruby boolean. @@ -27,26 +40,38 @@ raise Puppet::DevError, "'%s' is not a boolean" % @value end @value end + + def to_s + @value ? "true" : "false" + end end # The base string class. class String < AST::Leaf # Interpolate the string looking for variables, and then return # the result. def evaluate(scope) return scope.strinterp(@value, file, line) end + + def to_s + "\"#{@value}\"" + end end # An uninterpreted string. class FlatString < AST::Leaf def evaluate(scope) return @value end + + def to_s + "\"#{@value}\"" + end end # The 'default' option on case statements and selectors. class Default < AST::Leaf; end @@ -62,20 +87,61 @@ class ClassName < AST::Leaf; end # undef values; equiv to nil class Undef < AST::Leaf; end - # Host names, either fully qualified or just the short name + # Host names, either fully qualified or just the short name, or even a regex class HostName < AST::Leaf def initialize(hash) super - unless @value =~ %r{^[0-9a-zA-Z\-]+(\.[0-9a-zA-Z\-]+)*$} + @value = @value.to_s.downcase unless @value.is_a?(Regex) + if @value =~ /[^-\w.]/ raise Puppet::DevError, "'%s' is not a valid hostname" % @value end end + + def to_classname + classname = @value.to_s.downcase + classname.gsub!(/[^-a-zA-Z0-9:.]/,'') if regex? + classname + end + + # implementing eql? and hash so that when an HostName is stored + # in a hash it has the same hashing properties as the underlying value + def eql?(value) + value = value.value if value.is_a?(HostName) + return @value.eql?(value) + end + + def hash + return @value.hash + end + + def match(value) + return @value.match(value) unless value.is_a?(HostName) + + if value.regex? and self.regex? + # Wow this is some sweet design; maybe a touch of refactoring + # in order here. + return value.value.value == self.value.value + elsif value.regex? # we know if the existing name is not a regex, it won't match a regex + return false + else + # else, we could be either a regex or normal and it doesn't matter + return @value.match(value.value) + end + end + + def regex? + @value.is_a?(Regex) + end + + def to_s + @value.to_s + end end # A simple variable. This object is only used during interpolation; # the VarDef class is used for assignment. class Variable < Name @@ -83,8 +149,45 @@ # not include syntactical constructs, like '$' and '{}'). def evaluate(scope) parsewrap do return scope.lookupvar(@value) end + end + end + + class Regex < AST::Leaf + def initialize(hash) + super + @value = Regexp.new(@value) unless @value.is_a?(Regexp) + end + + # we're returning self here to wrap the regexp and to be used in places + # where a string would have been used, without modifying any client code. + # For instance, in many places we have the following code snippet: + # val = @val.safeevaluate(@scope) + # if val.match(otherval) + # ... + # end + # this way, we don't have to modify this test specifically for handling + # regexes. + def evaluate(scope) + return self + end + + def evaluate_match(value, scope, options = {}) + value = value.is_a?(String) ? value : value.to_s + + if matched = @value.match(value) + scope.ephemeral_from(matched, options[:file], options[:line]) + end + matched + end + + def match(value) + @value.match(value) + end + + def to_s + return "/#{@value.source}/" end end end