class Puppet::Pops::Loader::PuppetFunctionInstantiator
The PuppetFunctionInstantiator instantiates a Puppet::Functions::PuppetFunction given a Puppet Programming language source that when called evaluates the Puppet logic it contains.
Public Class Methods
Produces an instance of the Function class with the given typed_name, or fails with an error if the given puppet source does not produce this instance when evaluated.
@param loader [Loader] The loader the function is associated with @param typed_name [TypedName] the type / name of the function to load @param source_ref [URI, String] a reference to the source / origin of the puppet code to evaluate @param pp_code_string [String] puppet code in a string
@return [Functions::Function] - an instantiated function with global scope closure associated with the given loader
# File lib/puppet/pops/loader/puppet_function_instantiator.rb 18 def self.create(loader, typed_name, source_ref, pp_code_string) 19 parser = Parser::EvaluatingParser.new() 20 21 # parse and validate 22 result = parser.parse_string(pp_code_string, source_ref) 23 # Only one function is allowed (and no other definitions) 24 case result.definitions.size 25 when 0 26 raise ArgumentError, _("The code loaded from %{source_ref} does not define the function '%{func_name}' - it is empty.") % { source_ref: source_ref, func_name: typed_name.name } 27 when 1 28 # ok 29 else 30 raise ArgumentError, _("The code loaded from %{source_ref} must contain only the function '%{type_name}' - it has additional definitions.") % { source_ref: source_ref, type_name: typed_name.name } 31 end 32 the_function_definition = result.definitions[0] 33 34 unless the_function_definition.is_a?(Model::FunctionDefinition) 35 raise ArgumentError, _("The code loaded from %{source_ref} does not define the function '%{type_name}' - no function found.") % { source_ref: source_ref, type_name: typed_name.name } 36 end 37 unless the_function_definition.name == typed_name.name 38 expected = typed_name.name 39 actual = the_function_definition.name 40 raise ArgumentError, _("The code loaded from %{source_ref} produced function with the wrong name, expected %{expected}, actual %{actual}") % { source_ref: source_ref, expected: expected, actual: actual } 41 end 42 unless result.body == the_function_definition 43 raise ArgumentError, _("The code loaded from %{source} contains additional logic - can only contain the function %{name}") % { source: source_ref, name: typed_name.name } 44 end 45 46 # Adapt the function definition with loader - this is used from logic contained in it body to find the 47 # loader to use when making calls to the new function API. Such logic have a hard time finding the closure (where 48 # the loader is known - hence this mechanism 49 private_loader = loader.private_loader 50 Adapters::LoaderAdapter.adapt(the_function_definition).loader_name = private_loader.loader_name 51 52 # Cannot bind loaded functions to global scope, that must be done without binding that scope as 53 # loaders survive a compilation. 54 closure_scope = nil # Puppet.lookup(:global_scope) { {} } 55 56 created = create_function_class(the_function_definition) 57 # create the function instance - it needs closure (scope), and loader (i.e. where it should start searching for things 58 # when calling functions etc. 59 # It should be bound to global scope 60 61 created.new(closure_scope, private_loader) 62 end
Creates Function class and instantiates it based on a FunctionDefinition model @return [Array<TypedName, Functions.Function>] - array of
typed name, and an instantiated function with global scope closure associated with the given loader
# File lib/puppet/pops/loader/puppet_function_instantiator.rb 68 def self.create_from_model(function_definition, loader) 69 created = create_function_class(function_definition) 70 typed_name = TypedName.new(:function, function_definition.name) 71 [typed_name, created.new(nil, loader)] 72 end
# File lib/puppet/pops/loader/puppet_function_instantiator.rb 74 def self.create_function_class(function_definition) 75 # Create a 4x function wrapper around a named closure 76 Puppet::Functions.create_function(function_definition.name, Puppet::Functions::PuppetFunction) do 77 # TODO: should not create a new evaluator per function 78 init_dispatch(Evaluator::Closure::Named.new( 79 function_definition.name, 80 Evaluator::EvaluatorImpl.new(), function_definition)) 81 end 82 end