Class: Puppet::Pops::Binder::Injector::Private::InjectorImpl Private

Inherits:
Object
  • Object
show all
Defined in:
lib/puppet/pops/binder/injector.rb

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Defined Under Namespace

Classes: NotFound

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(configured_binder, parent_injector = nil) ⇒ InjectorImpl

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of InjectorImpl.

Raises:

  • (ArgumentError)


421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
# 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

Instance Attribute Details

#binderObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



419
420
421
# File 'lib/puppet/pops/binder/injector.rb', line 419

def binder
  @binder
end

#entriesObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Hash of key => InjectorEntry



413
414
415
# File 'lib/puppet/pops/binder/injector.rb', line 413

def entries
  @entries
end

#key_factoryObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



415
416
417
# File 'lib/puppet/pops/binder/injector.rb', line 415

def key_factory
  @key_factory
end

#type_calculatorObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



417
418
419
# File 'lib/puppet/pops/binder/injector.rb', line 417

def type_calculator
  @type_calculator
end

Instance Method Details

#assistable_injected_class(key) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Produces an injectable class given a key, or nil if key does not represent an injectable class



562
563
564
565
566
# File 'lib/puppet/pops/binder/injector.rb', line 562

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Produces a key for a PDataType/name combination



479
480
481
# File 'lib/puppet/pops/binder/injector.rb', line 479

def data_key(name)
  key_factory.data_key(name)
end

#format_binding(b) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



662
663
664
# File 'lib/puppet/pops/binder/injector.rb', line 662

def format_binding(b)
  Puppet::Pops::Binder::Binder.format_binding(b)
end

#get_contributions(scope, contributions_key) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.



552
553
554
555
556
557
# 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] }
end

#get_entry(key) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Should be used to get entries as it converts missing entries to NotFound entries or AssistedInject entries



531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:

  • (ArgumentError)


439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:

  • (ArgumentError)


568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
# File 'lib/puppet/pops/binder/injector.rb', line 568

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



600
601
602
603
604
605
606
607
608
609
610
# File 'lib/puppet/pops/binder/injector.rb', line 600

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 = '') ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



613
614
615
# File 'lib/puppet/pops/binder/injector.rb', line 613

def lookup_producer_type(scope, type, name='')
  lookup_producer_key(scope, named_key(type, name))
end

#lookup_type(scope, type, name = '') ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



484
485
486
487
488
489
490
491
# 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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



712
713
714
# File 'lib/puppet/pops/binder/injector.rb', line 712

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



657
658
659
# File 'lib/puppet/pops/binder/injector.rb', line 657

def merge_producer_options(binding, options)
  named_arguments_to_hash(binding.producer_args).merge(options)
end

#named_arguments_to_hash(named_args) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



649
650
651
652
653
654
# File 'lib/puppet/pops/binder/injector.rb', line 649

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Produces a key for a type/name combination.



473
474
475
# File 'lib/puppet/pops/binder/injector.rb', line 473

def named_key(type, name)
  key_factory.named_key(type, name)
end

#produce(scope, entry) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the produced instance

Returns:

  • (Object)

    the produced instance



643
644
645
646
# File 'lib/puppet/pops/binder/injector.rb', line 643

def produce(scope, entry)
  return nil unless entry # not found
  producer(scope, entry, :single_use).produce(scope)
end

#producer(scope, entry, use) ⇒ Puppet::Pops::Binder::Producers::Producer

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the producer for the entry

Returns:



622
623
624
625
626
627
628
629
630
631
632
# File 'lib/puppet/pops/binder/injector.rb', line 622

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) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


756
757
758
# File 'lib/puppet/pops/binder/injector.rb', line 756

def singleton?(descriptor)
  ! descriptor.eContainer().is_a?(Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor)
end

#singleton_wrapped(descriptor, scope, entry, producer) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



717
718
719
720
721
# File 'lib/puppet/pops/binder/injector.rb', line 717

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



635
636
637
# File 'lib/puppet/pops/binder/injector.rb', line 635

def transform(producer_descriptor, scope, entry)
  @@transform_visitor.visit_this_2(self, producer_descriptor, scope, entry)
end

#transform_ArrayMultibindProducerDescriptor(descriptor, scope, entry) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



684
685
686
# File 'lib/puppet/pops/binder/injector.rb', line 684

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



694
695
696
697
# File 'lib/puppet/pops/binder/injector.rb', line 694

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



706
707
708
709
# File 'lib/puppet/pops/binder/injector.rb', line 706

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



750
751
752
753
# File 'lib/puppet/pops/binder/injector.rb', line 750

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



738
739
740
741
# File 'lib/puppet/pops/binder/injector.rb', line 738

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



689
690
691
# File 'lib/puppet/pops/binder/injector.rb', line 689

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



700
701
702
703
# File 'lib/puppet/pops/binder/injector.rb', line 700

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



732
733
734
735
# File 'lib/puppet/pops/binder/injector.rb', line 732

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Handles a missing producer (which is valid for a Multibinding where one is selected automatically)



669
670
671
672
673
674
675
676
677
678
679
680
681
# File 'lib/puppet/pops/binder/injector.rb', line 669

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



744
745
746
747
# File 'lib/puppet/pops/binder/injector.rb', line 744

def transform_NonCachingProducerDescriptor(descriptor, scope, entry)
  # simply delegates to the wrapped producer
  transform(descriptor.producer, scope, entry)
end

#transform_ProducerProducerDescriptor(descriptor, scope, entry) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



724
725
726
727
728
729
# File 'lib/puppet/pops/binder/injector.rb', line 724

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) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



494
495
496
497
# 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