8dd097a915
From the Ruby style guide: # bad class FooError < StandardError end # okish class FooError < StandardError; end # good FooError = Class.new(StandardError) This cop does that, but only for error classes (classes where the superclass ends in 'Error'). We have empty controllers and models, which are perfectly valid empty classes.
64 lines
1.6 KiB
Ruby
64 lines
1.6 KiB
Ruby
module RuboCop
|
|
module Cop
|
|
# This cop makes sure that custom error classes, when empty, are declared
|
|
# with Class.new.
|
|
#
|
|
# @example
|
|
# # bad
|
|
# class FooError < StandardError
|
|
# end
|
|
#
|
|
# # okish
|
|
# class FooError < StandardError; end
|
|
#
|
|
# # good
|
|
# FooError = Class.new(StandardError)
|
|
class CustomErrorClass < RuboCop::Cop::Cop
|
|
MSG = 'Use `Class.new(SuperClass)` to define an empty custom error class.'.freeze
|
|
|
|
def on_class(node)
|
|
_klass, parent, body = node.children
|
|
|
|
return if body
|
|
|
|
parent_klass = class_name_from_node(parent)
|
|
|
|
return unless parent_klass && parent_klass.to_s.end_with?('Error')
|
|
|
|
add_offense(node, :expression)
|
|
end
|
|
|
|
def autocorrect(node)
|
|
klass, parent, _body = node.children
|
|
replacement = "#{class_name_from_node(klass)} = Class.new(#{class_name_from_node(parent)})"
|
|
|
|
lambda do |corrector|
|
|
corrector.replace(node.source_range, replacement)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
# The nested constant `Foo::Bar::Baz` looks like:
|
|
#
|
|
# s(:const,
|
|
# s(:const,
|
|
# s(:const, nil, :Foo), :Bar), :Baz)
|
|
#
|
|
# So recurse through that to get the name as written in the source.
|
|
#
|
|
def class_name_from_node(node, suffix = nil)
|
|
return unless node&.type == :const
|
|
|
|
name = node.children[1].to_s
|
|
name = "#{name}::#{suffix}" if suffix
|
|
|
|
if node.children[0]
|
|
class_name_from_node(node.children[0], name)
|
|
else
|
|
name
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|