class Puppet::Pops::Binder::Injector::Private::InjectorImpl

@api private

Attributes

binder[R]
entries[R]

Hash of key => InjectorEntry @api private

key_factory[R]
type_calculator[R]

Public Instance Methods

assistable_injected_class(key) click to toggle source

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
data_key(name) click to toggle source

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
format_binding(b) click to toggle source

@api private

# File lib/puppet/pops/binder/injector.rb, line 663
def format_binding(b)
  Puppet::Pops::Binder::Binder.format_binding(b)
end
get_contributions(scope, contributions_key) click to toggle source

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
get_entry(key) click to toggle source

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
lookup(scope, *args, &block) click to toggle source

@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
lookup_key(scope, key) click to toggle source

@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
lookup_producer(scope, *args, &block) click to toggle source
# 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
lookup_producer_key(scope, key) click to toggle source

@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
lookup_producer_type(scope, type, name='') click to toggle source

@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
lookup_type(scope, type, name='') click to toggle source

@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
make_producer(clazz, descriptor, scope, entry, options) click to toggle source

@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
merge_producer_options(binding, options) click to toggle source

@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
named_arguments_to_hash(named_args) click to toggle source

@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
named_key(type, name) click to toggle source

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
produce(scope, entry) click to toggle source

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
producer(scope, entry, use) click to toggle source

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
singleton?(descriptor) click to toggle source

@api private

# File lib/puppet/pops/binder/injector.rb, line 757
def singleton?(descriptor)
  ! descriptor.eContainer().is_a?(Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor)
end
singleton_wrapped(descriptor, scope, entry, producer) click to toggle source

@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
transform(producer_descriptor, scope, entry) click to toggle source

@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
transform_ArrayMultibindProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
transform_ConstantProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
transform_EvaluatingProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
transform_FirstFoundProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
transform_HashLookupProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
transform_HashMultibindProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
transform_InstanceProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
transform_LookupProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
transform_NilClass(descriptor, scope, entry) click to toggle source

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
transform_NonCachingProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
transform_ProducerProducerDescriptor(descriptor, scope, entry) click to toggle source

@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
type_error_detail(expected, actual) click to toggle source

@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

Public Class Methods

new(configured_binder, parent_injector = nil) click to toggle source
# 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