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)


423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# File 'lib/puppet/pops/binder/injector.rb', line 423

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     = Types::TypeCalculator.singleton
  @@transform_visitor ||= 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.



421
422
423
# File 'lib/puppet/pops/binder/injector.rb', line 421

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



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

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.



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

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.



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

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



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

def assistable_injected_class(key)
  kt = key_factory.get_type(key)
  return nil unless kt.is_a?(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



481
482
483
# File 'lib/puppet/pops/binder/injector.rb', line 481

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.



664
665
666
# File 'lib/puppet/pops/binder/injector.rb', line 664

def format_binding(b)
  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.



554
555
556
557
558
559
# File 'lib/puppet/pops/binder/injector.rb', line 554

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



533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
# File 'lib/puppet/pops/binder/injector.rb', line 533

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)


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
470
471
# File 'lib/puppet/pops/binder/injector.rb', line 441

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 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.



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
527
528
# File 'lib/puppet/pops/binder/injector.rb', line 502

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 InjectorEntry
      val = produce(scope, entry)
      return nil if val.nil?
      unless 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)


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
598
599
# File 'lib/puppet/pops/binder/injector.rb', line 570

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 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.



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

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.



615
616
617
# File 'lib/puppet/pops/binder/injector.rb', line 615

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.



486
487
488
489
490
491
492
493
# File 'lib/puppet/pops/binder/injector.rb', line 486

def lookup_type(scope, type, name='')
  val = lookup_key(scope, named_key(type, name))
  return nil if val.nil?
  unless 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.



714
715
716
# File 'lib/puppet/pops/binder/injector.rb', line 714

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.



659
660
661
# File 'lib/puppet/pops/binder/injector.rb', line 659

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.



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

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.



475
476
477
# File 'lib/puppet/pops/binder/injector.rb', line 475

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



645
646
647
648
# File 'lib/puppet/pops/binder/injector.rb', line 645

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

#producer(scope, entry, use) ⇒ 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:



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

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)


758
759
760
# File 'lib/puppet/pops/binder/injector.rb', line 758

def singleton?(descriptor)
  ! descriptor.eContainer().is_a?(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.



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

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.



637
638
639
# File 'lib/puppet/pops/binder/injector.rb', line 637

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.



686
687
688
# File 'lib/puppet/pops/binder/injector.rb', line 686

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.



696
697
698
699
# File 'lib/puppet/pops/binder/injector.rb', line 696

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.



708
709
710
711
# File 'lib/puppet/pops/binder/injector.rb', line 708

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.



752
753
754
755
# File 'lib/puppet/pops/binder/injector.rb', line 752

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.



740
741
742
743
# File 'lib/puppet/pops/binder/injector.rb', line 740

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.



691
692
693
# File 'lib/puppet/pops/binder/injector.rb', line 691

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.



702
703
704
705
# File 'lib/puppet/pops/binder/injector.rb', line 702

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.



734
735
736
737
# File 'lib/puppet/pops/binder/injector.rb', line 734

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)



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

def transform_NilClass(descriptor, scope, entry)
  unless entry.binding.is_a?(Bindings::Multibinding)
    raise ArgumentError, "Binding without producer detected, #{format_binding(entry.binding)}"
  end
  case entry.binding.type
  when Types::PArrayType
    transform(Bindings::ArrayMultibindProducerDescriptor.new(), scope, entry)
  when Types::PHashType
    transform(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.



746
747
748
749
# File 'lib/puppet/pops/binder/injector.rb', line 746

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.



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

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.



496
497
498
499
# File 'lib/puppet/pops/binder/injector.rb', line 496

def type_error_detail(expected, actual)
  actual_t = type_calculator.infer(actual)
  "expected: #{expected}, got: #{actual_t}"
end