# frozen_string_literal: true module Puppet module Pal # A PlanSignature is returned from `plan_signature`. Its purpose is to answer questions about the plans's parameters # and if it can be called with a hash of named parameters. # # @api public # class PlanSignature def initialize(plan_function) @plan_func = plan_function end # Returns true or false depending on if the given PlanSignature is callable with a set of named arguments or not # In addition to returning the boolean outcome, if a block is given, it is called with a string of formatted # error messages that describes the difference between what was given and what is expected. The error message may # have multiple lines of text, and each line is indented one space. # # @example Checking if signature is acceptable # # signature = pal.plan_signature('myplan') # signature.callable_with?({x => 10}) { |errors| raise ArgumentError("Ooops: given arguments does not match\n#{errors}") } # # @api public # def callable_with?(args_hash) dispatcher = @plan_func.class.dispatcher.dispatchers[0] param_scope = {} # Assign all non-nil values, even those that represent non-existent parameters. args_hash.each { |k, v| param_scope[k] = v unless v.nil? } dispatcher.parameters.each do |p| name = p.name arg = args_hash[name] if arg.nil? # Arg either wasn't given, or it was undef if p.value.nil? # No default. Assign nil if the args_hash included it param_scope[name] = nil if args_hash.include?(name) else # parameter does not have a default value, it will be assigned its default when being called # we assume that the default value is of the correct type and therefore simply skip # checking this # param_scope[name] = param_scope.evaluate(name, p.value, closure_scope, @evaluator) end end end errors = Puppet::Pops::Types::TypeMismatchDescriber.singleton.describe_struct_signature(dispatcher.params_struct, param_scope).flatten return true if errors.empty? if block_given? yield errors.map(&:format).join("\n") end false end # Returns a PStructType describing the parameters as a puppet Struct data type # Note that a `to_s` on the returned structure will result in a human readable Struct datatype as a # description of what a plan expects. # # @return [Puppet::Pops::Types::PStructType] a struct data type describing the parameters and their types # # @api public # def params_type dispatcher = @plan_func.class.dispatcher.dispatchers[0] dispatcher.params_struct end end end end