- The actual Hash [] behaviour:
{"a"=>1,"b"=>2}["a"]
=> 1
{"a"=>1,"b"=>2}["A"]
=> nil
- The beaviour I look for:
{"a"=>1,"b"=>2}["a"]
=> 1
{"a"=>1,"b"=>2}["A"]
=> 1
But I can't modify [] method since it's Ruby core written in C:
----------------------
VALUE
rb_hash_aref(hash, key)
VALUE hash, key;
{
VALUE val;
if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
return rb_funcall(hash, id_default, 1, key);
}
return val;
}
-----------------------
How could I do it?
--
Iñaki Baz Castillo
Yes, but my question is what to do into that:
def [](key)" method
...
end
since the original code is written in C and I don't know which attributes
should I use to access to keys and values.
--
Iñaki Baz Castillo
You can use super and/or alias:
class MyHash < Hash
def [] key
super(key.downcase)
end
end
Dan
opss, yes, it was no so difficult XDD
Thanks a lot.
--
Iñaki Baz Castillo
But he asking for case-insensitivity. If a key is created with
uppercase letters, you're out of luck. And if you look for a value
for a non-string key, that's no good either:
###
class MyHash < Hash
def [](key)
super(key.downcase)
end
end
h = MyHash.new
h['A'] = 'never findable'
h['A'] # => nil
h[1] # ~> undefined method `downcase' for 1:Fixnum (NoMethodError)
###
You could override []= as well (and with more care), but I wonder if a
different class with a Hash instance variable with mediated access
would be a better route.
Chris
Or delegation
h = CiHash.new
h["FOO"]=1
h[:not_a_string]=2 # works, too
puts h["foo"]
puts h[:not_a_string]
Cheers
robert
--
use.inject do |as, often| as.you_can - without end
Copy and paste error: this was missing:
require 'delegate'
class CiHash < DelegateClass(Hash)
def initialize
super({})
end
def []=(k,v)
__getobj__[(k.downcase rescue k)] = v
end
def [](k)
__getobj__[(k.downcase rescue k)]
end
# add other lookup and mutation methods
end
> But he asking for case-insensitivity. If a key is created with
> uppercase letters, you're out of luck. And if you look for a value
> for a non-string key, that's no good either:
Yeah, finally I've done:
class InsensitiveHash < Hash
def [](key)
find {|h| h[0] =~ /^#{key}$/i }[1]
end
end
It works. :)
--
Iñaki Baz Castillo
<i...@aliax.net>
.. and is awfully inefficient.
Here's another way, which is more efficient for large hashes
class CiHash2 < DelegateClass(Hash)
CiString = Struct.new :string do
def to_s; string.downcase end
def hash; string.downcase.hash end
def eql?(s) string.downcase.eql? s.string.downcase end
alias == eql?
def inspect; string.inspect; end
end
def initialize
super({})
end
def []=(k,v)
k = CiString.new(k) if String === k
__getobj__[k] = v
end
def [](k)
k = CiString.new(k) if String === k
__getobj__[k]
end
# add other lookup and mutation methods
end
h = CiHash2.new
h["FOO"]=3
h["Foo"]=4
puts h["foo"]
puts h["fOo"]
p h
Oh, thanks, I'll spend some time investigating what your solution (or
how) does :)
Thanks.