lib/rubocop/cop/rspec/described_class.rb in rubocop-rspec-1.5.3 vs lib/rubocop/cop/rspec/described_class.rb in rubocop-rspec-1.6.0
- old
+ new
@@ -18,44 +18,97 @@
# subject { described_class.do_something }
# end
class DescribedClass < Cop
include RuboCop::RSpec::TopLevelDescribe
- MESSAGE = 'Use `described_class` instead of `%s`'.freeze
+ DESCRIBED_CLASS = 'described_class'.freeze
+ MSG = "Use `#{DESCRIBED_CLASS}` instead of `%s`".freeze
- def on_block(node)
- method, _args, body = *node
- return unless top_level_describe?(method)
+ RSPEC_BLOCK_METHODS = '
+ :after
+ :around
+ :before
+ :context
+ :describe
+ :example
+ :example_group
+ :fcontext
+ :fdescribe
+ :feature
+ :fexample
+ :ffeature
+ :fit
+ :focus
+ :fscenario
+ :fspecify
+ :it
+ :let
+ :let!
+ :scenario
+ :specify
+ :xcontext
+ :xdescribe
+ :xexample
+ :xfeature
+ :xit
+ :xscenario
+ :xspecify
+ '.freeze
- _receiver, _method_name, object = *method
- return unless object && object.type.equal?(:const)
+ def_node_matcher :described_constant, <<-PATTERN
+ (block $(send _ :describe $(const ...)) (args) $_)
+ PATTERN
- inspect_children(body, object)
+ def_node_matcher :common_instance_exec_closure?, <<-PATTERN
+ (block (send (const nil {:Class :Module}) :new ...) ...)
+ PATTERN
+
+ def_node_matcher :rspec_block?, <<-PATTERN
+ (block (send nil {#{RSPEC_BLOCK_METHODS}} ...) ...)
+ PATTERN
+
+ def_node_matcher :scope_changing_syntax?, '{def class module}'
+
+ def on_block(node)
+ describe, described_class, body = described_constant(node)
+ return unless top_level_describe?(describe)
+
+ find_constant_usage(body, described_class) do |match|
+ add_offense(match, :expression, format(MSG, match.const_name))
+ end
end
def autocorrect(node)
lambda do |corrector|
- corrector.replace(node.loc.expression, 'described_class')
+ corrector.replace(node.loc.expression, DESCRIBED_CLASS)
end
end
private
- def inspect_children(node, object)
+ def find_constant_usage(node, described_class, &block)
+ yield(node) if node.eql?(described_class)
+
return unless node.instance_of?(Node)
- return if scope_change?(node) || node.type.equal?(:const)
+ return if scope_change?(node) || node.const_type?
node.children.each do |child|
- if child.eql?(object)
- name = object.loc.expression.source
- add_offense(child, :expression, format(MESSAGE, name))
- end
- inspect_children(child, object)
+ find_constant_usage(child, described_class, &block)
end
end
def scope_change?(node)
- [:def, :class, :module].include?(node.type)
+ scope_changing_syntax?(node) ||
+ common_instance_exec_closure?(node) ||
+ skippable_block?(node)
+ end
+
+ def skippable_block?(node)
+ node.block_type? && !rspec_block?(node) && skip_blocks?
+ end
+
+ def skip_blocks?
+ cop_config['SkipBlocks'].equal?(true)
end
end
end
end
end