Skip to content

Commit

Permalink
Remove support for present tense predicates
Browse files Browse the repository at this point in the history
  • Loading branch information
pirj committed Jan 31, 2021
1 parent 7f945e7 commit b61855c
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 62 deletions.
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Breaking Changes:
* Remove support for legacy RSpec matchers (pre 3). (Phil Pirozhkov, #1253)
* Remove `include_chain_clauses_in_custom_matcher_descriptions` option
and make it the default. (Phil Pirozhkov, #1279)
* Remove support for present-tense dynamic predicate. (Phil Pirozhkov, #1286)

Enhancements:

Expand Down
18 changes: 1 addition & 17 deletions lib/rspec/matchers/built_in/has.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,7 @@ def private_predicate?
end

def predicate_result
@predicate_result = actual.__send__(predicate_method_name, *@args, &@block)
end

def predicate_method_name
predicate
@predicate_result = actual.__send__(predicate, *@args, &@block)
end

def predicate_matches?(value=true)
Expand Down Expand Up @@ -129,25 +125,13 @@ def predicate
@predicate ||= :"#{root}?"
end

def predicate_method_name
actual.respond_to?(predicate) ? predicate : present_tense_predicate
end

def failure_to_respond_explanation
super || if predicate == :true?
" or perhaps you meant `be true` or `be_truthy`"
elsif predicate == :false?
" or perhaps you meant `be false` or `be_falsey`"
end
end

def predicate_accessible?
super || actual.respond_to?(present_tense_predicate)
end

def present_tense_predicate
:"#{root}s?"
end
end
end
end
Expand Down
65 changes: 20 additions & 45 deletions spec/rspec/matchers/built_in/be_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
]).to include a_happy_object
end

it "passes when actual returns true for :predicates? (present tense)" do
actual = double("actual", :exists? => true, :exist? => true)
expect(actual).to be_exist
it "passes when actual returns true for :predicate?" do
actual = double("actual", :happy? => true)
expect(actual).to be_happy
end

context "when actual returns false for :predicate?" do
Expand Down Expand Up @@ -142,11 +142,14 @@ def object.predicate?(returns:); returns; end
expect { expect(object).to be_predicate(true) }.to raise_error(ArgumentError)
end

it 'falls back to a present-tense form of the predicate when needed' do
it 'does not fall back to a present-tense form of the predicate' do
# NOTE: falling back to a present-tense form was removed in RSpec 4
mouth = Object.new
def mouth.frowns?(return_val); return_val; end
def mouth.frowns?; end

expect(mouth).to be_frown(true)
expect {
expect(mouth).to be_frown
}.to fail_including("to respond to `frown?`")
end

it 'fails when :predicate? is private' do
Expand Down Expand Up @@ -185,14 +188,6 @@ def foo?
}.to raise_error(NameError, /aaaah/)
end

it "fails on error other than NameError (with the present tense predicate)" do
actual = double
expect(actual).to receive(:foos?).and_raise("aaaah")
expect {
expect(actual).to be_foo
}.to raise_error(/aaaah/)
end

it "does not support operator chaining like a basic `be` matcher does" do
matcher = be_happy
value = double(:happy? => false)
Expand Down Expand Up @@ -356,56 +351,36 @@ def foo?
}.to fail_including("to respond to `happy?`")
end

it 'passes the block on to the present-tense predicate form' do
it 'passes the block on to the predicate' do
mouth = Object.new
def mouth.frowns?; yield; end
def mouth.frown?; yield; end

expect(mouth).to be_frown { true }
expect(mouth).not_to be_frown { false }
end

it 'works with a do..end block for either predicate form' do
mouth1 = Object.new
def mouth1.frown?; yield; end
mouth2 = Object.new
def mouth2.frowns?; yield; end

expect(mouth1).to be_frown do
true
end

expect(mouth1).not_to be_frown do
false
end
it 'works with a do..end block' do
mouth = Object.new
def mouth.frown?; yield; end

expect(mouth2).to be_frown do
expect(mouth).to be_frown do
true
end

expect(mouth2).not_to be_frown do
expect(mouth).not_to be_frown do
false
end
end

it 'prefers a { ... } block to a do/end block because it binds more tightly' do
mouth1 = Object.new
def mouth1.frown?; yield; end
mouth2 = Object.new
def mouth2.frowns?; yield; end

expect(mouth1).to be_frown { true } do
false
end

expect(mouth1).not_to be_frown { false } do
true
end
mouth = Object.new
def mouth.frown?; yield; end

expect(mouth2).to be_frown { true } do
expect(mouth).to be_frown { true } do
false
end

expect(mouth2).not_to be_frown { false } do
expect(mouth).not_to be_frown { false } do
true
end
end
Expand Down

0 comments on commit b61855c

Please sign in to comment.