A helper class that makes it easier to construct a Bindings model.
The BindingsModel (defined in {Puppet::Pops::Binder::Bindings} is a model that is intended to be generally free from Ruby concerns. This means that it is possible for system integrators to create and serialize such models using other technologies than Ruby. This manifests itself in the model in that producers are described using instances of a `ProducerDescriptor` rather than describing Ruby classes directly. This is also true of the type system where type is expressed using the {Puppet::Pops::Types} model to describe all types.
This class, the `BindingsFactory` is a concrete Ruby API for constructing instances of classes in the model.
Named Bindings
The typical usage of the factory is to call {Puppet::Pops::Binder::BindingsFactory.named_bindings} which creates a container of bindings wrapped in a *build object* equipped with convenience methods to define the details of the just created named bindings. The returned builder is an instance of {Puppet::Pops::Binder::BindingsFactory::BindingsContainerBuilder BindingsContainerBuilder}.
Binding
A Binding binds a type/name key to a producer of a value. A binding is conveniently created by calling `bind` on a `BindingsContainerBuilder`. The call to bind, produces a binding wrapped in a build object equipped with convenience methods to define the details of the just created binding. The returned builder is an instance of {Puppet::Pops::Binder::BindingsFactory::BindingsBuilder BindingsBuilder}.
Multibinding
A multibinding works like a binding, but it requires an additional ID. It also places constraints on the type of the binding; it must be a collection type (Hash or Array).
Constructing and Contributing Bindings from Ruby
The bindings system is used by referencing bindings symbolically; these are then specified in a Ruby file which is autoloaded by Puppet. The entry point for user code that creates bindings is described in {Puppet::Bindings Bindings}. That class makes use of a BindingsFactory, and the builder objects to make it easy to construct bindings.
It is intended that a user defining bindings in Ruby should be able to use the builder object methods for the majority of tasks. If something advanced is wanted, use of one of the helper class methods on the BuildingsFactory, and/or the {Puppet::Pops::Types::TypeCalculator TypeCalculator} will be required to create and configure objects that are not handled by the methods in the builder objects.
Chaining of calls
Since all the build methods return the build object it is easy to stack on additional calls. The intention is to do this in an order that is readable from left to right: `bind.string.name(‘thename’).to(42)`, but there is nothing preventing making the calls in some other order e.g. `bind.to(42).name(‘thename’).string`, the second is quite unreadable but produces the same result.
For sake of human readability, the method `name` is alsp available as `named`, with the intention that it is used after a type, e.g. `bind.integer.named(‘the meaning of life’).to(42)`
Methods taking blocks
Several methods take an optional block. The block evaluates with the builder object as `self`. This means that there is no need to chain the methods calls, they can instead be made in sequence - e.g.
bind do integer named 'the meaning of life' to 42 end
or mix the two styles
bind do integer.named 'the meaning of life' to 42 end
Unwrapping the result
The result from all methods is a builder object. Call the method `model` to unwrap the constructed bindings model object.
bindings = BindingsFactory.named_bindings('my named bindings') do
# bind things
end.model
@example Create a NamedBinding with content
result = Puppet::Pops::Binder::BindingsFactory.named_bindings("mymodule::mybindings") do
bind.name("foo").to(42)
bind.string.name("site url").to("http://www.example.com")
end
result.model()
@api public
Alias for the {Puppet::Pops::Types::TypeFactory TypeFactory}. This is also available as the method `type_factory`.
Produces a ContributedBindings. A ContributedBindings is used by bindings providers to return a set of named bindings.
@param name [String] the name of the contributed bindings (for human use in messages/logs only) @param ::named_bindings [Puppet::Pops::Binder::Bindings::NamedBindings, Array<Puppet::Pops::Binder::Bindings::NamedBindings>] the
named bindings to include
# File lib/puppet/pops/binder/bindings_factory.rb, line 599 def self.contributed_bindings(name, named_bindings) cb = Puppet::Pops::Binder::Bindings::ContributedBindings.new() cb.name = name named_bindings = [named_bindings] unless named_bindings.is_a?(Array) named_bindings.each {|b| cb.addBindings(b) } cb end
Creates an evaluating producer that evaluates a puppet expression. A puppet expression is most conveniently created by using the {Puppet::Pops::Parser::EvaluatingParser EvaluatingParser} as it performs all set up and validation of the parsed source. Two convenience methods are used to parse an expression, or parse a ruby string as a puppet string. See methods {::puppet_expression}, {::puppet_string} and {parser} for more information.
@example producing a puppet expression
expr = puppet_string("Interpolated $fqdn", __FILE__)
@param expression [Puppet::Pops::Model::Expression] a puppet DSL expression as producer by the eparser. @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer descriptor @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 748 def self.evaluating_producer(expression) p = Puppet::Pops::Binder::Bindings::EvaluatingProducerDescriptor.new() p.expression = expression p end
Creates a first-found producer that looks up from a given series of keys. The first found looked up value will be produced. @param producers [Array<Puppet::Pops::Binder::Bindings::ProducerDescriptor>] the producers to consult in given order @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer descriptor @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 730 def self.first_found_producer(*producers) p = Puppet::Pops::Binder::Bindings::FirstFoundProducerDescriptor.new() producers.each {|p2| p.addProducers(p2) } p end
Creates a Hash lookup producer that looks up a hash value, and then a key in the hash.
@return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description @param type [Puppet::Pops::Types::PAnyType] the type to lookup (i.e. a Hash of some key/value type). @param name [String] the name to lookup @param key [Object] the key to lookup in the looked up hash (type should comply with given key type). @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 717 def self.hash_lookup_producer(type, name, key) p = Puppet::Pops::Binder::Bindings::HashLookupProducerDescriptor.new() p.type = type p.name = name p.key = key p end
Creates an instance producer An instance producer creates a new instance of a class. If the class implements the class method `inject` this method is called instead of `new` to allow further lookups to take place. This is referred to as *assisted inject*. If the class method `inject` is missing, the regular `new` method is called.
@param class_name [String] the name of the class @param args arguments to the class’ `new` method. @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 690 def self.instance_producer(class_name, *args) p = Puppet::Pops::Binder::Bindings::InstanceProducerDescriptor.new() p.class_name = class_name args.each {|a| p.addArguments(a) } p end
Create a LayeredBindings. This is used by the bindings system to create a model of all given layers. @param named_layers [Puppet::Pops::Binder::Bindings::NamedLayer] one or more named layers @return [Puppet::Pops::Binder::Bindings::LayeredBindings] the constructed layered bindings. @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 770 def self.layered_bindings(*named_layers) result = Puppet::Pops::Binder::Bindings::LayeredBindings.new() named_layers.each {|b| result.addLayers(b) } result end
Creates a literal/constant producer @param value [Object] the value to produce @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 651 def self.literal_producer(value) producer = Puppet::Pops::Binder::Bindings::ConstantProducerDescriptor.new() producer.value = value producer end
Creates a Producer that looks up a value. @param type [Puppet::Pops::Types::PAnyType] the type to lookup @param name [String] the name to lookup @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 702 def self.lookup_producer(type, name) p = Puppet::Pops::Binder::Bindings::LookupProducerDescriptor.new() p.type = type p.name = name p end
Creates a named binding container, the top bindings model object. A NamedBindings is typically produced by a bindings provider.
The created container is wrapped in a BindingsContainerBuilder for further detailing. Unwrap the built result when done. @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 614 def self.named_bindings(name, &block) binding = Puppet::Pops::Binder::Bindings::NamedBindings.new() binding.name = name builder = BindingsContainerBuilder.new(binding) builder.instance_eval(&block) if block_given? builder end
Creates a NamedLayer. This is used by the bindings system to create a model of the layers.
@api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 758 def self.named_layer(name, *bindings) result = Puppet::Pops::Binder::Bindings::NamedLayer.new() result.name = name bindings.each { |b| result.addBindings(b) } result end
# File lib/puppet/pops/binder/bindings_factory.rb, line 631 def initialize(b) super b end
Creates a non caching producer @param producer [Puppet::Pops::Binder::Bindings::Producer] the producer to make non caching @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 662 def self.non_caching_producer(producer) p = Puppet::Pops::Binder::Bindings::NonCachingProducerDescriptor.new() p.producer = producer p end
@return [Puppet::Pops::Parser::EvaluatingParser] a parser for puppet expressions
# File lib/puppet/pops/binder/bindings_factory.rb, line 777 def self.parser @parser ||= Puppet::Pops::Parser::EvaluatingParser.new() end
Creates a producer producer @param producer [Puppet::Pops::Binder::Bindings::Producer] a producer producing a Producer. @return [Puppet::Pops::Binder::Bindings::ProducerDescriptor] a producer description @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 673 def self.producer_producer(producer) p = Puppet::Pops::Binder::Bindings::ProducerProducerDescriptor.new() p.producer = producer p end
Parses and produces a puppet expression from the given string. @param string [String] puppet source e.g. “1 + 2” @param source_file [String] the source location, typically `__File__` @return [Puppet::Pops::Model::Expression] an expression (that can be bound) @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 787 def self.puppet_expression(string, source_file) parser.parse_string(string, source_file).current end
Parses and produces a puppet string expression from the given string. The string will automatically be quoted and special characters escaped. As an example if given the (ruby) string “HinMary” it is transformed to the puppet string (illustrated with a ruby string) “"Hi\nMary”” before being parsed.
@param string [String] puppet source e.g. “On node $!{fqdn}” @param source_file [String] the source location, typically `__File__` @return [Puppet::Pops::Model::Expression] an expression (that can be bound) @api public
# File lib/puppet/pops/binder/bindings_factory.rb, line 802 def self.puppet_string(string, source_file) parser.parse_string(parser.quote(string), source_file).current end
This variant of {::named_bindings} evaluates the given block as a method on an anonymous class, thus, if the block defines methods or do something with the class itself, this does not pollute the base class (BindingsContainerBuilder). @api private
# File lib/puppet/pops/binder/bindings_factory.rb, line 627 def self.safe_named_bindings(name, scope, &block) binding = Puppet::Pops::Binder::Bindings::NamedBindings.new() binding.name = name anon = Class.new(BindingsContainerBuilder) do def initialize(b) super b end end anon.send(:define_method, :_produce, block) builder = anon.new(binding) case block.arity when 0 builder._produce() when 1 builder._produce(scope) end builder end