From cf2d24bd2fa585406dea37e20262f9aec3a72dea Mon Sep 17 00:00:00 2001 From: Sean Millichamp Date: Tue, 25 Jul 2023 10:37:18 -0400 Subject: [PATCH] Add stdlib::has_function Add a new function to test for function availability in the Puppet runtime, replacing the deprecated and removed is_function_available with support for legacy and modern functions. --- lib/puppet/functions/stdlib/has_function.rb | 33 +++++++++++++++++++ spec/functions/has_function_spec.rb | 36 +++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 lib/puppet/functions/stdlib/has_function.rb create mode 100644 spec/functions/has_function_spec.rb diff --git a/lib/puppet/functions/stdlib/has_function.rb b/lib/puppet/functions/stdlib/has_function.rb new file mode 100644 index 000000000..c30a6a203 --- /dev/null +++ b/lib/puppet/functions/stdlib/has_function.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +# @summary +# Returns whether the Puppet runtime has access to a given function. +# +# @example Using stdlib::has_function() +# stdlib::has_function('stdlib::has_function') # true +# stdlib::has_function('not_a_function') # false +# +# Determines whether the Puppet runtime has access to a function by the +# name provided. +# +# @return +# Returns true if the provided function name is available, false otherwise. +# +Puppet::Functions.create_function(:'stdlib::has_function', Puppet::Functions::InternalFunction) do + dispatch :has_function do + scope_param + param 'String[1]', :function_name + return_type 'Boolean' + end + + def has_function(scope, function_name) # rubocop:disable Naming/PredicateName + loaders = scope.compiler.loaders + loader = loaders.private_environment_loader + return true unless loader&.load(:function, function_name).nil? + + # If the loader cannot find the function it might be + # a 3x-style function stubbed in on-the-fly for testing. + func_3x = Puppet::Parser::Functions.function(function_name.to_sym) + func_3x.is_a?(String) && !func_3x.empty? + end +end diff --git a/spec/functions/has_function_spec.rb b/spec/functions/has_function_spec.rb new file mode 100644 index 000000000..dd66ebde2 --- /dev/null +++ b/spec/functions/has_function_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'stdlib::has_function' do + let(:pre_condition) { 'function puppet_func {}' } + + before(:each) do + Puppet::Parser::Functions.newfunction(:test_3x_func) do |_args| + true + end + end + + it { is_expected.not_to be_nil } + + # Itself, a namespaced function: + it { is_expected.to run.with_params('stdlib::has_function').and_return(true) } + + # A namespaced function which does not exist: + it { is_expected.to run.with_params('stdlib::not_a_function').and_return(false) } + + # A top-function which does not exist: + it { is_expected.to run.with_params('not_a_function').and_return(false) } + + # A Puppet core function: + it { is_expected.to run.with_params('assert_type').and_return(true) } + + # A Puppet function stubbed during testing: + it { is_expected.to run.with_params('puppet_func').and_return(true) } + + # A file-loaded 3x style function in stdlib: + it { is_expected.to run.with_params('validate_augeas').and_return(true) } + + # A stubbed 3x-style function: + it { is_expected.to run.with_params('test_3x_func').and_return(true) } +end