diff --git a/lib/puppet/pops/binder/bindings_composer.rb b/lib/puppet/pops/binder/bindings_composer.rb index 86be89ef0..db51fbba2 100644 --- a/lib/puppet/pops/binder/bindings_composer.rb +++ b/lib/puppet/pops/binder/bindings_composer.rb @@ -1,175 +1,175 @@ # The BindingsComposer handles composition of multiple bindings sources # It is directed by a {Puppet::Pops::Binder::Config::BinderConfig BinderConfig} that indicates how # the final composition should be layered, and what should be included/excluded in each layer # # The bindings composer is intended to be used once per environment as the compiler starts its work. # # TODO: Possibly support envdir: scheme / relative to environment root (== same as confdir if there is only one environment). # This is probably easier to do after ENC changes described in ARM-8 have been implemented. # TODO: If same config is loaded in a higher layer, skip it in the lower (since it is meaningless to load it again with lower # precedence. (Optimization, or possibly an error, should produce a warning). # class Puppet::Pops::Binder::BindingsComposer # The BindingsConfig instance holding the read and parsed, but not evaluated configuration # @api public # attr_reader :config # map of scheme name to handler # @api private attr_reader :scheme_handlers - # @return Hash map of module name to module instance + # @return [Hash{String => Puppet::Module}] map of module name to module instance # @api private attr_reader :name_to_module # @api private attr_reader :confdir # @api private attr_reader :diagnostics # Container of all warnings and errors produced while initializing and loading bindings # # @api public attr_reader :acceptor # @api public def initialize() @acceptor = Puppet::Pops::Validation::Acceptor.new() @diagnostics = Puppet::Pops::Binder::Config::DiagnosticProducer.new(acceptor) @config = Puppet::Pops::Binder::Config::BinderConfig.new(@diagnostics) if acceptor.errors? Puppet::Pops::IssueReporter.assert_and_report(acceptor, :message => 'Binding Composer: error while reading config.') raise Puppet::DevError.new("Internal Error: IssueReporter did not raise exception for errors in bindings config.") end end # Configures and creates the boot injector. # The read config may optionally contain mapping of bindings scheme handler name to handler class, and # mapping of biera2 backend symbolic name to backend class. # If present, these are turned into bindings in the category 'extension' (which is only used in the boot injector) which # has higher precedence than 'default'. This is done to allow users to override the default bindings for # schemes and backends. # @param scope [Puppet::Parser:Scope] the scope (used to find compiler and injector for the environment) # @api private # def configure_and_create_injector(scope) # create the injector (which will pick up the bindings registered above) @scheme_handlers = SchemeHandlerHelper.new(scope) # get extensions from the config # ------------------------------ scheme_extensions = @config.scheme_extensions # Define a named bindings that are known by the SystemBindings boot_bindings = Puppet::Pops::Binder::BindingsFactory.named_bindings(Puppet::Pops::Binder::SystemBindings::ENVIRONMENT_BOOT_BINDINGS_NAME) do scheme_extensions.each_pair do |scheme, class_name| # turn each scheme => class_name into a binding (contribute to the buildings-schemes multibind). # do this in category 'extensions' to allow them to override the 'default' bind do name(scheme) instance_of(::Puppetx::BINDINGS_SCHEMES_TYPE) in_multibind(::Puppetx::BINDINGS_SCHEMES) to_instance(class_name) end end end @injector = scope.compiler.create_boot_injector(boot_bindings.model) end # @return [Puppet::Pops::Binder::Bindings::LayeredBindings] def compose(scope) # The boot injector is used to lookup scheme-handlers configure_and_create_injector(scope) # get all existing modules and their root path @name_to_module = {} scope.environment.modules.each {|mod| name_to_module[mod.name] = mod } # setup the confdir @confdir = Puppet.settings[:confdir] factory = Puppet::Pops::Binder::BindingsFactory contributions = [] configured_layers = @config.layering_config.collect do | layer_config | # get contributions contribs = configure_layer(layer_config, scope, diagnostics) # collect the contributions separately for later checking of category precedence contributions.concat(contribs) # create a named layer with all the bindings for this layer factory.named_layer(layer_config['name'], *contribs.collect {|c| c.bindings }.flatten) end # Add the two system layers; the final - highest ("can not be overridden" layer), and the lowest # Everything here can be overridden 'default' layer. # configured_layers.insert(0, Puppet::Pops::Binder::SystemBindings.final_contribution) configured_layers.insert(-1, Puppet::Pops::Binder::SystemBindings.default_contribution) # and finally... create the resulting structure factory.layered_bindings(*configured_layers) end private def configure_layer(layer_description, scope, diagnostics) name = layer_description['name'] # compute effective set of uris to load (and get rid of any duplicates in the process included_uris = array_of_uris(layer_description['include']) excluded_uris = array_of_uris(layer_description['exclude']) effective_uris = Set.new(expand_included_uris(included_uris)).subtract(Set.new(expand_excluded_uris(excluded_uris))) # Each URI should result in a ContributedBindings effective_uris.collect { |uri| scheme_handlers[uri.scheme].contributed_bindings(uri, scope, self) } end def array_of_uris(descriptions) return [] unless descriptions descriptions = [descriptions] unless descriptions.is_a?(Array) descriptions.collect {|d| URI.parse(d) } end def expand_included_uris(uris) result = [] uris.each do |uri| unless handler = scheme_handlers[uri.scheme] raise ArgumentError, "Unknown bindings provider scheme: '#{uri.scheme}'" end result.concat(handler.expand_included(uri, self)) end result end def expand_excluded_uris(uris) result = [] uris.each do |uri| unless handler = scheme_handlers[uri.scheme] raise ArgumentError, "Unknown bindings provider scheme: '#{uri.scheme}'" end result.concat(handler.expand_excluded(uri, self)) end result end class SchemeHandlerHelper T = Puppet::Pops::Types::TypeFactory HASH_OF_HANDLER = T.hash_of(T.type_of('Puppetx::Puppet::BindingsSchemeHandler')) def initialize(scope) @scope = scope @cache = nil end def [] (scheme) load_schemes unless @cache @cache[scheme] end def load_schemes @cache = @scope.compiler.boot_injector.lookup(@scope, HASH_OF_HANDLER, Puppetx::BINDINGS_SCHEMES) || {} end end end diff --git a/lib/puppet/pops/evaluator/callable_signature.rb b/lib/puppet/pops/evaluator/callable_signature.rb index 8d5d045c7..e953a4409 100644 --- a/lib/puppet/pops/evaluator/callable_signature.rb +++ b/lib/puppet/pops/evaluator/callable_signature.rb @@ -1,101 +1,101 @@ # CallableSignature # === # A CallableSignature describes how something callable expects to be called. # Different implementation of this class are used for different types of callables. # # @api public # class Puppet::Pops::Evaluator::CallableSignature # Returns the names of the parameters as an array of strings. This does not include the name # of an optional block parameter. # # All implementations are not required to supply names for parameters. They may be used if present, # to provide user feedback in errors etc. but they are not authoritative about the number of # required arguments, optional arguments, etc. # # A derived class must implement this method. # - # @return Array - an array of names (that may be empty if names are unavailable) + # @return [Array] - an array of names (that may be empty if names are unavailable) # # @api public # def parameter_names raise NotImplementedError.new end # Returns a PCallableType with the type information, required and optional count, and type information about # an optional block. # # A derived class must implement this method. # # @return [Puppet::Pops::Types::PCallableType] # @api public # def type raise NotImplementedError.new end # Returns the expected type for an optional block. The type may be nil, which means that the callable does # not accept a block. If a type is returned it is one of Callable, Optional[Callable], Variant[Callable,...], # or Optional[Variant[Callable, ...]]. The Variant type is used when multiple signatures are acceptable. # The Optional type is used when the block is optional. # # @return [Puppet::Pops::Types::PAbstractType, nil] the expected type of a block given as the last parameter in a call. # # @api public # def block_type type.block_type end # Returns the name of the block parameter if the callable accepts a block. # @return [String] the name of the block parameter # A derived class must implement this method. # @api public # def block_name raise NotImplementedError.new end # Returns a range indicating the optionality of a block. One of [0,0] (does not accept block), [0,1] (optional # block), and [1,1] (block required) # - # @return Array[Integer, Integer] the range of the block parameter + # @return [Array(Integer, Integer)] the range of the block parameter # def block_range type.block_range end # Returns the range of required/optional argument values as an array of [min, max], where an infinite # end is given as INFINITY. To test against infinity, use the infinity? method. # - # @return Array[Integer, Numeric] - an Array with [min, max] + # @return [Array[Integer, Numeric]] - an Array with [min, max] # # @api public # def args_range type.size_range end # Returns true if the last parameter captures the rest of the arguments, with a possible cap, as indicated # by the `args_range` method. # A derived class must implement this method. # # @return [Boolean] true if last parameter captures the rest of the given arguments (up to a possible cap) # @api public # def last_captures_rest? raise NotImplementedError.new end # Returns true if the given x is infinity # @return [Boolean] true, if given value represents infinity # # @api public # def infinity?(x) x == Puppet::Pops::Types::INFINITY end -end \ No newline at end of file +end