Refactoring legacy 3.x functions
If you have Ruby functions written with the legacy 3.x API, refactor them to ensure that they work correctly with current versions of Puppet.
Refactoring legacy functions improves functionality and prevents errors. At minimum, refactor any extra methods in your 3.x functions, because these no longer work in Puppet.
Extra methods
Legacy functions that contain methods defined inside the function body or outside of the function return an error, such as:
raise SecurityError, _("Illegal method definition of method '%{method_name}' on line %{line}' in legacy function") % { method_name: mname, line: mline }
To fix these errors, refactor your 3.x functions to the 4.x function API, where defining multiple methods is permitted.
For example, the legacy function below has been refactored into the modern API, with the following changes:
-
Documentation for the function is now a comment before the call to
create_function
.
-
The default dispatcher dispatches all given arguments to a method with the same name as the function.
-
The
extra_method
has not been moved, but is legal in the modern API. -
Not visible in the code sample, the function has been moved from
lib/puppet/parser/functions
tolib/puppet/functions
.
3.x API function:
module Puppet::Parser::Functions
newfunction(:sample, :type => :rvalue, :doc => <<-EOS
The function's documentation
EOS
) do |arguments|
"the returned value"
end
def extra_method()
end
end
4.x API function:
# The function's documentation
Puppet::Functions.create_function(:sample) do
def sample(*arguments)
"the returned value"
end
def extra_method()
end
end
Function call forms
Change all function calls from the form function_***
to use
the method call_function(name, args)
.
The function_***
form applies only to functions implemented
in the 3.x API, so function with calls in that form can not call any function that has moved
to the 4.x API.
function_sprintf("%s", "example")
call_function('sprintf', "%s", "example")
:rvalue
specification
The 3.x API differentiated between functions returning a value (:type => :rvalue
) and functions that did not return a value (:type => :statement
). In the 4.x API, there is no such
distinction. If you are refactoring a function where :rvalue =>
true
, you do not need to make any changes. If you are refactoring a function
where :rvalue => false
, make sure the function returns
nil
.
Data values
The 4.x function API allows certain data values, such as Regexp
, Timespan
, and Timestamp
. However, the 3.x API transformed these and similar data values into
strings.
Review the logic in your refactored function with this in mind: instead of checking for
empty strings, the function checks for nil
. The function
uses neither empty strings nor the :undef
symbol in returned
values to denote undef
; again, use nil
instead.
For String
, Integer
,
Float
, Array
, Hash
, and Boolean
values, you do
not need to make changes to your 3.x functions.
Documentation
The 4.x API supports Markdown and Puppet Strings documentation tags to document functions, including individual parameters and returned values. See the Strings documentation page for details about the correct format and style for documentation comments.
Namespacing
Namespace your function to the module in which it is defined, and update manifests that use it.
The function name is in the format module_name::function_name
. For example, if the module name is mymodule
:
# The function's documentation
Puppet::Functions.create_function(:'mymodule::sample') do
def sample(*arguments)
"the returned value"
end
def extra_method()
end
end
The default dispatch uses the last part of the name when dispatching to a method in the
function, so you only have to change the module namespace in the function's full name. You
must also move the file containing the function to the correct location for 4.x API
functions, mymodule/lib/puppet/functions
.