Puppet includes two Ruby APIs for writing custom functions. This page is about the modern API, which uses the Puppet::Functions namespace.

Basic syntax

# /etc/puppetlabs/code/environments/production/modules/mymodule/lib/puppet/functions/mymodule/upcase.rb
Puppet::Functions.create_function(:'mymodule::upcase') do
  dispatch :up do
    param 'String', :some_string
  end

  def up(some_string)
    some_string.upcase
  end
end

To write a new function in Ruby, use the Puppet::Functions.create_function method. You don’t need to require any Puppet libraries to make it available; Puppet handles that automatically when it loads the function file.

The create_function method requires:

In summary, with the pieces labled:

Puppet::Functions.create_function(:<FUNCTION NAME>) do
  dispatch :<METHOD NAME> do
    param '<DATA TYPE>', :<ARGUMENT NAME (displayed in docs/errors)>
    ...
  end

  def <METHOD NAME>(<ARGUMENT NAME (for local use)>, ...)
    <IMPLEMENTATION>
  end
end

Location

A Ruby function must be placed in its own file, in the lib/puppet/functions directory of either a module or an environment.

The filename must match the name of the function, and have the .rb extension. For namespaced functions, each segment prior to the final one must be a subdirectory of functions, and the final segment must be the filename.

Examples:

Function name File location
upcase <MODULES DIR>/mymodule/lib/puppet/functions/upcase.rb
upcase /etc/puppetlabs/code/environments/production/lib/puppet/functions/upcase.rb
mymodule::upcase <MODULES DIR>/mymodule/lib/puppet/functions/mymodule/upcase.rb
environment::upcase /etc/puppetlabs/code/environments/production/lib/puppet/functions/environment/upcase.rb

Function names

Function names generally resemble these examples:

Function names are almost the same as class names. They consist of one or more segments; each segment must start with a lowercase letter, and can include:

If a name has multiple segments, they are separated by the double-colon (::) namespace separator.

In other words, each segment should match the following regular expression:

\A[a-z][a-z0-9_]*\Z

…and the full name should match the following regular expression:

\A([a-z][a-z0-9_]*)(::[a-z][a-z0-9_]*)*\Z

Function names can be either global or namespaced.

Some illegal function names:

Pass names to create_function as symbols

When you call the Puppet::Functions.create_function method, you should pass the function’s name to it as a Ruby symbol. (Although it can accept a string, we recommend always using a symbol.)

To turn a function name into a symbol:

Behavior of Ruby functions

Ruby functions can have multiple signatures. When a function is called, Puppet checks each signature in order, comparing the allowed arguments to the arguments that were actually passed. Arguments are checked using Puppet’s data type system, the same way class parameters are checked.

As soon as Puppet finds a signature that can accept the provided arguments, it calls the associated implementation method, passing the arguments to that method. When the method finishes running and returns a value, Puppet uses that as the function’s return value.

If none of the function’s signatures match the provided arguments, Puppet fails compilation and logs an error message describing the mismatch between the provided and expected arguments.

Conversion of Puppet and Ruby data types

When function arguments are passed to a Ruby method, they’re converted to Ruby objects. Similarly, the method’s return value is converted to a Puppet data type when the Puppet manifest regains control.

Puppet converts data types between the Puppet language and Ruby as follows:

Puppet type Ruby class
Boolean Boolean
Undef NilClass (value nil)
String String
Number subtype of Numeric
Array Array
Hash Hash
Default Symbol (value :default)
Regexp Regexp
Resource reference Puppet::Pops::Types::PResourceType, or Puppet::Pops::Types::PHostClassType
Lambda (code block) Puppet::Pops::Evaluator::Closure
Data type (Type) A type class under Puppet::Pops::Types, e.g. Puppet::Pops::Types::PIntegerType

Next pages

To make this API reference easier to use, we’ve split some of its larger topics into separate pages. Please read the following pages to learn the remainder of the Ruby functions API: