class Puppet::Pops::Functions::Function
@note WARNING: This new function API is still under development and may change at
any time
A function in the puppet evaluator.
Functions are normally defined by another system, which produces subclasses of this class as well as constructing delegations to call the appropriate methods.
This class should rarely be used directly. Instead functions should be constructed using {Puppet::Functions.create_function}.
@api public
Attributes
The scope where the function was defined
The loader that loaded this function. Should be used if function wants to load other things.
Public Class Methods
The dispatcher for the function
@api private
# File lib/puppet/pops/functions/function.rb 85 def self.dispatcher 86 @dispatcher ||= Puppet::Pops::Functions::Dispatcher.new 87 end
# File lib/puppet/pops/functions/function.rb 22 def initialize(closure_scope, loader) 23 @closure_scope = closure_scope 24 @loader = loader 25 end
Produces information about parameters in a way that is compatible with Closure
@api private
# File lib/puppet/pops/functions/function.rb 92 def self.signatures 93 @dispatcher.signatures 94 end
Public Instance Methods
Invokes the function via the dispatching logic that performs type check and weaving. A specialized function may override this method to do its own dispatching and checking of the raw arguments. A specialized implementation can rearrange arguments, add or remove arguments and then delegate to the dispatching logic by calling:
@example Delegating to the dispatcher
def call(scope, *args) manipulated_args = args + ['easter_egg'] self.class.dispatcher.dispatch(self, scope, manipulated_args) end
System functions that must have access to the calling scope can use this technique. Functions in general should not need the calling scope. (The closure scope; what is visible where the function is defined) is available via the method `closure_scope`).
@api public
# File lib/puppet/pops/functions/function.rb 43 def call(scope, *args, &block) 44 begin 45 result = catch(:return) do 46 return self.class.dispatcher.dispatch(self, scope, args, &block) 47 end 48 return result.value 49 rescue Puppet::Pops::Evaluator::Next => jumper 50 begin 51 throw :next, jumper.value 52 rescue Puppet::Parser::Scope::UNCAUGHT_THROW_EXCEPTION 53 raise Puppet::ParseError.new("next() from context where this is illegal", jumper.file, jumper.line) 54 end 55 rescue Puppet::Pops::Evaluator::Return => jumper 56 begin 57 throw :return, jumper 58 rescue Puppet::Parser::Scope::UNCAUGHT_THROW_EXCEPTION 59 raise Puppet::ParseError.new("return() from context where this is illegal", jumper.file, jumper.line) 60 end 61 end 62 end
Allows the implementation of a function to call other functions by name. The callable functions are those visible to the same loader that loaded this function (the calling function). The referenced function is called with the calling functions closure scope as the caller's scope.
@param function_name [String] The name of the function @param *args [Object] splat of arguments @return [Object] The result returned by the called function
@api public
# File lib/puppet/pops/functions/function.rb 73 def call_function(function_name, *args, &block) 74 internal_call_function(closure_scope, function_name, args, &block) 75 end
Protected Instance Methods
Allows the implementation of a function to call other functions by name and pass the caller scope. The callable functions are those visible to the same loader that loaded this function (the calling function).
@param scope [Puppet::Parser::Scope] The caller scope @param function_name [String] The name of the function @param args [Array] array of arguments @return [Object] The result returned by the called function
@api public
# File lib/puppet/pops/functions/function.rb 108 def internal_call_function(scope, function_name, args, &block) 109 110 the_loader = loader 111 unless the_loader 112 raise ArgumentError, _("Function %{class_name}(): cannot call function '%{function_name}' - no loader specified") % 113 { class_name: self.class.name, function_name: function_name } 114 end 115 116 func = the_loader.load(:function, function_name) 117 if func 118 Puppet::Util::Profiler.profile(function_name, [:functions, function_name]) do 119 return func.call(scope, *args, &block) 120 end 121 end 122 123 # Check if a 3x function is present. Raise a generic error if it's not to allow upper layers to fill in the details 124 # about where in a puppet manifest this error originates. (Such information is not available here). 125 loader_scope = closure_scope 126 func_3x = Puppet::Parser::Functions.function(function_name, loader_scope.environment) if loader_scope.is_a?(Puppet::Parser::Scope) 127 unless func_3x 128 raise ArgumentError, _("Function %{class_name}(): Unknown function: '%{function_name}'") % 129 { class_name: self.class.name, function_name: function_name } 130 end 131 132 # Call via 3x API 133 # Arguments must be mapped since functions are unaware of the new and magical creatures in 4x. 134 # NOTE: Passing an empty string last converts nil/:undef to empty string 135 result = scope.send(func_3x, Puppet::Pops::Evaluator::Runtime3FunctionArgumentConverter.map_args(args, loader_scope, ''), &block) 136 137 # Prevent non r-value functions from leaking their result (they are not written to care about this) 138 Puppet::Parser::Functions.rvalue?(function_name) ? result : nil 139 end