class RuboCop::Cop::RSpec::MultipleSubjects

Checks if an example group defines `subject` multiple times.

@example

# bad
describe Foo do
  subject(:user) { User.new }
  subject(:post) { Post.new }
end

# good
describe Foo do
  let(:user) { User.new }
  subject(:post) { Post.new }
end

The autocorrect behavior for this cop depends on the type of duplication:

- If multiple named subjects are defined then this probably indicates
  that the overwritten subjects (all subjects except the last
  definition) are effectively being used to define helpers. In this
  case they are replaced with `let`.

- If multiple unnamed subjects are defined though then this can *only*
  be dead code and we remove the overwritten subject definitions.

- If subjects are defined with `subject!` then we don't autocorrect.
  This is enough of an edge case that people can just move this to
  a `before` hook on their own

Constants

MSG

Public Instance Methods

on_block(node) click to toggle source
# File lib/rubocop/cop/rspec/multiple_subjects.rb, line 42
def on_block(node)
  return unless example_group?(node)

  subjects = RuboCop::RSpec::ExampleGroup.new(node).subjects

  subjects[0...-1].each do |subject|
    add_offense(subject) do |corrector|
      autocorrect(corrector, subject)
    end
  end
end

Private Instance Methods

autocorrect(corrector, subject) click to toggle source
# File lib/rubocop/cop/rspec/multiple_subjects.rb, line 56
def autocorrect(corrector, subject)
  return unless subject.method_name.equal?(:subject) # Ignore `subject!`

  if named_subject?(subject)
    rename_autocorrect(corrector, subject)
  else
    remove_autocorrect(corrector, subject)
  end
end
named_subject?(node) click to toggle source
# File lib/rubocop/cop/rspec/multiple_subjects.rb, line 66
def named_subject?(node)
  node.send_node.arguments?
end
remove_autocorrect(corrector, node) click to toggle source
# File lib/rubocop/cop/rspec/multiple_subjects.rb, line 74
def remove_autocorrect(corrector, node)
  range = range_by_whole_lines(node.source_range,
                               include_final_newline: true)
  corrector.remove(range)
end
rename_autocorrect(corrector, node) click to toggle source
# File lib/rubocop/cop/rspec/multiple_subjects.rb, line 70
def rename_autocorrect(corrector, node)
  corrector.replace(node.send_node.loc.selector, 'let')
end