class RuboCop::Cop::Style::PublicMethodDocumentation
TODO: Write cop description and example of bad / good code. For every `SupportedStyle` and unique configuration, there needs to be examples. Examples must have valid Ruby syntax. Do not use upticks.
@example EnforcedStyle: PublicMethodDocumentation
(default)
# Description of the `PublicMethodDocumentation` style. # bad def xxx # bad # xxx documentation def xxx # bad # xxx documentation # the end def xxx # good # class xxx documentation # def xxx # bad # class xxx documentation # def xxx(p1)
Constants
- ATTRS_DOC
- ATTR_REGEXP
- DOC_PARM_REGEXP
- DOC_RET_REGEXP
- DOC_SUB_PARM_REGEXP
- MSG_ATTRIBUTES_AND_PARAMETERS_NO_COEXIST
- MSG_DESCRIPTION_SHOULD_END_WITH_BLANK_COMMENT
- MSG_ILLEGAL_RANGE_BODY_FORMAT
- MSG_ILLEGAL_RANGE_RET_BODY_FORMAT
- MSG_INVALID_DOCUMENTATION
- MSG_MISSING_DOCUMENTATION
- MSG_MISSING_PARAMETERS
- MSG_PARAMETERS_ARG_NAME_MISMATCH
- MSG_PARAMETERS_ARG_SIZE_MISMATCH
- MSG_PARAMETERS_SHOULD_BE_BEFORE_RETURNS
- MSG_RANGE_BODY_EMPTY
- MSG_RETURNS_SHOULD_BE_LAST
- MSG_UNNECESSARY_PARAMETERS
- PARMS_DOC
- PARMS_REGEXP
- RETURNS_DOC
- RETURNS_REGEXP
Public Instance Methods
on_def(node)
click to toggle source
Private Instance Methods
add_format(message)
click to toggle source
# File lib/rubocop/cop/style/public_method_documentation.rb, line 86 def add_format(message) format(message, @method_name) end
add_offense(node, location: :expression, message: nil, severity: nil)
click to toggle source
Calls superclass method
# File lib/rubocop/cop/style/public_method_documentation.rb, line 90 def add_offense(node, location: :expression, message: nil, severity: nil) super(node, message: add_format(message), severity: severity) end
check(node)
click to toggle source
# File lib/rubocop/cop/style/public_method_documentation.rb, line 94 def check(node) return if non_public?(node) # return if documentation_comment?(node) prk_documentation_comment(node) end
check_blank_comments(description_range, parameters_range, returns_range, attrs_range)
click to toggle source
# File lib/rubocop/cop/style/public_method_documentation.rb, line 203 def check_blank_comments(description_range, parameters_range, returns_range, attrs_range) unless description_range.missing? # rubocop:disable Layout/LineLength add_offense(description_range.start_comment, message: MSG_DESCRIPTION_SHOULD_NOT_BEGIN_WITH_BLANK_COMMENT) if description_range.starts_with_empty_comment? add_offense(description_range.end_comment, message: MSG_DESCRIPTION_SHOULD_END_WITH_BLANK_COMMENT) unless description_range.ends_with_empty_comment? end add_offense(parameters_range.start_comment, message: MSG_PARAMETERS_IS_MISSING_FIRST_BLANK_COMMENT) unless parameters_range.first_empty_comment? add_offense(parameters_range.end_comment, message: MSG_PARAMETERS_SHOULD_END_WITH_BLANK_COMMENT) unless parameters_range.ends_with_empty_comment? add_offense(returns_range.start_comment, message: MSG_RETURNS_IS_MISSING_FIRST_BLANK_COMMENT) unless returns_range.first_empty_comment? add_offense(returns_range.end_comment, message: MSG_RETURNS_SHOULD_END_WITH_BLANK_COMMENT) unless returns_range.ends_with_empty_comment? add_offense(attrs_range.start_comment, message: MSG_ATTRIBUTES_IS_MISSING_FIRST_BLANK_COMMENT) unless attrs_range.first_empty_comment? ends_with_empty_comment_ = attrs_range.ends_with_empty_comment? add_offense(attrs_range.end_comment, message: MSG_ATTRIBUTES_SHOULD_END_WITH_BLANK_COMMENT) unless ends_with_empty_comment_ # rubocop:enable Layout/LineLength end
check_body(range)
click to toggle source
# File lib/rubocop/cop/style/public_method_documentation.rb, line 222 def check_body(range) # puts "check_body=#{range.type} for #{@method_name}" # puts range.start_comment.text body = range.range_body found = false body.each_with_index do |line, _i| # puts "check_body loop text=#{line.text}" next if range.empty_comm?(line) found = true text = line.text.to_s if range.returns? # puts "check_body ret DOC_RET_REGEXP) text=#{DOC_RET_REGEXP.match(text)}" # puts "check_body (DOC_SUB_PARM_REGEXP) text=#{DOC_SUB_PARM_REGEXP.match(text)}" unless DOC_RET_REGEXP.match(text) || DOC_SUB_PARM_REGEXP.match(text) add_offense(line, message: format(MSG_ILLEGAL_RANGE_RET_BODY_FORMAT, range.type)) unless text.start_with?('# **') add_offense(line, message: format(MSG_ILLEGAL_RANGE_BODY_FORMAT_SUB, range.type)) if text.start_with?('# **') end else # puts "check_body DOC_PARM_REGEXP) text=#{DOC_PARM_REGEXP.match(text)}" # puts "check_body (DOC_SUB_PARM_REGEXP) text=#{DOC_SUB_PARM_REGEXP.match(text)}" unless DOC_PARM_REGEXP.match(text) || DOC_SUB_PARM_REGEXP.match(text) add_offense(line, message: format(MSG_ILLEGAL_RANGE_BODY_FORMAT, range.type)) unless text.start_with?('# **') add_offense(line, message: format(MSG_ILLEGAL_RANGE_BODY_FORMAT_SUB, range.type)) if text.start_with?('# **') end end end # puts "check_body found=#{found}" # puts "check_body adding_offense=#{found}" unless found add_offense(range.start_comment, message: format(MSG_RANGE_BODY_EMPTY, range.type)) unless found end
check_parms_and_args(args, parameters_range)
click to toggle source
# File lib/rubocop/cop/style/public_method_documentation.rb, line 254 def check_parms_and_args(args, parameters_range) # pns = parm_names(range_lines(preceding_lines, parameters_range)) pns = parameters_range.parm_names # rubocop:disable Layout/LineLength add_offense(pns[args.size][0], message: format(MSG_PARAMETERS_ARG_SIZE_MISMATCH, pns.size, args.size)) if pns.size > args.size add_offense(args[pns.size], message: format(MSG_PARAMETERS_ARG_SIZE_MISMATCH, pns.size, args.size)) if args.size > pns.size # rubocop:enable Layout/LineLength match_parms_to_args(args, pns) end
get_arg_name(arg)
click to toggle source
# File lib/rubocop/cop/style/public_method_documentation.rb, line 283 def get_arg_name(arg) name = arg.node_parts[0].to_s # handle unused arguments, which begin with _ return name[1...name.size] if name[0] == '_' name end
match_parms_to_args(args, pns)
click to toggle source
# File lib/rubocop/cop/style/public_method_documentation.rb, line 266 def match_parms_to_args(args, pns) pns.each_with_index do |param_pair, i| break if args[i].nil? arg_name = get_arg_name(args[i]) param_line = param_pair[0] param_name = param_pair[1] # puts "Comparing arg name #{arg_name} with parm name #{param_name} ans=#{param_name == arg_name}" next if param_name == arg_name add_offense( param_line, message: format(MSG_PARAMETERS_ARG_NAME_MISMATCH, param_name, arg_name) ) end end
parse_documentation(comments)
click to toggle source
# File lib/rubocop/cop/style/public_method_documentation.rb, line 155 def parse_documentation(comments) desc = MethodDocRange.new(comments, 'Description') returns = MethodDocRange.new(comments, 'Return') parms = MethodDocRange.new(comments, 'Parameter') attrs = MethodDocRange.new(comments, 'Attribute') current = nil comments.each_with_index do |comment_line, i| text_line = comment_line.text if RETURNS_REGEXP.match?(text_line) current.end = i - 1 unless current.nil? returns.start = i # [comment_line, i, 0] current = returns elsif PARMS_REGEXP.match?(text_line) current.end = i - 1 unless current.nil? parms.start = i # [comment_line, i, 0] current = parms elsif ATTR_REGEXP.match?(text_line) current.end = i - 1 unless current.nil? attrs.start = i # [comment_line, i, 0] current = attrs elsif i == 0 current.end = i - 1 unless current.nil? desc.start = i # [comment_line, i, 0] current = desc end current.end = comments.size - 1 end # !parms.first_comment? && !returns.first_comment? add_offense(comments[0], message: MSG_MISSING_DESCRIPTION) if desc.missing? unless parms.missing? guard = parms.first_comment_equal?(PARMS_DOC) add_offense(parms.start_comment, message: MSG_PARAMETERS_DOES_MATCH_MATCH) unless guard end unless returns.missing? guard = returns.first_comment_equal?(RETURNS_DOC) add_offense(returns.start_comment, message: MSG_RETURNS_DOES_NOT_MATCH) unless guard end unless attrs.missing? add_offense(attrs.start_comment, message: MSG_RETURNS_DOES_NOT_MATCH) unless attrs.first_comment_equal?(ATTRS_DOC) end # puts 'parse_document result' # puts(" desc =#{desc.to_s}") # puts(" parms=#{parms.to_s}") # puts(" returns=#{returns.to_s}") # puts(" attrs=#{attrs.to_s}") [desc, parms, returns, attrs] end
prk_documentation_comment(node)
click to toggle source
# File lib/rubocop/cop/style/public_method_documentation.rb, line 101 def prk_documentation_comment(node) @method_name = node.children.first.to_s # puts " processing: #{@method_name}" preceding_lines = preceding_lines(node) return add_offense(node, message: MSG_MISSING_DOCUMENTATION) unless preceding_comment?(node, preceding_lines.last) description_range, parameters_range, returns_range, attrs_range = parse_documentation(preceding_lines) add_offense(preceding_lines[0], message: MSG_MISSING_DESCRIPTION) if description_range.nil? # order # description_range # parameters_range || attrs_range # returns_range # grd = description_range.before?(parameters_range) && description_range.before?(returns_range) && description_range.before?(attrs_range) add_offense(description_range.start_comment, message: MSG_DESCRIPTIION_SHOULD_BE_FIRST) unless grd guard = parameters_range.before?(returns_range) grd = guard && attrs_range.before?(returns_range) add_offense(description_range.start_comment, message: MSG_RETURNS_SHOULD_BE_LAST) unless grd grd = attrs_range.missing? || parameters_range.missing? add_offense(attrs_range.start_comment, message: MSG_ATTRIBUTES_AND_PARAMETERS_NO_COEXIST) unless grd # copied from documentation_comment.rb not_special_comm = preceding_lines(node) do |comment| !AnnotationComment.new(comment, annotation_keywords).annotation? && !interpreter_directive_comment?(comment) && !rubocop_directive_comment?(comment) end return add_offense(preceding_lines(node)[0], message: MSG_INVALID_DOCUMENTATION) unless not_special_comm add_offense(parameters_range.start_comment, message: MSG_PARAMETERS_SHOULD_BE_BEFORE_RETURNS) unless guard check_blank_comments(description_range, parameters_range, returns_range, attrs_range) args = node.arguments guard = parameters_range.missing? && !args.empty? return add_offense(preceding_lines[0], message: MSG_MISSING_PARAMETERS) if guard guard = !parameters_range.missing? && args.empty? return add_offense(parameters_range.start_comment, message: MSG_UNNECESSARY_PARAMETERS) if guard check_body(parameters_range) unless parameters_range.missing? check_body(attrs_range) unless attrs_range.missing? check_body(returns_range) unless returns_range.missing? check_parms_and_args(args, parameters_range) unless parameters_range.missing? end