Module: Puppet::Pops::Binder::BindingsFactory

Defined in:
lib/puppet/pops/binder/bindings_factory.rb

Overview

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

The Bindings Model


The BindingsModel (defined in 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 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 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 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 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 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 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

Examples:

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()

Defined Under Namespace

Classes: AbstractBuilder, BindingsBuilder, BindingsContainerBuilder, MultibindingsBuilder

Constant Summary collapse

T =

Alias for the TypeFactory. This is also available as the method ‘type_factory`.

Puppet::Pops::Types::TypeFactory

Class Method Summary collapse

Class Method Details

.contributed_bindings(name, named_bindings) ⇒ Object

Produces a ContributedBindings. A ContributedBindings is used by bindings providers to return a set of named bindings.

Parameters:



599
600
601
602
603
604
605
# 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) ⇒ Puppet::Pops::Binder::Bindings::ProducerDescriptor

Creates an evaluating producer that evaluates a puppet expression. A puppet expression is most conveniently created by using the 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.

Examples:

producing a puppet expression

expr = puppet_string("Interpolated $fqdn", __FILE__)

Parameters:

Returns:



748
749
750
751
752
# 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) ⇒ Puppet::Pops::Binder::Bindings::ProducerDescriptor

Creates a first-found producer that looks up from a given series of keys. The first found looked up value will be produced.

Parameters:

Returns:



730
731
732
733
734
# 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) ⇒ Puppet::Pops::Binder::Bindings::ProducerDescriptor

Creates a Hash lookup producer that looks up a hash value, and then a key in the hash.

Parameters:

  • type (Puppet::Pops::Types::PAnyType)

    the type to lookup (i.e. a Hash of some key/value type).

  • name (String)

    the name to lookup

  • key (Object)

    the key to lookup in the looked up hash (type should comply with given key type).

Returns:



717
718
719
720
721
722
723
# 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) ⇒ Puppet::Pops::Binder::Bindings::ProducerDescriptor

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.

Parameters:

  • class_name (String)

    the name of the class

  • args (Object)

    arguments to the class’ ‘new` method.

Returns:



690
691
692
693
694
695
# 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) ⇒ Puppet::Pops::Binder::Bindings::LayeredBindings

Create a LayeredBindings. This is used by the bindings system to create a model of all given layers.

Parameters:

Returns:



770
771
772
773
774
# 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) ⇒ Puppet::Pops::Binder::Bindings::ProducerDescriptor

Creates a literal/constant producer

Parameters:

  • value (Object)

    the value to produce

Returns:



651
652
653
654
655
# 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) ⇒ Puppet::Pops::Binder::Bindings::ProducerDescriptor

Creates a Producer that looks up a value.

Parameters:

Returns:



702
703
704
705
706
707
# 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) ⇒ Object

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.



614
615
616
617
618
619
620
# 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) ⇒ Object

Creates a NamedLayer. This is used by the bindings system to create a model of the layers.



758
759
760
761
762
763
# 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

.non_caching_producer(producer) ⇒ Puppet::Pops::Binder::Bindings::ProducerDescriptor

Creates a non caching producer

Parameters:

  • producer (Puppet::Pops::Binder::Bindings::Producer)

    the producer to make non caching

Returns:



662
663
664
665
666
# 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

.parserPuppet::Pops::Parser::EvaluatingParser

Returns a parser for puppet expressions.

Returns:



777
778
779
# File 'lib/puppet/pops/binder/bindings_factory.rb', line 777

def self.parser
  @parser ||= Puppet::Pops::Parser::EvaluatingParser.new()
end

.producer_producer(producer) ⇒ Puppet::Pops::Binder::Bindings::ProducerDescriptor

Creates a producer producer

Parameters:

  • producer (Puppet::Pops::Binder::Bindings::Producer)

    a producer producing a Producer.

Returns:



673
674
675
676
677
# 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) ⇒ Puppet::Pops::Model::Expression

Parses and produces a puppet expression from the given string.

Parameters:

  • string (String)

    puppet source e.g. “1 + 2”

  • source_file (String)

    the source location, typically ‘__File__`

Returns:



787
788
789
# 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) ⇒ Puppet::Pops::Model::Expression

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.

Parameters:

  • string (String)

    puppet source e.g. “On node ${fqdn}”

  • source_file (String)

    the source location, typically ‘__File__`

Returns:



802
803
804
# 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) ⇒ 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.

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



627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
# 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