2010-01-08 2 views

Antwort

11

diese Änderung zu verhindern, dass völlig Bruch unabhängige Teile des Programms (wie andere Rubin Edelsteine ​​Sie verwenden), eine separate Klasse für unempfindliche Hash machen.

Nach dem Überschreiben der Zuordnung und Abruffunktionen ist es ziemlich Kuchen. Um einen vollständigen Ersatz für Hash zu erstellen, müssen Sie die Aliase und andere Funktionen (z. B. #has_key? Und #store), die für eine vollständige Implementierung benötigt werden, sorgfältiger handhaben. Das obige Muster kann leicht auf alle diese verwandten Methoden erweitert werden.

+3

Ich weiß, das war vor fast fünf Jahren, aber "Sie unsensible Clod" brachte mich zum Lachen. Bravo. –

+0

Warnung: Dies funktioniert auch nicht mit verschachtelten Hashes. – jrg

+0

@James Soweit mir bekannt ist, funktioniert es, wenn Sie jede Verschachtelungsebene als HashClod erstellen. Wenn Sie Standard-Hashes erstellen, wird es natürlich fehlschlagen. –

1

Gibt es einen Grund, nicht nur die Zeichenfolge # upcase zu verwenden?

h = Hash.new 

h["HELLO"] = 7 

puts h["hello".upcase] 

Wenn Sie zum Ändern von Hash bestehen, können Sie so etwas wie die folgenden

class Hash 
alias :oldIndexer :[] 

def [](val) 
    if val.respond_to? :upcase then oldIndexer(val.upcase) else oldIndexer(val) end 
end 
end 

tun, da es gebracht wurde, können Sie dies auch zu Fall machen Einstellung unempfindlich:

class Hash 
alias :oldSetter :[]= 
def []=(key, value) 
    if key.respond_to? :upcase then oldSetter(key.upcase, value) else oldSetter(key, value) end 
end 
end 

Ich empfehle auch dies mit module_eval.

+0

h [ "HELLO "] = 7? –

+0

Es wurde angenommen, dass das Setzen des Hashs mit Großbuchstaben erfolgt. Sie können das obenstehende einfach auf [] = – mletterle

1

Im Allgemeinen würde ich sagen, dass dies ein schlechter Plan ist; aber wenn ich Sie wäre, würde ich eine Unterklasse von Hash erstellen, die die [] Methode überschreibt:

class SpecialHash < Hash 
    def [](search) 
    # Do special code here 
    end 
end 
+1

erweitern. Um dieser Antwort ein wenig mehr hinzuzufügen: Überschreiben Sie # [] =, um #downcase auf den empfangenen Schlüsseln anzurufen, und dann in # [] können Sie self.get (search.get) aufrufen. downcase). –

+0

@Federico Builes - +1 - Danke für das Extra-Bit :-) –

1
require 'test/unit' 
class TestCaseIndifferentHash < Test::Unit::TestCase 
    def test_that_the_hash_matches_keys_case_indifferent 
    def (hsh = {}).[](key) super(key.upcase) end 

    hsh['HELLO'] = 7 
    assert_equal 7, hsh['hello'] 
    end 
end 
+1

Das wird natürlich explodieren, wenn Schlüssel nicht eine Methode namens upcase implementiert ... – mletterle

14

Wenn Sie wirklich Fall ignorieren wollen in beiden Richtungen und behandeln alle Hash-Methoden wie #has_key?, #fetch , #values_at, #delete, usw., müssen Sie etwas arbeiten, wenn Sie dies von Grund auf neu erstellen möchten, aber wenn Sie eine neue Klasse erstellen, die von der Klasse ActiveSupport::HashWithIndifferentAccess ausgeht, sollten Sie in der Lage sein, dies ziemlich einfach zu tun :

require "active_support/hash_with_indifferent_access" 

class CaseInsensitiveHash < HashWithIndifferentAccess 
    # This method shouldn't need an override, but my tests say otherwise. 
    def [](key) 
    super convert_key(key) 
    end 

    protected 

    def convert_key(key) 
    key.respond_to?(:downcase) ? key.downcase : key 
    end 
end 

Hier einige Beispiel Verhalten:

h = CaseInsensitiveHash.new 
h["HELLO"] = 7 
h.fetch("HELLO")    # => 7 
h.fetch("hello")    # => 7 
h["HELLO"]      # => 7 
h["hello"]      # => 7 
h.has_key?("hello")    # => true 
h.values_at("hello", "HELLO") # => [7, 7] 
h.delete("hello")    # => 7 
h["HELLO"]      # => nil 
+1

Ordentlich, wusste ich nicht darüber! –

+3

Warnung, dieser Ansatz funktioniert nicht mit verschachtelten Hashes, da Ihre Unterklasse nicht verwendet wird –

0

Während Ryan McGearys Ansatz gut funktioniert und mit ziemlicher Sicherheit der richtige Weg ist, gibt es einen Fehler, bei dem ich die Ursache nicht erkennen konnte, was die Methode Hash[] bricht.

Zum Beispiel:

r = CaseInsensitiveHash['ASDF', 1, 'QWER', 2] 
=> {"ASDF"=>1, "QWER"=>2} 
r['ASDF'] 
=> nil 
ap r 
{ 
    "ASDF" => nil, 
    "QWER" => nil 
} 
=> {"ASDF"=>1, "QWER"=>2} 

Obwohl ich nicht in der Lage, die zugrunde liegende Ursache des Fehlers zu finden oder zu beheben, die folgenden Hack tun lindern das Problem:

r = CaseInsensitiveHash.new(Hash['ASDF', 1, 'QWER', 2]) 
=> {"asdf"=>1, "qwer"=>2} 
r['ASDF'] 
=> 1 
ap r 
{ 
    "asdf" => 1, 
    "qwer" => 2 
} 
=> {"asdf"=>1, "qwer"=>2} 
+0

Als Follow-up, was ich wirklich brauchte, war ein Case-Ignoring/Case-Erhaltung Hash aber Subclassing HashWithIndifferentAccess endet Munging den Fall der ursprünglichen Schlüssel (ganz zu schweigen von der [] Methode Fehler oben), so gab ich auf und Monkeypatched stattdessen eine fetch_indifferently-Methode auf Hash. – rantler

Verwandte Themen