rubocop / rubocop-rspec

Code style checking for RSpec files.
https://docs.rubocop.org/rubocop-rspec
MIT License
805 stars 277 forks source link

Cop idea: Replace `equal` with `be` #1676

Open ydakuka opened 1 year ago

ydakuka commented 1 year ago

Reference: https://github.com/rspec/rspec-expectations#identity

Actual behavior

I have the following spec:

# frozen_string_literal: true

require 'rails_helper'

RSpec.describe ApplicationHelper do
  specify do
    expect(foo).to equal described_class
  end

  def foo
    described_class
  end
end

I run rubocop and don't get any offences:

ydakuka@yauhenid:~/Work/project$ bin/rails_docker rubocop spec/helpers/application_helper_spec.rb 
Inspecting 1 file
.

1 file inspected, no offenses detected

Expected behavior

# frozen_string_literal: true

require 'rails_helper'

RSpec.describe ApplicationHelper do
  specify do
    expect(foo).to be described_class
  end

  def foo
    described_class
  end
end

Rubocop

ydakuka@yauhenid:~/Work/project$ bin/rails_docker rubocop -V
1.54.1 (using Parser 3.2.2.3, rubocop-ast 1.29.0, running on ruby 2.7.8) [x86_64-linux]
  - rubocop-capybara 2.18.0
  - rubocop-factory_bot 2.23.1
  - rubocop-performance 1.18.0
  - rubocop-rails 2.20.2
  - rubocop-rake 0.6.0
  - rubocop-rspec 2.22.0
  - rubocop-thread_safety 0.5.1
pirj commented 1 year ago

Both matchers exist in RSpec. Are they always interchangeable? Why one should be used instead of another?

ydakuka commented 1 year ago

Are they always interchangeable?

If any arguments pass, the matchers will be equal. https://github.com/rspec/rspec-expectations/blob/main/lib/rspec/matchers.rb#L349

Why one should be used instead of another?

In my opinion the be matcher is used oftener, while the equal matcher is used less frequently. (https://github.com/rspec/rspec-expectations/tree/main#comparisons , https://github.com/rspec/rspec-expectations/tree/main#truthiness)

pirj commented 1 year ago

be matcher is used oftener

Can you prove that by harvesting real-world-rspec? I’d specifically be interested in cases where the argument is not among nil/true/false.

bquorning commented 1 year ago

Related: #933.

ydakuka commented 1 year ago

Can you prove that by harvesting real-world-rspec? I’d specifically be interested in cases where the argument is not among nil/true/false.

@pirj I've searched in real-world-rspec and got the following results:

Searching 54609 files for "(?!.*nil|.*false|.*true)(\.to_not equal(\ |\(|\_).{1,})" (regex)
10 matches across 6 files

Searching 54609 files for "(?!.*nil|.*false|.*true)(\.to equal(\ |\(|\_).{1,})" (regex)
595 matches across 157 files

Searching 54609 files for "(?!.*nil|.*false|.*true)(\.not_to equal(\ |\(|\_).{1,})" (regex)
39 matches across 20 files

and

Searching 54609 files for "(?!.*nil|.*false|.*true)(\.to_not be(\ |\(|\_).{1,})" (regex)
672 matches across 247 files

Searching 54609 files for "(?!.*nil|.*false|.*true)(\.to be(\ |\(|\_).{1,})" (regex)
35901 matches across 6329 files

Searching 54609 files for "(?!.*nil|.*false|.*true)(\.not_to be(\ |\(|\_).{1,})" (regex)
6345 matches across 1752 files