class Puppet::Functions::Function3x

Constants

PARAM_NAMES

Table of optimized parameter names - 0 to 5 parameters

Public Class Methods

create_function(func_name, func_info, loader) click to toggle source

Creates an anonymous Function3x class that wraps a 3x function

@api private

    # File lib/puppet/functions.rb
698 def self.create_function(func_name, func_info, loader)
699   func_name = func_name.to_s
700 
701   # Creates an anonymous class to represent the function
702   # The idea being that it is garbage collected when there are no more
703   # references to it.
704   #
705   # (Do not give the class the block here, as instance variables should be set first)
706   the_class = Class.new(Function3x)
707 
708   unless loader.nil?
709     the_class.instance_variable_set(:'@loader', loader.private_loader)
710   end
711 
712   the_class.instance_variable_set(:'@func_name', func_name)
713   the_class.instance_variable_set(:'@method3x', :"function_#{func_name}")
714 
715   # Make the anonymous class appear to have the class-name <func_name>
716   # Even if this class is not bound to such a symbol in a global ruby scope and
717   # must be resolved via the loader.
718   # This also overrides any attempt to define a name method in the given block
719   # (Since it redefines it)
720   #
721   the_class.instance_eval do
722     def name
723       @func_name
724     end
725 
726     def loader
727       @loader
728     end
729 
730     def method3x
731       @method3x
732     end
733   end
734 
735   # Add the method that is called - it simply delegates to
736   # the 3.x function by calling it via the calling scope using the @method3x symbol
737   # :"function_#{name}".
738   #
739   # When function is not an rvalue function, make sure it produces nil
740   #
741   the_class.class_eval do
742 
743     # Bypasses making the  call via the dispatcher to make sure errors
744     # are reported exactly the same way as in 3x. The dispatcher is still needed as it is
745     # used to support other features than calling.
746     #
747     def call(scope, *args, &block)
748       begin
749         result = catch(:return) do
750           mapped_args = Puppet::Pops::Evaluator::Runtime3FunctionArgumentConverter.map_args(args, scope, '')
751           # this is the scope.function_xxx(...) call
752           return scope.send(self.class.method3x, mapped_args)
753         end
754         return result.value
755       rescue Puppet::Pops::Evaluator::Next => jumper
756         begin
757           throw :next, jumper.value
758         rescue Puppet::Parser::Scope::UNCAUGHT_THROW_EXCEPTION
759           raise Puppet::ParseError.new("next() from context where this is illegal", jumper.file, jumper.line)
760         end
761       rescue Puppet::Pops::Evaluator::Return => jumper
762         begin
763           throw :return, jumper
764         rescue Puppet::Parser::Scope::UNCAUGHT_THROW_EXCEPTION
765           raise Puppet::ParseError.new("return() from context where this is illegal", jumper.file, jumper.line)
766         end
767       end
768     end
769   end
770 
771   # Create a dispatcher based on func_info
772   type, names = Puppet::Functions.any_signature(*from_to_names(func_info))
773   last_captures_rest = (type.size_range[1] == Float::INFINITY)
774 
775   # The method '3x_function' here is a dummy as the dispatcher is not used for calling, only for information.
776   the_class.dispatcher.add(Puppet::Pops::Functions::Dispatch.new(type, '3x_function', names, last_captures_rest))
777   # The function class is returned as the result of the create function method
778   the_class
779 end
from_to_names(func_info) click to toggle source

Compute min and max number of arguments and a list of constructed parameter names p0 - pn (since there are no parameter names in 3x functions).

@api private

    # File lib/puppet/functions.rb
785 def self.from_to_names(func_info)
786   arity = func_info[:arity]
787   if arity.nil?
788     arity = -1
789   end
790   if arity < 0
791     from = -arity - 1 # arity -1 is 0 min param, -2 is min 1 param
792     to = :default     # infinite range
793     count = -arity    # the number of named parameters
794   else
795     count = from = to = arity
796   end
797   # Names of parameters, up to 5 are optimized and use frozen version
798   # Note that (0..count-1) produces expected empty array for count == 0, 0-n for count >= 1
799   names = count <= 5 ? PARAM_NAMES[count] : (0..count-1).map {|n| "p#{n}" }
800   [from, to, names]
801 end

Public Instance Methods

call(scope, *args, &block) click to toggle source

Bypasses making the call via the dispatcher to make sure errors are reported exactly the same way as in 3x. The dispatcher is still needed as it is used to support other features than calling.

    # File lib/puppet/functions.rb
747 def call(scope, *args, &block)
748   begin
749     result = catch(:return) do
750       mapped_args = Puppet::Pops::Evaluator::Runtime3FunctionArgumentConverter.map_args(args, scope, '')
751       # this is the scope.function_xxx(...) call
752       return scope.send(self.class.method3x, mapped_args)
753     end
754     return result.value
755   rescue Puppet::Pops::Evaluator::Next => jumper
756     begin
757       throw :next, jumper.value
758     rescue Puppet::Parser::Scope::UNCAUGHT_THROW_EXCEPTION
759       raise Puppet::ParseError.new("next() from context where this is illegal", jumper.file, jumper.line)
760     end
761   rescue Puppet::Pops::Evaluator::Return => jumper
762     begin
763       throw :return, jumper
764     rescue Puppet::Parser::Scope::UNCAUGHT_THROW_EXCEPTION
765       raise Puppet::ParseError.new("return() from context where this is illegal", jumper.file, jumper.line)
766     end
767   end
768 end
loader() click to toggle source
    # File lib/puppet/functions.rb
726 def loader
727   @loader
728 end
method3x() click to toggle source
    # File lib/puppet/functions.rb
730 def method3x
731   @method3x
732 end
name() click to toggle source
    # File lib/puppet/functions.rb
722 def name
723   @func_name
724 end