(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.
This commit is contained in:
Ian Kronquist 2015-06-29 13:37:30 -07:00
parent 49171c92b9
commit 463d4e0a1f
6 changed files with 56 additions and 12 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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