Class: Puppet::Pops::Binder::Injector
- Defined in:
- lib/puppet/pops/binder/injector.rb
Overview
The injector is the “lookup service” class
Initialization
The injector is initialized with a configured Binder. The Binder instance contains a resolved set of ‘key => “binding information”` that is used to setup the injector.
Lookup
It is possible to lookup either the value, or a producer of the value. The #lookup method looks up a value, and the #lookup_producer looks up a producer. Both of these methods can be called with three different signatures; ‘lookup(key)`, `lookup(type, name)`, and `lookup(name)`, with the corresponding calls to obtain a producer; `lookup_producer(key)`, `lookup_producer(type, name)`, and `lookup_producer(name)`.
It is possible to pass a block to #lookup and #lookup_producer, the block is passed the result of the lookup and the result of the block is returned as the value of the lookup. This is useful in order to provide a default value.
Singleton or Not
The lookup of a value is always based on the lookup of a producer. For *singleton producers* this means that the value is determined by the first value lookup. Subsequent lookups via ‘lookup` or `lookup_producer` will produce the same instance.
*Non singleton producers* will produce a new instance on each request for a value. For constant value producers this means that a new deep-clone is produced for mutable objects (but not for immutable objects as this is not needed). Custom producers should have non singleton behavior, or if this is not possible ensure that the produced result is immutable. (The behavior if a custom producer hands out a mutable value and this is mutated is undefined).
Custom bound producers capable of producing a series of objects when bound as a singleton means that the producer is a singleton, not the value it produces. If such a producer is bound as non singleton, each ‘lookup` will get a new producer (hence, typically, restarting the series). However, the producer returned from `lookup_producer` will not recreate the producer on each call to `produce`; i.e. each `lookup_producer` returns a producer capable of returning a series of objects.
Assisted Inject
The injector supports lookup of instances of classes *even if the requested class is not explicitly bound*. This is possible for classes that have a zero argument ‘initialize` method, or that has a class method called `inject` that takes two arguments; `injector`, and `scope`. This is useful in ruby logic as a class can then use the given injector to inject details. An `inject` class method wins over a zero argument `initialize` in all cases.
Access to key factory and type calculator
It is important to use the same key factory, and type calculator as the binder. It is therefor possible to obtain these with the methods #key_factory, and #type_calculator.
Special support for producers
There is one method specially designed for producers. The #get_contributions method returns an array of all contributions to a given *contributions key*. This key is obtained from the #key_factory for a given multibinding. The returned set of contributed bindings is sorted in descending precedence order. Any conflicts, merges, etc. is performed by the multibinding producer configured for a multibinding.
Defined Under Namespace
Modules: Private
Constant Summary collapse
Class Method Summary collapse
-
.create(name, &block) ⇒ Object
Creates an injector with a single bindings layer created with the given name, and the bindings produced by the given block.
- .create_from_hash(name, key_value_hash) ⇒ Object
- .create_from_model(layered_bindings_model) ⇒ Object
-
.null_injector ⇒ Object
Returns an Injector that returns (or yields) nil on all lookups, and produces an empty structure for contributions This method is intended for testing purposes.
Instance Method Summary collapse
-
#get_contributions(scope, contributions_key) ⇒ Array<Puppet::Pops::Binder::InjectorEntry>
Returns the contributions to a multibind given its contribution key (as produced by the KeyFactory).
-
#initialize(configured_binder, parent_injector = nil) ⇒ Injector
constructor
An Injector is initialized with a configured Binder.
-
#key_factory ⇒ Puppet::Pops::Binder::KeyFactory
The KeyFactory used to produce keys in this injector.
-
#lookup(scope, *args) {|value| ... } ⇒ Object
Lookup (a.k.a “inject”) of a value given a key.
-
#lookup_key(scope, key) ⇒ Object?
Looks up the key and returns the entry, or nil if no entry is found.
-
#lookup_producer(scope, *args) {|producer| ... } ⇒ Puppet::Pops::Binder::Producers::Producer, ...
Lookup (a.k.a “inject”) producer of a value given a key.
-
#lookup_producer_key(scope, key) ⇒ Puppet::Pops::Binder::Producers::Producer?
Looks up a Producer given an opaque binder key.
-
#lookup_producer_type(scope, type, name = '') ⇒ Puppet::Pops::Binder::Producers::Producer?
Looks up a Producer given a type/name key.
-
#lookup_type(scope, type, name = '') ⇒ Object?
Looks up a (typesafe) value based on a type/name combination.
-
#override(name, &block) ⇒ Object
Creates an overriding injector with a single bindings layer created with the given name, and the bindings produced by the given block.
-
#override_with_hash(name, key_value_hash) ⇒ Object
Creates an overriding injector with a single bindings layer created with the given name, and the bindings given in the key_value_hash.
-
#override_with_model(layered_bindings) ⇒ Object
Creates an overriding injector with bindings from a bindings model (a LayeredBindings) which may consists of multiple layers of bindings.
-
#type_calculator ⇒ Puppet::Pops::Types::TypeCalculator
Returns the TypeCalculator in use for keys.
Constructor Details
#initialize(configured_binder, parent_injector = nil) ⇒ Injector
An Injector is initialized with a configured Binder.
164 165 166 167 168 169 170 |
# File 'lib/puppet/pops/binder/injector.rb', line 164 def initialize(configured_binder, parent_injector = nil) if configured_binder.nil? @impl = Private::NullInjectorImpl.new() else @impl = Private::InjectorImpl.new(configured_binder, parent_injector) end end |
Class Method Details
.create(name, &block) ⇒ Object
Creates an injector with a single bindings layer created with the given name, and the bindings produced by the given block. The block is evaluated with self bound to a BindingsContainerBuilder.
110 111 112 113 114 |
# File 'lib/puppet/pops/binder/injector.rb', line 110 def self.create(name, &block) factory = Puppet::Pops::Binder::BindingsFactory layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',factory.named_bindings(name, &block).model)) self.new(Puppet::Pops::Binder::Binder.new(layered_bindings)) end |
.create_from_hash(name, key_value_hash) ⇒ Object
93 94 95 96 97 98 |
# File 'lib/puppet/pops/binder/injector.rb', line 93 def self.create_from_hash(name, key_value_hash) factory = Puppet::Pops::Binder::BindingsFactory named_bindings = factory.named_bindings(name) { key_value_hash.each {|k,v| bind.name(k).to(v) }} layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',named_bindings.model)) self.new(Puppet::Pops::Binder::Binder.new(layered_bindings)) end |
.create_from_model(layered_bindings_model) ⇒ Object
89 90 91 |
# File 'lib/puppet/pops/binder/injector.rb', line 89 def self.create_from_model(layered_bindings_model) self.new(Puppet::Pops::Binder::Binder.new(layered_bindings_model)) end |
.null_injector ⇒ Object
Returns an Injector that returns (or yields) nil on all lookups, and produces an empty structure for contributions This method is intended for testing purposes.
337 338 339 |
# File 'lib/puppet/pops/binder/injector.rb', line 337 def self.null_injector self.new(nil) end |
Instance Method Details
#get_contributions(scope, contributions_key) ⇒ Array<Puppet::Pops::Binder::InjectorEntry>
Returns the contributions to a multibind given its contribution key (as produced by the KeyFactory). This method is typically used by multibind value producers, but may be used for introspection of the injector’s state.
330 331 332 |
# File 'lib/puppet/pops/binder/injector.rb', line 330 def get_contributions(scope, contributions_key) @impl.get_contributions(scope, contributions_key) end |
#key_factory ⇒ Puppet::Pops::Binder::KeyFactory
The KeyFactory used to produce keys in this injector. The factory is shared with the Binder to ensure consistent translation to keys. A compatible type calculator can also be obtained from the key factory.
179 180 181 |
# File 'lib/puppet/pops/binder/injector.rb', line 179 def key_factory() @impl.key_factory end |
#lookup(scope, key) ⇒ Object #lookup(scope, type, name = '') ⇒ Object #lookup(scope, name) ⇒ Object
Lookup (a.k.a “inject”) of a value given a key. The lookup may be called with different parameters. This method is a convenience method that dispatches to one of #lookup_key or #lookup_type depending on the arguments. It also provides the ability to use an optional block that is called with the looked up value, or scope and value if the block takes two parameters. This is useful to provide a default value or other transformations, calculations based on the result of the lookup.
226 227 228 |
# File 'lib/puppet/pops/binder/injector.rb', line 226 def lookup(scope, *args, &block) @impl.lookup(scope, *args, &block) end |
#lookup_key(scope, key) ⇒ Object?
Looks up the key and returns the entry, or nil if no entry is found. Produced type is checked for type conformance with its binding, but not with the lookup key. (This since all subtypes of PDataType are looked up using a key based on PDataType). Use the Puppet::Pops::Types::TypeCalculator#instance? method to check for conformance of the result if this is wanted, or use #lookup_type.
259 260 261 |
# File 'lib/puppet/pops/binder/injector.rb', line 259 def lookup_key(scope, key) @impl.lookup_key(scope, key) end |
#lookup_producer(scope, key) ⇒ Puppet::Pops::Binder::Producers::Producer, ... #lookup_producer(scope, type, name = '') ⇒ Puppet::Pops::Binder::Producers::Producer, ... #lookup_producer(scope, name) ⇒ Puppet::Pops::Binder::Producers::Producer, ...
Lookup (a.k.a “inject”) producer of a value given a key. The producer lookup may be called with different parameters. This method is a convenience method that dispatches to one of #lookup_producer_key or #lookup_producer_type depending on the arguments. It also provides the ability to use an optional block that is called with the looked up producer, or scope and producer if the block takes two parameters. This is useful to provide a default value, call a custom producer method, or other transformations, calculations based on the result of the lookup.
298 299 300 |
# File 'lib/puppet/pops/binder/injector.rb', line 298 def lookup_producer(scope, *args, &block) @impl.lookup_producer(scope, *args, &block) end |
#lookup_producer_key(scope, key) ⇒ Puppet::Pops::Binder::Producers::Producer?
Looks up a Producer given an opaque binder key.
307 308 309 |
# File 'lib/puppet/pops/binder/injector.rb', line 307 def lookup_producer_key(scope, key) @impl.lookup_producer_key(scope, key) end |
#lookup_producer_type(scope, type, name = '') ⇒ Puppet::Pops::Binder::Producers::Producer?
The result is not type checked (it cannot be until the producer has produced an instance).
Looks up a Producer given a type/name key.
317 318 319 |
# File 'lib/puppet/pops/binder/injector.rb', line 317 def lookup_producer_type(scope, type, name='') @impl.lookup_producer_type(scope, type, name) end |
#lookup_type(scope, type, name = '') ⇒ Object?
Looks up a (typesafe) value based on a type/name combination. Creates a key for the type/name combination using a KeyFactory. Specialization of the Data type are transformed to a Data key, and the result is type checked to conform with the given key.
243 244 245 |
# File 'lib/puppet/pops/binder/injector.rb', line 243 def lookup_type(scope, type, name='') @impl.lookup_type(scope, type, name) end |
#override(name, &block) ⇒ Object
Creates an overriding injector with a single bindings layer created with the given name, and the bindings produced by the given block. The block is evaluated with self bound to a BindingsContainerBuilder.
127 128 129 130 131 |
# File 'lib/puppet/pops/binder/injector.rb', line 127 def override(name, &block) factory = Puppet::Pops::Binder::BindingsFactory layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',factory.named_bindings(name, &block).model)) self.class.new(Puppet::Pops::Binder::Binder.new(layered_bindings, @impl.binder)) end |
#override_with_hash(name, key_value_hash) ⇒ Object
Creates an overriding injector with a single bindings layer created with the given name, and the bindings given in the key_value_hash
149 150 151 152 153 154 |
# File 'lib/puppet/pops/binder/injector.rb', line 149 def override_with_hash(name, key_value_hash) factory = Puppet::Pops::Binder::BindingsFactory named_bindings = factory.named_bindings(name) { key_value_hash.each {|k,v| bind.name(k).to(v) }} layered_bindings = factory.layered_bindings(factory.named_layer(name+'-layer',named_bindings.model)) self.class.new(Puppet::Pops::Binder::Binder.new(layered_bindings, @impl.binder)) end |
#override_with_model(layered_bindings) ⇒ Object
Creates an overriding injector with bindings from a bindings model (a LayeredBindings) which may consists of multiple layers of bindings.
138 139 140 141 142 143 |
# File 'lib/puppet/pops/binder/injector.rb', line 138 def override_with_model(layered_bindings) unless layered_bindings.is_a?(Puppet::Pops::Binder::Bindings::LayeredBindings) raise ArgumentError, "Expected a LayeredBindings model, got '#{bindings_model.class}'" end self.class.new(Puppet::Pops::Binder::Binder.new(layered_bindings, @impl.binder)) end |
#type_calculator ⇒ Puppet::Pops::Types::TypeCalculator
Returns the TypeCalculator in use for keys. The same calculator (as used for keys) should be used if there is a need to check type conformance, or infer the type of Ruby objects.
189 190 191 |
# File 'lib/puppet/pops/binder/injector.rb', line 189 def type_calculator() @impl.type_calculator() end |