Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit cf52fe6

Browse files
committed
Merge pull request #193 from rspec/hash_match_array_failure
Provide a clear failure message when using `{}.should =~ {}`.
2 parents abefb76 + c7a91af commit cf52fe6

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

lib/rspec/matchers.rb

Lines changed: 1 addition & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -684,6 +684,6 @@ def match_array(array)
684
BuiltIn::MatchArray.new(array)
684
BuiltIn::MatchArray.new(array)
685
end
685
end
686

686

687-
OperatorMatcher.register(Array, '=~', BuiltIn::MatchArray)
687+
OperatorMatcher.register(Enumerable, '=~', BuiltIn::MatchArray)
688
end
688
end
689
end
689
end

lib/rspec/matchers/operator_matcher.rb

Lines changed: 17 additions & 1 deletion
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -31,7 +31,7 @@ def initialize(actual)
31

31

32
def self.use_custom_matcher_or_delegate(operator)
32
def self.use_custom_matcher_or_delegate(operator)
33
define_method(operator) do |expected|
33
define_method(operator) do |expected|
34-
if matcher = OperatorMatcher.get(@actual.class, operator)
34+
if uses_generic_implementation_of?(operator) && matcher = OperatorMatcher.get(@actual.class, operator)
35
@actual.send(::RSpec::Matchers.last_should, matcher.new(expected))
35
@actual.send(::RSpec::Matchers.last_should, matcher.new(expected))
36
else
36
else
37
eval_match(@actual, operator, expected)
37
eval_match(@actual, operator, expected)
@@ -62,6 +62,22 @@ def description
62

62

63
private
63
private
64

64

65+
if Method.method_defined?(:owner) # 1.8.6 lacks Method#owner :-(
66+
def uses_generic_implementation_of?(op)
67+
@actual.method(op).owner == ::Kernel
68+
end
69+
else
70+
def uses_generic_implementation_of?(op)
71+
# This is a bit of a hack, but:
72+
#
73+
# {}.method(:=~).to_s # => "#<Method: Hash(Kernel)#=~>"
74+
#
75+
# In the absence of Method#owner, this is the best we
76+
# can do to see if the method comes from Kernel.
77+
@actual.method(op).to_s.include?('(Kernel)')
78+
end
79+
end
80+
65
def eval_match(actual, operator, expected)
81
def eval_match(actual, operator, expected)
66
::RSpec::Matchers.last_matcher = self
82
::RSpec::Matchers.last_matcher = self
67
@operator, @expected = operator, expected
83
@operator, @expected = operator, expected

spec/rspec/matchers/match_array_spec.rb

Lines changed: 15 additions & 0 deletions
Original file line numberOriginal file lineDiff line numberDiff line change
@@ -113,6 +113,17 @@ def ==(other)
113
MESSAGE
113
MESSAGE
114
end
114
end
115

115

116+
context "when the array defines a `=~` method" do
117+
it 'delegates to that method rather than using the match_array matcher' do
118+
array = []
119+
def array.=~(other)
120+
other == :foo
121+
end
122+
123+
array.should =~ :foo
124+
expect { array.should =~ :bar }.to fail_with(/expected: :bar/)
125+
end
126+
end
116
end
127
end
117

128

118
describe "should_not =~ [:with, :multiple, :args]" do
129
describe "should_not =~ [:with, :multiple, :args]" do
@@ -135,4 +146,8 @@ def ==(other)
135
it "fails with a string and the expected error message is given" do
146
it "fails with a string and the expected error message is given" do
136
expect { "I like turtles".should match_array([1,2,3]) }.to fail_with(/expected an array/)
147
expect { "I like turtles".should match_array([1,2,3]) }.to fail_with(/expected an array/)
137
end
148
end
149+
150+
it 'fails with a clear message when given a hash using the `should =~` syntax' do
151+
expect { {}.should =~ {} }.to fail_with(/expected an array/)
152+
end
138
end
153
end

0 commit comments

Comments
 (0)