@api private
Hash of key => InjectorEntry @api private
Produces an injectable class given a key, or nil if key does not represent an injectable class @api private
# File lib/puppet/pops/binder/injector.rb, line 563 def assistable_injected_class(key) kt = key_factory.get_type(key) return nil unless kt.is_a?(Puppet::Pops::Types::PRuntimeType) && kt.runtime == :ruby && !key_factory.is_named?(key) type_calculator.injectable_class(kt) end
Produces a key for a PDataType/name combination @api private
# File lib/puppet/pops/binder/injector.rb, line 479 def data_key(name) key_factory.data_key(name) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 663 def format_binding(b) Puppet::Pops::Binder::Binder.format_binding(b) end
Returns contributions to a multibind in precedence order; highest first. Returns an Array on the form [ [key, entry], [key, entry]] where the key is intended to be used to lookup the value (or a producer) for that entry. @api private
# File lib/puppet/pops/binder/injector.rb, line 552 def get_contributions(scope, contributions_key) result = {} return [] unless contributions = lookup_key(scope, contributions_key) contributions.each { |k| result[k] = get_entry(k) } result.sort {|a, b| a[0] <=> b[0] } #result.sort_by {|key, entry| entry } end
Should be used to get entries as it converts missing entries to NotFound entries or AssistedInject entries
@api private
# File lib/puppet/pops/binder/injector.rb, line 531 def get_entry(key) case entry = entries[ key ] when NilClass # not found, is this an assisted inject? if clazz = assistable_injected_class(key) entry = Producers::AssistedInjectProducer.new(self, clazz) entries[ key ] = entry else entries[ key ] = NotFound.new() entry = nil end when NotFound entry = nil end entry end
@api private
# File lib/puppet/pops/binder/injector.rb, line 439 def lookup(scope, *args, &block) raise ArgumentError, "lookup should be called with two or three arguments, got: #{args.size()+1}" unless args.size.between?(1,2) val = case args[ 0 ] when Puppet::Pops::Types::PAnyType lookup_type(scope, *args) when String raise ArgumentError, "lookup of name should only pass the name" unless args.size == 1 lookup_key(scope, key_factory.data_key(args[ 0 ])) else raise ArgumentError, 'lookup using a key should only pass a single key' unless args.size == 1 lookup_key(scope, args[ 0 ]) end # call block with result if given if block case block.arity when 1 block.call(val) when 2 block.call(scope, val) else raise ArgumentError, "The block should have arity 1 or 2" end else val end end
@api private
# File lib/puppet/pops/binder/injector.rb, line 500 def lookup_key(scope, key) if @recursion_lock.include?(key) raise ArgumentError, "Lookup loop detected for key: #{key}" end begin @recursion_lock.push(key) case entry = get_entry(key) when NilClass @parent ? @parent.lookup_key(scope, key) : nil when Puppet::Pops::Binder::InjectorEntry val = produce(scope, entry) return nil if val.nil? unless key_factory.type_calculator.instance?(entry.binding.type, val) raise "Type error: incompatible type returned by producer, #{type_error_detail(entry.binding.type, val)}" end val when Producers::AssistedInjectProducer entry.produce(scope) else # internal, direct entries entry end ensure @recursion_lock.pop() end end
# File lib/puppet/pops/binder/injector.rb, line 569 def lookup_producer(scope, *args, &block) raise ArgumentError, "lookup_producer should be called with two or three arguments, got: #{args.size()+1}" unless args.size <= 2 p = case args[ 0 ] when Puppet::Pops::Types::PAnyType lookup_producer_type(scope, *args) when String raise ArgumentError, "lookup_producer of name should only pass the name" unless args.size == 1 lookup_producer_key(scope, key_factory.data_key(args[ 0 ])) else raise ArgumentError, "lookup_producer using a key should only pass a single key" unless args.size == 1 lookup_producer_key(scope, args[ 0 ]) end # call block with result if given if block case block.arity when 1 block.call(p) when 2 block.call(scope, p) else raise ArgumentError, "The block should have arity 1 or 2" end else p end end
@api private
# File lib/puppet/pops/binder/injector.rb, line 601 def lookup_producer_key(scope, key) if @recursion_lock.include?(key) raise ArgumentError, "Lookup loop detected for key: #{key}" end begin @recursion_lock.push(key) producer(scope, get_entry(key), :multiple_use) ensure @recursion_lock.pop() end end
@api private
# File lib/puppet/pops/binder/injector.rb, line 614 def lookup_producer_type(scope, type, name='') lookup_producer_key(scope, named_key(type, name)) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 484 def lookup_type(scope, type, name='') val = lookup_key(scope, named_key(type, name)) return nil if val.nil? unless key_factory.type_calculator.instance?(type, val) raise ArgumentError, "Type error: incompatible type, #{type_error_detail(type, val)}" end val end
@api private
# File lib/puppet/pops/binder/injector.rb, line 713 def make_producer(clazz, descriptor, scope, entry, options) singleton_wrapped(descriptor, scope, entry, clazz.new(self, entry.binding, scope, options)) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 658 def merge_producer_options(binding, options) named_arguments_to_hash(binding.producer_args).merge(options) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 650 def named_arguments_to_hash(named_args) nb = named_args.nil? ? [] : named_args result = {} nb.each {|arg| result[ :"#{arg.name}" ] = arg.value } result end
Produces a key for a type/name combination. @api private
# File lib/puppet/pops/binder/injector.rb, line 473 def named_key(type, name) key_factory.named_key(type, name) end
Returns the produced instance @return [Object] the produced instance @api private
# File lib/puppet/pops/binder/injector.rb, line 644 def produce(scope, entry) return nil unless entry # not found producer(scope, entry, :single_use).produce(scope) end
Returns the producer for the entry @return [Puppet::Pops::Binder::Producers::Producer] the entry’s producer.
@api private
# File lib/puppet/pops/binder/injector.rb, line 623 def producer(scope, entry, use) return nil unless entry # not found return entry.producer(scope) if entry.is_a?(Producers::AssistedInjectProducer) unless entry.cached_producer entry.cached_producer = transform(entry.binding.producer, scope, entry) end unless entry.cached_producer raise ArgumentError, "Injector entry without a producer #{format_binding(entry.binding)}" end entry.cached_producer.producer(scope) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 757 def singleton?(descriptor) ! descriptor.eContainer().is_a?(Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 718 def singleton_wrapped(descriptor, scope, entry, producer) return producer unless singleton?(descriptor) Producers::SingletonProducer.new(self, entry.binding, scope, merge_producer_options(entry.binding, {:value => producer.produce(scope)})) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 636 def transform(producer_descriptor, scope, entry) @@transform_visitor.visit_this_2(self, producer_descriptor, scope, entry) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 685 def transform_ArrayMultibindProducerDescriptor(descriptor, scope, entry) make_producer(Producers::ArrayMultibindProducer, descriptor, scope, entry, named_arguments_to_hash(entry.binding.producer_args)) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 695 def transform_ConstantProducerDescriptor(descriptor, scope, entry) producer_class = singleton?(descriptor) ? Producers::SingletonProducer : Producers::DeepCloningProducer producer_class.new(self, entry.binding, scope, merge_producer_options(entry.binding, {:value => descriptor.value})) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 707 def transform_EvaluatingProducerDescriptor(descriptor, scope, entry) make_producer(Producers::EvaluatingProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:expression => descriptor.expression})) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 751 def transform_FirstFoundProducerDescriptor(descriptor, scope, entry) make_producer(Producers::FirstFoundProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:producers => descriptor.producers.collect {|p| transform(p, scope, entry) }})) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 739 def transform_HashLookupProducerDescriptor(descriptor, scope, entry) make_producer(Producers::LookupKeyProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:type => descriptor.type, :name => descriptor.name, :key => descriptor.key})) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 690 def transform_HashMultibindProducerDescriptor(descriptor, scope, entry) make_producer(Producers::HashMultibindProducer, descriptor, scope, entry, named_arguments_to_hash(entry.binding.producer_args)) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 701 def transform_InstanceProducerDescriptor(descriptor, scope, entry) make_producer(Producers::InstantiatingProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:class_name => descriptor.class_name, :init_args => descriptor.arguments})) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 733 def transform_LookupProducerDescriptor(descriptor, scope, entry) make_producer(Producers::LookupProducer, descriptor, scope, entry, merge_producer_options(entry.binding, {:type => descriptor.type, :name => descriptor.name})) end
Handles a missing producer (which is valid for a Multibinding where one is selected automatically) @api private
# File lib/puppet/pops/binder/injector.rb, line 670 def transform_NilClass(descriptor, scope, entry) unless entry.binding.is_a?(Puppet::Pops::Binder::Bindings::Multibinding) raise ArgumentError, "Binding without producer detected, #{format_binding(entry.binding)}" end case entry.binding.type when Puppet::Pops::Types::PArrayType transform(Puppet::Pops::Binder::Bindings::ArrayMultibindProducerDescriptor.new(), scope, entry) when Puppet::Pops::Types::PHashType transform(Puppet::Pops::Binder::Bindings::HashMultibindProducerDescriptor.new(), scope, entry) else raise ArgumentError, "Unsupported multibind type, must be an array or hash type, #{format_binding(entry.binding)}" end end
@api private
# File lib/puppet/pops/binder/injector.rb, line 745 def transform_NonCachingProducerDescriptor(descriptor, scope, entry) # simply delegates to the wrapped producer transform(descriptor.producer, scope, entry) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 725 def transform_ProducerProducerDescriptor(descriptor, scope, entry) p = transform(descriptor.producer, scope, entry) clazz = singleton?(descriptor) ? Producers::SingletonProducerProducer : Producers::ProducerProducer clazz.new(self, entry.binding, scope, merge_producer_options(entry.binding, merge_producer_options(entry.binding, { :producer_producer => p }))) end
@api private
# File lib/puppet/pops/binder/injector.rb, line 494 def type_error_detail(expected, actual) actual_t = type_calculator.infer(actual) "expected: #{type_calculator.string(expected)}, got: #{type_calculator.string(actual_t)}" end
# File lib/puppet/pops/binder/injector.rb, line 421 def initialize(configured_binder, parent_injector = nil) @binder = configured_binder @parent = parent_injector # TODO: Different error message raise ArgumentError, "Given Binder is not configured" unless configured_binder #&& configured_binder.configured?() @entries = configured_binder.injector_entries() # It is essential that the injector uses the same key factory as the binder since keys must be # represented the same (but still opaque) way. # @key_factory = configured_binder.key_factory() @type_calculator = key_factory.type_calculator() @@transform_visitor ||= Puppet::Pops::Visitor.new(nil,"transform", 2, 2) @recursion_lock = [ ] end