class Puppet::Pops::Binder::Producers::ArrayMultibindProducer

A configurable multibind producer for Array type multibindings.

This implementation collects all contributions to the multibind and then combines them using the following rules:

@note

Collection accepts elements that comply with the array's element type, or the entire type (i.e. Array[element_type]).
If the type is restrictive - e.g. Array[String] and an Array[String] is contributed, the result will not be type
compliant without also using the `:flatten` option, and a type error will be raised. For an array with relaxed typing
i.e. Array[Data], it is valid to produce a result such as `['a', ['b', 'c'], 'd']` and no flattening is required
and no error is raised (but using the array needs to be aware of potential array, non-array entries.
The use of the option `:flatten` controls how the result is flattened.

@api public

Attributes

flatten[R]

@return [Boolean, Integer] If result should be flattened (true), or not (false), or flattened to given level (0 = none, -1 = all) @api public

priority_on_named[R]

@return [Boolean] whether priority should be considered for named contributions @api public

priority_on_unnamed[R]

@return [Boolean] whether priority should be considered for unnamed contributions @api public

uniq[R]

@return [Boolean] whether the result should be made contain unique (non-equal) entries or not @api public

Protected Instance Methods

assert_type(binding, tc, value) click to toggle source

@api private

# File lib/puppet/pops/binder/producers.rb, line 655
def assert_type(binding, tc, value)
  infered = tc.infer(value)
  unless tc.assignable?(binding.type.element_type, infered) || tc.assignable?(binding.type, infered)
    raise ArgumentError, ["Type Error: contribution to '#{binding.name}' does not match type of multibind, ",
      "#{type_error_detail([binding.type.element_type, binding.type], value)}"].join()
  end
end
internal_produce(scope) click to toggle source

@api private

# File lib/puppet/pops/binder/producers.rb, line 615
def internal_produce(scope)
  seen = {}
  included_keys = []

  injector.get_contributions(scope, contributions_key).each do |element|
    key = element[0]
    entry = element[1]

    name = entry.binding.name
    existing = seen[name]
    empty_name = name.nil? || name.empty?
    if existing
      if empty_name && priority_on_unnamed
        if (seen[name] <=> entry) >= 0
          raise ArgumentError, "Duplicate key (same priority) contributed to Array Multibinding '#{binding.name}' with unnamed entry."
        end
        next
      elsif !empty_name && priority_on_named
        if (seen[name] <=> entry) >= 0
          raise ArgumentError, "Duplicate key (same priority) contributed to Array Multibinding '#{binding.name}', key: '#{name}'."
        end
        next
      end
    else
      seen[name] = entry
    end
    included_keys << key
  end
  result = included_keys.collect do |k|
    x = injector.lookup_key(scope, k)
    assert_type(binding(), injector.type_calculator(), x)
    x
  end

  result.flatten!(flatten) if flatten
  result.uniq! if uniq
  result
end

Public Class Methods

new(injector, binding, scope, options) click to toggle source

@param injector [Puppet::Pops::Binder::Injector] The injector where the lookup originates @param binding [Puppet::Pops::Binder::Bindings::Binding, nil] The binding using this producer @param scope [Puppet::Parser::Scope] The scope to use for evaluation @option options [Puppet::Pops::Model::LambdaExpression] :transformer (nil) a transformer of produced value @option options [Boolean] :uniq (false) if collected result should be post-processed to contain only unique entries @option options [Boolean, Integer] :flatten (false) if collected result should be post-processed so all contained arrays

are flattened. May be set to an Integer value to indicate the level of recursion (-1 is endless, 0 is none).

@option options [Boolean] :#priority_on_named (true) if highest precedented named element should win or if all should be included @option options [Boolean] :#priority_on_unnamed (false) if highest precedented unnamed element should win or if all should be included @api public

# File lib/puppet/pops/binder/producers.rb, line 592
def initialize(injector, binding, scope, options)
  super
  @uniq = !!options[:uniq]
  @flatten = options[:flatten]
  @priority_on_named = options[:priority_on_named].nil? ? true : options[:priority_on_name]
  @priority_on_unnamed = !!options[:priority_on_unnamed]

  case @flatten
  when Integer
  when true
    @flatten = -1
  when false
    @flatten = nil
  when NilClass
    @flatten = nil
  else
    raise ArgumentError, "Option :flatten must be nil, Boolean, or an integer value" unless @flatten.is_a?(Integer)
  end
end