lib/rubocop/cop/rspec/described_class.rb in rubocop-rspec-1.10.0 vs lib/rubocop/cop/rspec/described_class.rb in rubocop-rspec-1.11.0

- old
+ new

@@ -4,28 +4,42 @@ module Cop module RSpec # Checks that tests use `described_class`. # # If the first argument of describe is a class, the class is exposed to - # each example via described_class - this should be used instead of - # repeating the class. + # each example via described_class. # - # @example + # This cop can be configured using the `EnforcedStyle` option + # + # @example `EnforcedStyle: described_class` # # bad # describe MyClass do # subject { MyClass.do_something } # end # # # good # describe MyClass do # subject { described_class.do_something } # end + # + # @example `EnforcedStyle: explicit` + # # bad + # describe MyClass do + # subject { described_class.do_something } + # end + # + # # good + # describe MyClass do + # subject { MyClass.do_something } + # end + # class DescribedClass < Cop include RuboCop::RSpec::TopLevelDescribe + include RuboCop::Cop::ConfigurableEnforcedStyle DESCRIBED_CLASS = 'described_class'.freeze - MSG = "Use `#{DESCRIBED_CLASS}` instead of `%s`".freeze + MSG = 'Use `%s` instead of `%s`'.freeze def_node_matcher :common_instance_exec_closure?, <<-PATTERN (block (send (const nil {:Class :Module}) :new ...) ...) PATTERN @@ -36,34 +50,51 @@ 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)) + # in case we explicit style is used, this cop needs to remember what's + # being described, so to replace described_class with the constant + @described_class = described_class + + find_usage(body) do |match| + add_offense(match, :expression, message(match.const_name)) end end def autocorrect(node) + replacement = if style == :described_class + DESCRIBED_CLASS + else + @described_class.const_name + end lambda do |corrector| - corrector.replace(node.loc.expression, DESCRIBED_CLASS) + corrector.replace(node.loc.expression, replacement) end end private - def find_constant_usage(node, described_class, &block) - yield(node) if node.eql?(described_class) + def find_usage(node, &block) + yield(node) if offensive?(node) return unless node.is_a?(Parser::AST::Node) return if scope_change?(node) || node.const_type? node.children.each do |child| - find_constant_usage(child, described_class, &block) + find_usage(child, &block) end end + def message(offense) + if style == :described_class + format(MSG, DESCRIBED_CLASS, offense) + else + format(MSG, @described_class.const_name, DESCRIBED_CLASS) + end + end + def scope_change?(node) scope_changing_syntax?(node) || common_instance_exec_closure?(node) || skippable_block?(node) end @@ -72,9 +103,18 @@ node.block_type? && !rspec_block?(node) && skip_blocks? end def skip_blocks? cop_config['SkipBlocks'].equal?(true) + end + + def offensive?(node) + if style == :described_class + node.eql?(@described_class) + else + _receiver, method_name, *_args = *node + method_name == :described_class + end end end end end end