module Puppet::Pops::Binder::SystemBindings::Factory

A helper class that makes it easier to construct a Bindings model.

The 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

Constants

T

Alias for the {Puppet::Pops::Types::TypeFactory TypeFactory}. This is also available as the method `type_factory`.

Public Class Methods

contributed_bindings(name, named_bindings) click to toggle source

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
evaluating_producer(expression) click to toggle source

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
first_found_producer(*producers) click to toggle source

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
hash_lookup_producer(type, name, key) click to toggle source

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
instance_producer(class_name, *args) click to toggle source

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
layered_bindings(*named_layers) click to toggle source

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
literal_producer(value) click to toggle source

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
lookup_producer(type, name) click to toggle source

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
named_bindings(name, &block) click to toggle source

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
named_layer(name, *bindings) click to toggle source

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
new(b) click to toggle source
# File lib/puppet/pops/binder/bindings_factory.rb, line 631
def initialize(b)
  super b
end
non_caching_producer(producer) click to toggle source

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
parser() click to toggle source

@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
producer_producer(producer) click to toggle source

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
puppet_expression(string, source_file) click to toggle source

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
puppet_string(string, source_file) click to toggle source

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
safe_named_bindings(name, scope, &block) click to toggle source

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