class RuboCop::Cop::Style::Documentation

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, constant definitions or constant visibility declarations.

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.

@example

# bad
class Person
  # ...
end

module Math
end

# good
# Description/Explanation of Person class
class Person
  # ...
end

# allowed
  # Class without body
  class Person
  end

  # Namespace - A namespace can be a class or a module
  # Containing a class
  module Namespace
    # Description/Explanation of Person class
    class Person
      # ...
    end
  end

  # Containing constant visibility declaration
  module Namespace
    class Private
    end

    private_constant :Private
  end

  # Containing constant definition
  module Namespace
    Public = Class.new
  end

  # Macro calls
  module Namespace
    extend Foo
  end

@example AllowedConstants: [‘ClassMethods’]

# good
module A
  module ClassMethods
    # ...
  end
 end

Constants

MSG

Public Instance Methods

on_class(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 89
def on_class(node)
  return unless node.body

  check(node, node.body)
end
on_module(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 95
def on_module(node)
  check(node, node.body)
end

Private Instance Methods

allowed_constants() click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 168
def allowed_constants
  @allowed_constants ||= cop_config.fetch('AllowedConstants', []).map(&:intern)
end
check(node, body) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 101
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 macro_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
compact_namespace?(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 141
def compact_namespace?(node)
  /::/.match?(node.loc.name.source)
end
constant_allowed?(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 137
def constant_allowed?(node)
  allowed_constants.include?(node.identifier.short_name)
end
constant_declaration?(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 133
def constant_declaration?(node)
  constant_definition?(node) || constant_visibility_declaration?(node)
end
identifier(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 172
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
macro_only?(body) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 118
def macro_only?(body)
  (body.respond_to?(:macro?) && body.macro?) ||
    (body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) })
end
namespace?(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 123
def namespace?(node)
  return false unless node

  if node.begin_type?
    node.children.all? { |child| constant_declaration?(child) }
  else
    constant_definition?(node)
  end
end
nodoc(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 164
def nodoc(node)
  processed_source.ast_with_comments[node.children.first].first
end
nodoc?(comment, require_all: false) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 160
def nodoc?(comment, require_all: false)
  /^#\s*:nodoc:#{"\s+all\s*$" if require_all}/.match?(comment.text)
end
nodoc_comment?(node, 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 150
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
nodoc_self_or_outer_module?(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 113
def nodoc_self_or_outer_module?(node)
  nodoc_comment?(node) ||
    (compact_namespace?(node) && nodoc_comment?(outer_module(node).first))
end
qualify_const(node) click to toggle source
# File lib/rubocop/cop/style/documentation.rb, line 178
def qualify_const(node)
  return if node.nil? || node.cbase_type?

  [qualify_const(node.namespace), node.short_name].compact
end