class Puppet::Pops::Types::PObjectTypeExtension
Base class for Parameterized Object implementations. The wrapper impersonates the base object and extends it with methods to filter assignable types and instances based on parameter values.
@api public
Attributes
Public Class Methods
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 27 def self.create(base_type, init_parameters) 28 impl_class = Loaders.implementation_registry.module_for_type("#{base_type.name}TypeExtension") || self 29 impl_class.new(base_type, init_parameters) 30 end
Creates an array of type parameters from the attributes of the given instance that matches the type parameters by name. Type parameters for which there is no matching attribute will have `nil` in their corresponding position on the array. The array is then passed as the `init_parameters` argument in a call to `create`
@return [PObjectTypeExtension] the created extension @api private
# File lib/puppet/pops/types/p_object_type_extension.rb 39 def self.create_from_instance(base_type, instance) 40 type_parameters = base_type.type_parameters(true) 41 attrs = base_type.attributes(true) 42 params = type_parameters.keys.map do |pn| 43 attr = attrs[pn] 44 attr.nil? ? nil : instance.send(pn) 45 end 46 create(base_type, params) 47 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 54 def initialize(base_type, init_parameters) 55 pts = base_type.type_parameters(true) 56 raise Puppet::ParseError, _('The %{label}-Type cannot be parameterized using []') % { label: base_type.label } if pts.empty? 57 @base_type = base_type 58 59 named_args = init_parameters.size == 1 && init_parameters[0].is_a?(Hash) 60 if named_args 61 # Catch case when first parameter is an assignable Hash 62 named_args = pts.size >= 1 && !pts.values[0].type.instance?(init_parameters[0]) 63 end 64 65 by_name = {} 66 if named_args 67 hash = init_parameters[0] 68 hash.each_pair do |pn, pv| 69 tp = pts[pn] 70 if tp.nil? 71 raise Puppet::ParseError, _("'%{pn}' is not a known type parameter for %{label}-Type") % { pn: pn, label: base_type.label } 72 end 73 by_name[pn] = check_param(tp, pv) unless pv == :default 74 end 75 else 76 pts.values.each_with_index do |tp, idx| 77 if idx < init_parameters.size 78 pv = init_parameters[idx] 79 by_name[tp.name] = check_param(tp, pv) unless pv == :default 80 end 81 end 82 end 83 if by_name.empty? 84 raise Puppet::ParseError, _('The %{label}-Type cannot be parameterized using an empty parameter list') % { label: base_type.label } 85 end 86 @parameters = by_name 87 end
# File lib/puppet/pops/types/p_object_type_extension.rb 13 def self.register_ptype(loader, ir) 14 create_ptype(loader, ir, 'AnyType', 15 'base_type' => { 16 KEY_TYPE => PTypeType::DEFAULT 17 }, 18 'init_parameters' => { 19 KEY_TYPE => PArrayType::DEFAULT 20 } 21 ) 22 end
Public Instance Methods
# File lib/puppet/pops/types/p_object_type_extension.rb 49 def [](name) 50 @base_type[name] 51 end
# File lib/puppet/pops/types/p_object_type_extension.rb 89 def check_param(type_param, v) 90 TypeAsserter.assert_instance_of(nil, type_param.type, v) { type_param.label } 91 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 133 def check_self_recursion(originator) 134 @base_type.check_self_recursion(originator) 135 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 138 def create(*args) 139 @base_type.create(*args) 140 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 113 def eql?(o) 114 super(o) && @base_type.eql?(o.base_type) && @parameters.eql?(o.parameters) 115 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 118 def generalize 119 @base_type 120 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 123 def hash 124 @base_type.hash ^ @parameters.hash 125 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 158 def implementation_class(create = true) 159 @base_type.implementation_class(create) 160 end
Return the parameter values as positional arguments with unset values as :default. The array is stripped from trailing :default values @return [Array] the parameter values @api private
# File lib/puppet/pops/types/p_object_type_extension.rb 97 def init_parameters 98 pts = @base_type.type_parameters(true) 99 if pts.size > 2 100 @parameters 101 else 102 result = pts.values.map do |tp| 103 pn = tp.name 104 @parameters.include?(pn) ? @parameters[pn] : :default 105 end 106 # Remove trailing defaults 107 result.pop while result.last == :default 108 result 109 end 110 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 143 def instance?(o, guard = nil) 144 @base_type.instance?(o, guard) && test_instance?(o, guard) 145 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 128 def loader 129 @base_type.loader 130 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 148 def new_function 149 @base_type.new_function 150 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 163 def parameter_info(impl_class) 164 @base_type.parameter_info(impl_class) 165 end
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 153 def simple_name 154 @base_type.simple_name 155 end
Protected Instance Methods
@api private
# File lib/puppet/pops/types/p_object_type_extension.rb 220 def _assignable?(o, guard = nil) 221 if o.is_a?(PObjectTypeExtension) 222 @base_type.assignable?(o.base_type, guard) && test_assignable?(o.parameters, guard) 223 else 224 @base_type.assignable?(o, guard) && test_assignable?(EMPTY_HASH, guard) 225 end 226 end
Checks that the given `param_values` hash contains all keys present in the `parameters` of this instance and that each keyed value is a match for the given parameter. The match is done using case expression semantics.
This method is only called when a given type is found to be assignable to the base type of this extension.
@param param_values the parameter values of the assignable type @param guard guard against endless recursion @return [Boolean] true or false to indicate assignability @api public
# File lib/puppet/pops/types/p_object_type_extension.rb 180 def test_assignable?(param_values, guard) 181 # Default implementation performs case expression style matching of all parameter values 182 # provided that the value exist (this should always be the case, since all defaults have 183 # been assigned at this point) 184 eval = Parser::EvaluatingParser.singleton.evaluator 185 @parameters.keys.all? do |pn| 186 if param_values.include?(pn) 187 a = param_values[pn] 188 b = @parameters[pn] 189 eval.match?(a, b) || a.is_a?(PAnyType) && b.is_a?(PAnyType) && b.assignable?(a) 190 else 191 false 192 end 193 end 194 end
Checks that the given instance `o` has one attribute for each key present in the `parameters` of this instance and that each attribute value is a match for the given parameter. The match is done using case expression semantics.
This method is only called when the given value is found to be an instance of the base type of this extension.
@param o [Object] the instance to test @param guard guard against endless recursion @return [Boolean] true or false to indicate if the value is an instance or not @api public
# File lib/puppet/pops/types/p_object_type_extension.rb 207 def test_instance?(o, guard) 208 eval = Parser::EvaluatingParser.singleton.evaluator 209 @parameters.keys.all? do |pn| 210 begin 211 m = o.public_method(pn) 212 m.arity == 0 ? eval.match?(m.call, @parameters[pn]) : false 213 rescue NameError 214 false 215 end 216 end 217 end