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



563
564
565
566
567
# 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) ⇒ 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.



663
664
665
# 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) ⇒ 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
558
# 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) ⇒ 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)


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
598
# 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) ⇒ 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.



601
602
603
604
605
606
607
608
609
610
611
# 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 = '') ⇒ 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.



614
615
616
# 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 = '') ⇒ 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.



713
714
715
# 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) ⇒ 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.



658
659
660
# 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) ⇒ 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.



650
651
652
653
654
655
# 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) ⇒ 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



644
645
646
647
# 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) ⇒ 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:



623
624
625
626
627
628
629
630
631
632
633
# 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) ⇒ 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)


757
758
759
# 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) ⇒ 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.



718
719
720
721
722
# 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) ⇒ 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.



636
637
638
# 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) ⇒ 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.



685
686
687
# 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) ⇒ 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.



695
696
697
698
# 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) ⇒ 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.



707
708
709
710
# 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) ⇒ 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.



751
752
753
754
# 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) ⇒ 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.



739
740
741
742
# 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) ⇒ 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.



690
691
692
# 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) ⇒ 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.



701
702
703
704
# 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) ⇒ 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.



733
734
735
736
# 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) ⇒ 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)



670
671
672
673
674
675
676
677
678
679
680
681
682
# 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) ⇒ 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.



745
746
747
748
# 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) ⇒ 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.



725
726
727
728
729
730
# 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) ⇒ 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