В Ruby я хочу сохранить некоторый материал в Хеше, но я не хочу, чтобы он был чувствителен к регистру. Так, например:
h = Hash.new
h["HELLO"] = 7
puts h["hello"]
Это должно произвести 7, даже при том, что случай отличается. Я могу просто переопределить метод равенства хеша или чего-то подобного?
Спасибо.
] Чтобы это изменение не нарушало полностью независимые части вашей программы (такие как другие рубиновые драгоценные камни, которые вы используете), сделайте отдельный класс для вашего нечувствительного хэша.[
] [class HashClod < Hash
def [](key)
super _insensitive(key)
end
def []=(key, value)
super _insensitive(key), value
end
# Keeping it DRY.
protected
def _insensitive(key)
key.respond_to?(:upcase) ? key.upcase : key
end
end
you_insensitive = HashClod.new
you_insensitive['clod'] = 1
puts you_insensitive['cLoD'] # => 1
you_insensitive['CLod'] = 5
puts you_insensitive['clod'] # => 5
]
[]После переопределения функций присваивания и извлечения, это практически пирог. Создание полной замены Hash потребует более тщательной работы с псевдонимами и другими функциями (например, #has_key? и #store), необходимыми для полной реализации. Вышеприведенный паттерн можно легко распространить на все эти связанные методы.[
].]По какой причине вы не просто используете string#upcase?[
] [h = Hash.new
h["HELLO"] = 7
puts h["hello".upcase]
]
[]Если вы настаиваете на модификации хэша, вы можете сделать что-то вроде следующего[
] [class Hash
alias :oldIndexer :[]
def [](val)
if val.respond_to? :upcase then oldIndexer(val.upcase) else oldIndexer(val) end
end
end
]
[]Так как он был поднят, вы также можете сделать это, чтобы сделать настройку нечувствительной к регистру: [
] [class Hash
alias :oldSetter :[]=
def []=(key, value)
if key.respond_to? :upcase then oldSetter(key.upcase, value) else oldSetter(key, value) end
end
end
]
[]Я также рекомендую сделать это, используя модуль_eval.[
]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
]. ] Если вы действительно хотите игнорировать регистр в обоих направлениях и обрабатывать все методы Хэша, такие как [] #has_key?[
], [] #fetch[
], [] #values_at[
], [] #delete[
] и т.д., и т.п. Вам нужно будет немного поработать, если вы хотите построить это с нуля, но если вы создадите новый класс, который расширяет класс []ActiveSupport::HashWithIndifferentAccess[], вы сможете сделать это довольно легко, как например:[
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
]
[]Вот пример поведения:[
] [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
] ] В общем, я бы сказал, что это плохой план, но на вашем месте я бы создал подкласс гашиша, который перекрывает [][][
] метод:[
class SpecialHash < Hash
def [](search)
# Do special code here
end
end
]