我有两个包含数组的哈希。在我的例子中,数组元素的顺序并不重要。有没有一种简单的方法来匹配RSpec2中的这些哈希值?
{ a: [1, 2] }.should == { a: [2, 1] } # how to make it pass?
P.S。
有一个数组匹配器,忽略了顺序。
[1, 2].should =~ [2, 1] # Is there a similar matcher for hashes?
解
解决方案对我有用。最初由tokland建议,有修复。
RSpec::Matchers.define :match_hash do |expected|
match do |actual|
matches_hash?(expected, actual)
end
end
def matches_hash?(expected, actual)
matches_array?(expected.keys, actual.keys) &&
actual.all? { |k, xs| matches_array?(expected[k], xs) }
end
def matches_array?(expected, actual)
return expected == actual unless expected.is_a?(Array) && actual.is_a?(Array)
RSpec::Matchers::BuiltIn::MatchArray.new(expected).matches? actual
end
使用匹配器:
{a: [1, 2]}.should match_hash({a: [2, 1]})
答案 0 :(得分:2)
我会写一个自定义匹配器:
RSpec::Matchers.define :have_equal_sets_as_values do |expected|
match do |actual|
same_elements?(actual.keys, expected.keys) &&
actual.all? { |k, xs| same_elements?(xs, expected[k]) }
end
def same_elements?(xs, ys)
RSpec::Matchers::BuiltIn::MatchArray.new(xs).matches?(ys)
end
end
describe "some test" do
it { {a: [1, 2]}.should have_equal_sets_as_values({a: [2, 1]}) }
end
# 1 example, 0 failures
答案 1 :(得分:2)
[Rspec 3]
我最终对散列值(数组)进行了排序,如下所示:
hash1.map! {|key, value| [key, value.sort]}.to_h
hash2.map! {|key, value| [key, value.sort]}.to_h
expect(hash1).to match a_hash_including(hash2)
我确信它虽然相当大,却不会表现得很好......
答案 2 :(得分:1)
== on Hashes不关心订单,{1 => 2,3 => 4} == {3 => 4,1>> 2}。但是,它将检查值的相等性,当然[2,1]不等于[1,2]。我不认为〜=是递归的:[[1,2],[3,4]]可能与[[4,3],[2,1]]不匹配。如果是这样,你可以写两个支票,一个用于键,一个用于值。这看起来像这样:
hash1.keys.should =~ hash2.keys
hash1.values.should =~ hash2.values
但正如我所说,这可能行不通。因此,您可能希望扩展Hash类以包含自定义方法,例如:
class Hash
def match_with_array_values?(other)
return false unless self.length == other.length
return false unless self.keys - other.keys == []
return false unless self.values.flatten-other.values.flatten == []
return true
end
end
答案 3 :(得分:1)
如果订单不重要,您可以使用集合而不是数组:
require 'set'
Set.new([1,2]) == Set.new([2,1])
=> true