diff --git a/lib/puppet/pops/patterns.rb b/lib/puppet/pops/patterns.rb index abf9348b1..30475d986 100644 --- a/lib/puppet/pops/patterns.rb +++ b/lib/puppet/pops/patterns.rb @@ -1,46 +1,46 @@ # The Patterns module contains common regular expression patters for the Puppet DSL language module Puppet::Pops::Patterns # NUMERIC matches hex, octal, decimal, and floating point and captures several parts # 0 = entire matched number, leading and trailing whitespace and sign included # 1 = sign, +, - or nothing # 2 = entire numeric part - # 3 = hexadecimal number (1) - # 4 = non hex integer portion, possibly with leading 0 (octal) (2) - # 5 = floating point part, starts with ".", decimals and optional exponent (3) + # 3 = hexadecimal number + # 4 = non hex integer portion, possibly with leading 0 (octal) + # 5 = floating point part, starts with ".", decimals and optional exponent # # Thus, a hex number has group 1 value, an octal value has group 2 (if it starts with 0), and no group 3 # and a floating point value has group 2 and group 3. # NUMERIC = %r{^\s*([-+]?)\s*((0[xX][0-9A-Fa-f]+)|(0?\d+)((?:\.\d+)?(?:[eE]-?\d+)?))\s*$} # ILLEGAL_P3_1_HOSTNAME matches if a hostname contains illegal characters. # This check does not prevent pathological names like 'a....b', '.....', "---". etc. ILLEGAL_HOSTNAME_CHARS = %r{[^-\w.]} # NAME matches a name the same way as the lexer. NAME = %r{\A((::)?[a-z]\w*)(::[a-z]\w*)*\z} # CLASSREF_EXT matches a class reference the same way as the lexer - i.e. the external source form # where each part must start with a capital letter A-Z. # This name includes hyphen, which may be illegal in some cases. # CLASSREF_EXT = %r{\A((::){0,1}[A-Z][\w]*)+\z} # CLASSREF matches a class reference the way it is represented internally in the # model (i.e. in lower case). # This name includes hyphen, which may be illegal in some cases. # CLASSREF = %r{\A((::){0,1}[a-z][\w]*)+\z} # DOLLAR_VAR matches a variable name including the initial $ character DOLLAR_VAR = %r{\$(::)?(\w+::)*\w+} # VAR_NAME matches the name part of a variable (The $ character is not included) # Note, that only the final segment may start with an underscore. VAR_NAME = %r{\A(:?(::)?[a-z]\w*)*(:?(::)?[a-z_]\w*)\z} # A Numeric var name must be the decimal number 0, or a decimal number not starting with 0 NUMERIC_VAR_NAME = %r{\A(?:0|(?:[1-9][0-9]*))\z} end diff --git a/lib/puppet/pops/utils.rb b/lib/puppet/pops/utils.rb index f44baa85b..7fd98c58f 100644 --- a/lib/puppet/pops/utils.rb +++ b/lib/puppet/pops/utils.rb @@ -1,122 +1,122 @@ # Provides utility methods module Puppet::Pops::Utils # Can the given o be converted to numeric? (or is numeric already) # Accepts a leading '::' # Returns a boolean if the value is numeric # If testing if value can be converted it is more efficient to call {#to_n} or {#to_n_with_radix} directly # and check if value is nil. def self.is_numeric?(o) case o - when Numeric, Integer, Fixnum, Float - !!o + when Numeric + true else !!Puppet::Pops::Patterns::NUMERIC.match(relativize_name(o.to_s)) end end # To Numeric with radix, or nil if not a number. # If the value is already Numeric it is returned verbatim with a radix of 10. # @param o [String, Number] a string containing a number in octal, hex, integer (decimal) or floating point form # with optional sign +/- # @return [Array, nil] array with converted number and radix, or nil if not possible to convert # @api public # def self.to_n_with_radix o begin case o when String match = Puppet::Pops::Patterns::NUMERIC.match(relativize_name(o)) if !match nil elsif match[5].to_s.length > 0 # Use default radix (default is decimal == 10) for floats match[1] == '-' ? [-Float(match[2]), 10] : [Float(match[2]), 10] else # Set radix (default is decimal == 10) radix = 10 if match[3].to_s.length > 0 radix = 16 elsif match[4].to_s.length > 1 && match[4][0,1] == '0' radix = 8 end # Ruby 1.8.7 does not have a second argument to Kernel method that creates an # integer from a string, it relies on the prefix 0x, 0X, 0 (and unsupported in puppet binary 'b') # We have the correct string here, match[2] is safe to parse without passing on radix match[1] == '-' ? [-Integer(match[2]), radix] : [Integer(match[2]), radix] end - when Numeric, Fixnum, Integer, Float + when Numeric # Impossible to calculate radix, assume decimal [o, 10] else nil end rescue ArgumentError nil end end # To Numeric (or already numeric) # Returns nil if value is not numeric, else an Integer or Float. A String may have an optional sign. # # A leading '::' is accepted (and ignored) # def self.to_n o begin case o when String match = Puppet::Pops::Patterns::NUMERIC.match(relativize_name(o)) if !match nil elsif match[5].to_s.length > 0 match[1] == '-' ? -Float(match[2]) : Float(match[2]) else match[1] == '-' ? -Integer(match[2]) : Integer(match[2]) end - when Numeric, Fixnum, Integer, Float + when Numeric o else nil end rescue ArgumentError nil end end # is the name absolute (i.e. starts with ::) def self.is_absolute? name name.start_with? "::" end def self.name_to_segments name name.split("::") end def self.relativize_name name is_absolute?(name) ? name[2..-1] : name end # Finds an existing adapter for o or for one of its containers, or nil, if none of the containers # was adapted with the given adapter. # This method can only be used with objects that respond to `:eContainer`. # with true. # # @see #find_closest_positioned # def self.find_adapter(o, adapter) return nil if o.nil? || (o.is_a?(Array) && o.empty?) a = adapter.get(o) return a if a return find_adapter(o.eContainer, adapter) end # Finds the closest positioned Puppet::Pops::Model::Positioned object, or object decorated with # a SourcePosAdapter, and returns # a SourcePosAdapter for the first found, or nil if not found. # def self.find_closest_positioned(o) return nil if o.nil? || o.is_a?(Puppet::Pops::Model::Program) || (o.is_a?(Array) && o.empty?) return find_adapter(o, Puppet::Pops::Adapters::SourcePosAdapter) unless o.is_a?(Puppet::Pops::Model::Positioned) o.offset.nil? ? find_closest_positioned(o.eContainer) : Puppet::Pops::Adapters::SourcePosAdapter.adapt(o) end end