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