Class: RuboCop::Cop::Style::EmptyClassDefinition

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
ConfigurableEnforcedStyle
Defined in:
lib/rubocop/cop/style/empty_class_definition.rb

Overview

Enforces consistent style for empty class definitions.

This cop can enforce either a standard class definition or Class.new for classes with no body.

The supported styles are:

  • class_keyword (default) - prefer standard class definition over Class.new
  • class_new - prefer Class.new over class definition

One difference between the two styles is that the Class.new form does not make the subclass name available to the base class's inherited callback. For this reason, EnforcedStyle: class_keyword is set as the default style. Class definitions without a superclass, which are not involved in inheritance, are not detected. This ensures safe detection regardless of the applied style. This avoids overlapping responsibilities with the Lint/EmptyClass cop.

Use AllowedParentClasses to permit both styles for specific parent classes. For example, adding StandardError allows both Error = Class.new(StandardError) and class Error < StandardError; end regardless of the enforced style.

Examples:

EnforcedStyle: class_keyword (default)

# bad
FooError = Class.new(StandardError)

# okish
class FooError < StandardError; end

# good
class FooError < StandardError
end

EnforcedStyle: class_new

# bad
class FooError < StandardError
end

# bad
class FooError < StandardError; end

# good
FooError = Class.new(StandardError)

AllowedParentClasses: ['StandardError']

# good - allowed regardless of EnforcedStyle
FooError = Class.new(StandardError)

# good - allowed regardless of EnforcedStyle
class FooError < StandardError
end

Constant Summary collapse

MSG_CLASS_KEYWORD =
'Use the `class` keyword instead of `Class.new` to define an empty class.'
MSG_CLASS_NEW =
'Use `Class.new` instead of the `class` keyword to define an empty class.'

Constants inherited from Base

Base::RESTRICT_ON_SEND

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source, #project_index

Instance Method Summary collapse

Methods included from AutoCorrector

support_autocorrect?

Methods included from ConfigurableEnforcedStyle

#alternative_style, #alternative_styles, #ambiguous_style_detected, #correct_style_detected, #detected_style, #detected_style=, #no_acceptable_style!, #no_acceptable_style?, #opposite_style_detected, #style, #style_configured?, #style_detected, #style_parameter_name, #supported_styles, #unexpected_style_detected

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, #always_autocorrect?, autocorrect_incompatible_with, badge, #begin_investigation, #callbacks_needed, callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #contextual_autocorrect?, #cop_config, cop_name, #cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #message, #offenses, #on_investigation_end, #on_new_investigation, #on_other_file, #parse, #parser_engine, #ready, #relevant_file?, requires_gem, #string_literals_frozen_by_default?, support_autocorrect?, support_multiple_source?, #target_gem_version, #target_rails_version, #target_ruby_version

Methods included from ExcludeLimit

cop_dir_for, #exclude_limit, read_limits

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

silence_warnings

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Instance Method Details

#class_new_assignment(node) ⇒ Object



66
67
68
# File 'lib/rubocop/cop/style/empty_class_definition.rb', line 66

def_node_matcher :class_new_assignment, <<~PATTERN
  (casgn _ _ $(send (const _ :Class) :new _))
PATTERN

#on_casgn(node) ⇒ Object



70
71
72
73
74
75
76
77
78
79
# File 'lib/rubocop/cop/style/empty_class_definition.rb', line 70

def on_casgn(node)
  return unless %i[class_keyword class_definition].include?(style)
  return unless (class_new_node = class_new_assignment(node))
  return if (arg = class_new_node.first_argument) && !arg.const_type?
  return if allowed_parent_class?(class_new_node.first_argument.source)

  add_offense(node, message: MSG_CLASS_KEYWORD) do |corrector|
    autocorrect_class_new(corrector, node, class_new_node)
  end
end

#on_class(node) ⇒ Object



81
82
83
84
85
86
87
88
89
90
# File 'lib/rubocop/cop/style/empty_class_definition.rb', line 81

def on_class(node)
  return unless style == :class_new
  return unless node.parent_class
  return if (body = node.body) && !body.children.empty?
  return if allowed_parent_class?(node.parent_class.source)

  add_offense(node, message: MSG_CLASS_NEW) do |corrector|
    autocorrect_class_definition(corrector, node)
  end
end