class RuboCop::Cop::Style::Documentation


end
end
# …
module ClassMethods
module A
# good
@example AllowedConstants: [‘ClassMethods’]
end
extend Foo
module Namespace
# Macro calls
end
Public = Class.new
module Namespace
# Containing constant definition
end
private_constant :Private
end
class Private
module Namespace
# Containing constant visibility declaration
end
end
# …
class Person
# Description/Explanation of Person class
module Namespace
# Containing a class
# Namespace - A namespace can be a class or a module
end
class Person
# Class without body
# allowed
end
# …
class Person
# Description/Explanation of Person class
# good
end
module Math
end
# …
class Person
# bad
@example
same for all its children.
a “#:nodoc:” comment next to it. Likewise, “#:nodoc: all” does the
The documentation requirement is annulled if the class or module has
declarations.
classes, other modules, constant definitions or constant visibility
namespace modules - modules that have nothing in their bodies except
modules. Classes with no body are exempt from the check and so are
Checks for missing top-level documentation of classes and

def allowed_constants

def allowed_constants
  @allowed_constants ||= cop_config.fetch('AllowedConstants', []).map(&:intern)
end

def check(node, body)

def check(node, body)
  return if namespace?(body)
  return if documentation_comment?(node)
  return if constant_allowed?(node)
  return if nodoc_self_or_outer_module?(node)
  return if include_statement_only?(body)
  range = range_between(node.loc.expression.begin_pos, node.loc.name.end_pos)
  message = format(MSG, type: node.type, identifier: identifier(node))
  add_offense(range, message: message)
end

def compact_namespace?(node)

def compact_namespace?(node)
  /::/.match?(node.loc.name.source)
end

def constant_allowed?(node)

def constant_allowed?(node)
  allowed_constants.include?(node.identifier.short_name)
end

def constant_declaration?(node)

def constant_declaration?(node)
  constant_definition?(node) || constant_visibility_declaration?(node)
end

def identifier(node)

def identifier(node)
  # Get the fully qualified identifier for a class/module
  nodes = [node, *node.each_ancestor(:class, :module)]
  nodes.reverse_each.flat_map { |n| qualify_const(n.identifier) }.join('::')
end

def include_statement_only?(body)

def include_statement_only?(body)
  return true if include_statement?(body)
  body.respond_to?(:children) && body.children.all? { |node| include_statement_only?(node) }
end

def namespace?(node)

def namespace?(node)
  return false unless node
  if node.begin_type?
    node.children.all? { |child| constant_declaration?(child) }
  else
    constant_definition?(node)
  end
end

def nodoc(node)

def nodoc(node)
  processed_source.ast_with_comments[node.children.first].first
end

def nodoc?(comment, require_all: false)

def nodoc?(comment, require_all: false)
  /^#\s*:nodoc:#{"\s+all\s*$" if require_all}/.match?(comment.text)
end

def nodoc_comment?(node, require_all: false)

parser-2.2.0.4.
Note: How end-of-line comments are associated with code changed in
proceeds to check its ancestors for :nodoc: all.
class/module. Unless the element is tagged with :nodoc:, the search
First checks if the :nodoc: comment is associated with the
def nodoc_comment?(node, require_all: false)
  return false unless node&.children&.first
  nodoc = nodoc(node)
  return true if same_line?(nodoc, node) && nodoc?(nodoc, require_all: require_all)
  nodoc_comment?(node.parent, require_all: true)
end

def nodoc_self_or_outer_module?(node)

def nodoc_self_or_outer_module?(node)
  nodoc_comment?(node) ||
    (compact_namespace?(node) && nodoc_comment?(outer_module(node).first))
end

def on_class(node)

def on_class(node)
  return unless node.body
  check(node, node.body)
end

def on_module(node)

def on_module(node)
  check(node, node.body)
end

def qualify_const(node)

def qualify_const(node)
  return if node.nil? || node.cbase_type? || node.self_type? || node.send_type?
  [qualify_const(node.namespace), node.short_name].compact
end