class RuboCop::Cop::Style::Documentation

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

def associated_comment?(node, ast_with_comments)

isn't an annotation.
Returns true if the node has a comment on the line above it that
def associated_comment?(node, ast_with_comments)
  return false if ast_with_comments[node].empty?
  preceding_comment = ast_with_comments[node].last
  distance = node.loc.keyword.line - preceding_comment.loc.line
  return false if distance > 1
  # As long as there's at least one comment line that isn't an
  # annotation, it's OK.
  ast_with_comments[node].any? { |comment| !annotation?(comment) }
end

def check(ast, ast_with_comments)

def check(ast, ast_with_comments)
  ast.each_node(:class, :module) do |node|
    case node.type
    when :class
      _name, _superclass, body = *node
    when :module
      _name, body = *node
    end
    next if node.type == :class && !body
    next if namespace?(body)
    next if associated_comment?(node, ast_with_comments)
    add_offense(node, :keyword, format(MSG, node.type.to_s))
  end
end

def investigate(processed_source)

def investigate(processed_source)
  ast = processed_source.ast
  return unless ast
  ast_with_comments = Parser::Source::Comment.associate(
    ast,
    processed_source.comments
  )
  check(ast, ast_with_comments)
end

def namespace?(body_node)

def namespace?(body_node)
  return false unless body_node
  case body_node.type
  when :begin
    body_node.children.all? do |node|
      [:class, :module].include?(node.type)
    end
  when :class, :module
    true
  else
    false
  end
end