2012-07-06 63 views
3

我有兩個哈希包含數組。在我的情況下,數組元素的順序並不重要。有沒有一種簡單的方法來匹配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? 

SOLUTION

該解決方案爲我工作。最初由托克蘭建議,修復。

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]}) 

回答

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

感謝您的想法。 '=〜'在這裏不起作用,需要調用'RSpec :: Matchers :: BuiltIn :: MatchArray.new(expected).matches? actual'。我在上面的問題中添加了修復程序。 – Evgenii 2012-07-07 06:18:02

+0

@Evgeny:更新你的(好)建議。 – tokland 2012-07-07 14:56:13

+0

得到錯誤'未初始化的常量RSpec :: Matchers :: BuiltIn :: MatchArray'。看起來這個匹配器在最近的版本中已經被棄用了?我在Rails 5中使用了'rspec-core' 3.6.0。爲了解決這個問題,我只是將'same_elements?'方法簡化爲'xs.sort == xy.sort' – user2490003 2017-09-22 13:01:40

1

==於哈希不關心順序,{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 

但正如我所說,這可能無法正常工作。所以可能的話,你可能要延長哈希類,包括自定義的方法,是這樣的:

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 
+0

我知道有些人喜歡這種模式,但讓我注意的是'返回false,除非;除非b返回false;返回true'可以寫成一個簡單的表達式'a && b'。 – tokland 2012-07-06 19:34:42

+0

@tokland在a == b &&(c - d)== e &&(e - f == g)的情況下,您正在創建複合複雜表達式。在這種情況下,我去了可讀性,而不是簡潔。 – philosodad 2012-07-06 22:03:32

1

您可以使用組,而不是陣列如果順序並不重要:

require 'set' 
Set.new([1,2]) == Set.new([2,1]) 
=> true 
+1

請注意,集合也會刪除重複項 – aromero 2016-07-18 23:20:12

1

[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) 

我敢肯定它不會進行大具有相當大陣雖然...