diff --git a/lib/puppet/pops/evaluator/runtime3_converter.rb b/lib/puppet/pops/evaluator/runtime3_converter.rb index ce779a9b3..f759743d8 100644 --- a/lib/puppet/pops/evaluator/runtime3_converter.rb +++ b/lib/puppet/pops/evaluator/runtime3_converter.rb @@ -1,175 +1,175 @@ module Puppet::Pops::Evaluator # Converts nested 4x supported values to 3x values. This is required because # resources and other objects do not know about the new type system, and does not support # regular expressions. Unfortunately this has to be done for array and hash as well. # A complication is that catalog types needs to be resolved against the scope. # # Users should not create instances of this class. Instead the class methods {Runtime3Converter.convert}, # {Runtime3Converter.map_args}, or {Runtime3Converter.instance} should be used class Runtime3Converter # Converts 4x supported values to a 3x values. Same as calling Runtime3Converter.instance.map_args(...) # # @param args [Array] Array of values to convert # @param scope [Puppet::Parser::Scope] The scope to use when converting # @param undef_value [Object] The value that nil is converted to # @return [Array] The converted values # def self.map_args(args, scope, undef_value) @@instance.map_args(args, scope, undef_value) end # Converts 4x supported values to a 3x values. Same as calling Runtime3Converter.instance.convert(...) # # @param o [Object]The value to convert # @param scope [Puppet::Parser::Scope] The scope to use when converting # @param undef_value [Object] The value that nil is converted to # @return [Object] The converted value # def self.convert(o, scope, undef_value) @@instance.convert(o, scope, undef_value) end # Returns the singleton instance of this class. # @return [Runtime3Converter] The singleton instance def self.instance @@instance end # Converts 4x supported values to a 3x values. # # @param args [Array] Array of values to convert # @param scope [Puppet::Parser::Scope] The scope to use when converting # @param undef_value [Object] The value that nil is converted to # @return [Array] The converted values # def map_args(args, scope, undef_value) args.map {|a| convert(a, scope, undef_value) } end # Converts a 4x supported value to a 3x value. # # @param o [Object]The value to convert # @param scope [Puppet::Parser::Scope] The scope to use when converting # @param undef_value [Object] The value that nil is converted to # @return [Object] The converted value # def convert(o, scope, undef_value) @convert_visitor.visit_this_2(self, o, scope, undef_value) end def convert_NilClass(o, scope, undef_value) undef_value end def convert2_NilClass(o, scope, undef_value) :undef end def convert_String(o, scope, undef_value) # although wasteful, needed because user code may mutate these strings in Resources o.frozen? ? o.dup : o end alias convert2_String :convert_String def convert_Object(o, scope, undef_value) o end alias :convert2_Object :convert_Object def convert_Array(o, scope, undef_value) o.map {|x| convert2(x, scope, undef_value) } end alias :convert2_Array :convert_Array def convert_Hash(o, scope, undef_value) result = {} o.each {|k,v| result[convert2(k, scope, undef_value)] = convert2(v, scope, undef_value) } result end alias :convert2_Hash :convert_Hash def convert_Regexp(o, scope, undef_value) # Puppet 3x cannot handle parameter values that are reqular expressions. Turn into regexp string in # source form o.inspect end alias :convert2_Regexp :convert_Regexp def convert_Symbol(o, scope, undef_value) case o # Support :undef since it may come from a 3x structure when :undef undef_value # 3x wants undef as either empty string or :undef else o # :default, and all others are verbatim since they are new in future evaluator end end # The :undef symbol should not be converted when nested in arrays or hashes def convert2_Symbol(o, scope, undef_value) o end def convert_PAnyType(o, scope, undef_value) o end alias :convert2_PAnyType :convert_PAnyType def convert_PCatalogEntryType(o, scope, undef_value) # Since 4x does not support dynamic scoping, all names are absolute and can be # used as is (with some check/transformation/mangling between absolute/relative form # due to Puppet::Resource's idiosyncratic behavior where some references must be # absolute and others cannot be. # Thus there is no need to call scope.resolve_type_and_titles to do dynamic lookup. Puppet::Resource.new(*catalog_type_to_split_type_title(o)) end alias :convert2_PCatalogEntryType :convert_PCatalogEntryType # Produces an array with [type, title] from a PCatalogEntryType # This method is used to produce the arguments for creation of reference resource instances # (used when 3x is operating on a resource). # Ensures that resources are *not* absolute. # def catalog_type_to_split_type_title(catalog_type) split_type = catalog_type.is_a?(Puppet::Pops::Types::PType) ? catalog_type.type : catalog_type case split_type when Puppet::Pops::Types::PHostClassType class_name = split_type.class_name ['class', class_name.nil? ? nil : class_name.sub(/^::/, '')] when Puppet::Pops::Types::PResourceType type_name = split_type.type_name title = split_type.title - if type_name =~ /^(::)?[Cc]lass/ + if type_name =~ /^(::)?[Cc]lass$/ ['class', title.nil? ? nil : title.sub(/^::/, '')] else # Ensure that title is '' if nil # Resources with absolute name always results in error because tagging does not support leading :: [type_name.nil? ? nil : type_name.sub(/^::/, ''), title.nil? ? '' : title] end else raise ArgumentError, "Cannot split the type #{catalog_type.class}, it represents neither a PHostClassType, nor a PResourceType." end end private def initialize @convert_visitor = Puppet::Pops::Visitor.new(self, 'convert', 2, 2) @convert2_visitor = Puppet::Pops::Visitor.new(self, 'convert2', 2, 2) end @@instance = self.new # Converts a nested 4x supported value to a 3x value. # # @param o [Object]The value to convert # @param scope [Puppet::Parser::Scope] The scope to use when converting # @param undef_value [Object] The value that nil is converted to # @return [Object] The converted value # def convert2(o, scope, undef_value) @convert2_visitor.visit_this_2(self, o, scope, undef_value) end end end diff --git a/spec/unit/pops/evaluator/runtime3_converter_spec.rb b/spec/unit/pops/evaluator/runtime3_converter_spec.rb new file mode 100644 index 000000000..a33368f83 --- /dev/null +++ b/spec/unit/pops/evaluator/runtime3_converter_spec.rb @@ -0,0 +1,19 @@ +#! /usr/bin/env ruby +require 'spec_helper' + +require 'puppet/pops' +require 'puppet/pops/types/type_factory' + +describe 'when converting to 3.x' do + it "converts a resource type starting with Class without confusing it with exact match on 'class'" do + t = Puppet::Pops::Types::TypeFactory.resource('classroom', 'kermit') + converted = Puppet::Pops::Evaluator::Runtime3Converter.instance.catalog_type_to_split_type_title(t) + expect(converted).to eql(['classroom', 'kermit']) + end + + it "converts a resource type of exactly 'Class'" do + t = Puppet::Pops::Types::TypeFactory.resource('class', 'kermit') + converted = Puppet::Pops::Evaluator::Runtime3Converter.instance.catalog_type_to_split_type_title(t) + expect(converted).to eql(['class', 'kermit']) + end +end \ No newline at end of file