From 463d4e0a1f0067fca8176ff44acb9c8f503fb58b Mon Sep 17 00:00:00 2001 From: Ian Kronquist Date: Mon, 29 Jun 2015 13:37:30 -0700 Subject: [PATCH] (PDOC-37) Attach params to Puppet 4.x code object Traverse the ruby AST to get method arguments and attach them to the code object. * Fixes spurious warnings issued by yard. * Obviates the need for ugly regex code in the templates to retrieve parameters from the source code. --- lib/puppet/face/strings.rb | 1 + .../handlers/puppet_4x_function_handler.rb | 27 ++++++++++++++-- .../templates/default/definedtype/setup.rb | 3 +- .../yard/templates/default/hostclass/setup.rb | 4 +++ .../default/puppetnamespace/setup.rb | 2 +- .../yard/templates/default/template_helper.rb | 31 ++++++++++++++----- 6 files changed, 56 insertions(+), 12 deletions(-) diff --git a/lib/puppet/face/strings.rb b/lib/puppet/face/strings.rb index e0221a5..48d6300 100644 --- a/lib/puppet/face/strings.rb +++ b/lib/puppet/face/strings.rb @@ -50,6 +50,7 @@ Puppet::Face.define(:strings, '0.0.1') do # For now, assume the remaining positional args are a list of manifest # and ruby files to parse. yard_args = (args.empty? ? MODULE_SOURCEFILES : args) + class YARD::Logger; def progress(*args); end; end yardoc_actions.generate_documentation(*yard_args) end diff --git a/lib/puppet_x/puppetlabs/strings/yard/handlers/puppet_4x_function_handler.rb b/lib/puppet_x/puppetlabs/strings/yard/handlers/puppet_4x_function_handler.rb index 29b7b22..27d6ebf 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/handlers/puppet_4x_function_handler.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/handlers/puppet_4x_function_handler.rb @@ -26,7 +26,30 @@ class Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base process do name = process_parameters - obj = MethodObject.new(function_namespace, name) + method_arguments = [] + + # To attach the method parameters to the new code object, traverse the + # ruby AST until a node is found which defines a list of parameters. + # Then, traverse the children of the parameters, storing each identifier + # in the list of method arguments. + obj = MethodObject.new(function_namespace, name) do |o| + statement.traverse do |node| + if node.type == :params + node.traverse do |params| + if params.type == :ident + # FIXME: Replace nil with parameter types + method_arguments << [params[0], nil] + end + end + + # Now that the parameters have been found, break out of the traversal + break + end + end + end + + obj.parameters = method_arguments + obj['puppet_4x_function'] = true register obj @@ -78,7 +101,7 @@ class Puppet4xFunctionHandler < YARD::Handlers::Ruby::Base # # @return [(String, Hash{String => String})] def process_parameters - # Passing `false` to prameters excludes the block param from the returned + # Passing `false` to parameters excludes the block param from the returned # list. name, _ = statement.parameters(false).compact diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/definedtype/setup.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/definedtype/setup.rb index 31d54fd..b11f1fa 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/definedtype/setup.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/definedtype/setup.rb @@ -18,7 +18,8 @@ def parameter_details @param_details = [] - @param_details = @template_helper.extract_param_details(params, param_tags, object.files, true) + @param_details = @template_helper.extract_param_details(params, param_tags, true) + @template_helper.check_parameters_match_docs object erb(:parameter_details) end diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/hostclass/setup.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/hostclass/setup.rb index 081d237..f640d5b 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/hostclass/setup.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/hostclass/setup.rb @@ -3,6 +3,9 @@ include T('default/definedtype') def init super sections.push :subclasses + + @template_helper = TemplateHelper.new + @template_helper.check_parameters_match_docs object end def subclasses @@ -18,3 +21,4 @@ def subclasses return if @subclasses.nil? || @subclasses.empty? erb(:subclasses) end + diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/setup.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/setup.rb index 5238f64..054cee2 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/setup.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/puppetnamespace/setup.rb @@ -75,7 +75,7 @@ def method_details_list # Convert the matched string into an array of strings params = parameters.nil? ? nil : parameters[1].split(/\s*,\s*/) - param_details = @template_helper.extract_param_details(params, param_tags, object.files) unless params.nil? + param_details = @template_helper.extract_param_details(params, param_tags) unless params.nil? else param_details = @template_helper.comment_only_param_details(param_tags) end diff --git a/lib/puppet_x/puppetlabs/strings/yard/templates/default/template_helper.rb b/lib/puppet_x/puppetlabs/strings/yard/templates/default/template_helper.rb index 030fd8f..64b236c 100644 --- a/lib/puppet_x/puppetlabs/strings/yard/templates/default/template_helper.rb +++ b/lib/puppet_x/puppetlabs/strings/yard/templates/default/template_helper.rb @@ -36,7 +36,7 @@ class TemplateHelper # :desc => [String] The description provided in the comment # :types => [Array] The parameter type(s) specified in the comment # :exists => [Boolean] True only if the parameter exists in the documented logic and not just in a comment} - def extract_param_details(parameters, tags_hash, locations, fq_name = false) + def extract_param_details(parameters, tags_hash, fq_name = false) parameter_info = [] # Extract the information for parameters that exist @@ -73,13 +73,6 @@ class TemplateHelper end if !param_exists parameter_info.push({:name => tag.name, :desc => tag.text, :types => tag.types, :exists? => false}) - if locations.length >= 1 and locations[0].length == 2 - file_name = locations[0][0] - line_number = locations[0][1] - $stderr.puts "[warn]: The parameter #{tag.name} is documented, but doesn't exist in your code, in file #{file_name} near line #{line_number}" - else - $stderr.puts "[warn]: The parameter #{tag.name} is documented, but doesn't exist in your code. Sorry, the file and line number could not be determined." - end end end @@ -111,4 +104,26 @@ class TemplateHelper parameter_info end + + # Check that the actual function parameters match what is stated in the docs. + # If there is a mismatch, print a warning to stderr. + # This is necessary for puppet classes and defined types. This type of + # warning will be issued for ruby code by the ruby docstring parser. + # @param object the code object to examine for parameters names + def check_parameters_match_docs(object) + param_tags = object.tags.find_all{ |tag| tag.tag_name == "param"} + names = object.parameters.map {|l| l.first.gsub(/\W/, '') } + locations = object.files + param_tags.each do |tag| + if not names.include?(tag.name) + if locations.length >= 1 and locations[0].length == 2 + file_name = locations[0][0] + line_number = locations[0][1] + $stderr.puts "[warn]: The parameter #{tag.name} is documented, but doesn't exist in your code, in file #{file_name} near line #{line_number}" + else + $stderr.puts "[warn]: The parameter #{tag.name} is documented, but doesn't exist in your code. Sorry, the file and line number could not be determined." + end + end + end + end end