class RuboCop::Cop::Style::Documentation

This cop checks for missing top-level documentation of classes and modules. Classes with no body are exempt from the check and so are namespace modules - modules that have nothing in their bodies except classes, other modules, or constant definitions.

The documentation requirement is annulled if the class or module has a β€œ#:nodoc:” comment next to it. Likewise, β€œ#:nodoc: all” does the same for all its children.

Constants

MSG

Public Instance Methods

on_class(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 21
def on_class(node)
  _name, _superclass, body = *node
  return unless body
  return if namespace?(body)

  ast_with_comments = processed_source.ast_with_comments
  return if associated_comment?(node, ast_with_comments)
  return if nodoc_comment?(node, ast_with_comments)
  add_offense(node, :keyword, format(MSG, :class))
end
on_module(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 32
def on_module(node)
  _name, body = *node
  return if namespace?(body)

  ast_with_comments = processed_source.ast_with_comments
  return if associated_comment?(node, ast_with_comments)
  return if nodoc_comment?(node, ast_with_comments)
  add_offense(node, :keyword, format(MSG, :module))
end

Private Instance Methods

associated_comment?(node, ast_with_comments) click to toggle source

Returns true if the node has a comment on the line above it that isn't an annotation.

# File lib/rubocop/cop/style/documentation.rb, line 57
def associated_comment?(node, ast_with_comments)
  preceding_comments = preceding_comments(node, ast_with_comments)
  return false if preceding_comments.empty?

  distance = node.loc.keyword.line - preceding_comments.last.loc.line
  return false if distance > 1
  return false unless comment_line_only?(preceding_comments.last)

  # As long as there's at least one comment line that isn't an
  # annotation, it's OK.
  preceding_comments.any? { |comment| !annotation?(comment) }
end
comment_line_only?(comment) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 74
def comment_line_only?(comment)
  source_buffer = comment.loc.expression.source_buffer
  comment_line = source_buffer.source_line(comment.loc.line)
  comment_line =~ /^\s*#/
end
namespace?(body_node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 44
def namespace?(body_node)
  return false unless body_node

  case body_node.type
  when :begin
    body_node.children.all? { |node| constant_definition?(node) }
  else
    constant_definition?(body_node)
  end
end
nodoc_comment?(node, ast_with_comments, require_all = false) click to toggle source

First checks if the :nodoc: comment is associated with the class/module. Unless the element is tagged with :nodoc:, the search proceeds to check its ancestors for :nodoc: all. Note: How end-of-line comments are associated with code changed in parser-2.2.0.4.

# File lib/rubocop/cop/style/documentation.rb, line 85
def nodoc_comment?(node, ast_with_comments, require_all = false)
  return false unless node
  nodoc_node = node.children.first
  return false unless nodoc_node
  comment = ast_with_comments[nodoc_node].first

  if comment && comment.loc.line == node.loc.line
    regex = /^#\s*:nodoc:#{"\s+all\s*$" if require_all}/
    return true if comment.text =~ regex
  end

  nodoc_comment?(node.ancestors.first, ast_with_comments, true)
end
preceding_comments(node, ast_with_comments) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 70
def preceding_comments(node, ast_with_comments)
  ast_with_comments[node].select { |c| c.loc.line < node.loc.line }
end