Method: Puppet::Functions.create_loaded_function

Defined in:
lib/puppet/functions.rb

.create_loaded_function(func_name, loader, function_base = Function, &block) ⇒ Class<Function>

Creates a function in, or in a local loader under the given loader. This method should only be used when manually creating functions for the sake of testing. Functions that are autoloaded should always use the ‘create_function` method and the autoloader will supply the correct loader.

Parameters:

  • func_name (String, Symbol)

    a simple or qualified function name

  • loader (Puppet::Pops::Loaders::Loader)

    the loader loading the function

  • block (Proc)

    the block that defines the methods and dispatch of the Function to create

Returns:

  • (Class<Function>)

    the newly created Function class



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/puppet/functions.rb', line 211

def self.create_loaded_function(func_name, loader, function_base = Function, &block)
  if function_base.ancestors.none? { |s| s == Puppet::Pops::Functions::Function }
    raise ArgumentError, _("Functions must be based on Puppet::Pops::Functions::Function. Got %{function_base}") % { function_base: function_base }
  end

  func_name = func_name.to_s
  # Creates an anonymous class to represent the function
  # The idea being that it is garbage collected when there are no more
  # references to it.
  #
  # (Do not give the class the block here, as instance variables should be set first)
  the_class = Class.new(function_base)

  unless loader.nil?
    the_class.instance_variable_set(:'@loader', loader.private_loader)
  end

  # Make the anonymous class appear to have the class-name <func_name>
  # Even if this class is not bound to such a symbol in a global ruby scope and
  # must be resolved via the loader.
  # This also overrides any attempt to define a name method in the given block
  # (Since it redefines it)
  #
  # TODO, enforce name in lower case (to further make it stand out since Ruby
  # class names are upper case)
  #
  the_class.instance_eval do
    @func_name = func_name

    def name
      @func_name
    end

    def loader
      @loader
    end
  end

  # The given block can now be evaluated and have access to name and loader
  #
  the_class.class_eval(&block)

  # Automatically create an object dispatcher based on introspection if the
  # loaded user code did not define any dispatchers. Fail if function name
  # does not match a given method name in user code.
  #
  if the_class.dispatcher.empty?
    simple_name = func_name.split(/::/)[-1]
    type, names = default_dispatcher(the_class, simple_name)
    last_captures_rest = (type.size_range[1] == Float::INFINITY)
    the_class.dispatcher.add(Puppet::Pops::Functions::Dispatch.new(type, simple_name, names, last_captures_rest))
  end

  # The function class is returned as the result of the create function method
  the_class
end