Extending Hast class with custom [] []= methods

  • Thread starter Iñaki Baz Castillo
  • Start date
I

Iñaki Baz Castillo

Hi, I'd like to extend Hash class [] and []=3D methods in order to find a k=
ey=20
with case insensitive. This is:


=2D The actual Hash [] behaviour:

{"a"=3D>1,"b"=3D>2}["a"]
=3D> 1
{"a"=3D>1,"b"=3D>2}["A"]
=3D> nil

=2D The beaviour I look for:

{"a"=3D>1,"b"=3D>2}["a"]
=3D> 1
{"a"=3D>1,"b"=3D>2}["A"]
=3D> 1


But I can't modify [] method since it's Ruby core written in C:

=2D---------------------
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;
}
=2D----------------------


How could I do it?


=2D-=20
I=C3=B1aki Baz Castillo
 
I

Iñaki Baz Castillo

El Mi=C3=A9rcoles, 23 de Abril de 2008, David A. Black escribi=C3=B3:
A better way is to
write a module, and then use it selectively for the hashes that need
it:

=C2=A0 =C2=A0module CaseInsensitiveLookup
=C2=A0 =C2=A0 =C2=A0def [](key)

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=20
should I use to access to keys and values.

=2D-=20
I=C3=B1aki Baz Castillo
 
D

Daniel Finnie

Hi,

You can use super and/or alias:

class MyHash < Hash
def [] key
super(key.downcase)
end
end

Dan

El Mi=E9rcoles, 23 de Abril de 2008, David A. Black escribi=F3:
A better way is to
write a module, and then use it selectively for the hashes that need
it:

module CaseInsensitiveLookup
def [](key)

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 attribute= s
should I use to access to keys and values.
 
I

Iñaki Baz Castillo

El Mi=E9rcoles, 23 de Abril de 2008, Daniel Finnie escribi=F3:
Hi,

You can use super and/or alias:

class MyHash < Hash
=A0 def [] key
=A0 =A0 super(key.downcase)
=A0 end
end

Dan

opss, yes, it was no so difficult XDD
Thanks a lot.

=2D-=20
I=F1aki Baz Castillo
 
C

Chris Shea

Hi,

You can use super and/or alias:

class MyHash < Hash
def [] key
super(key.downcase)
end
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:

###
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
 
C

Chris Shea

You can use super and/or alias:
class MyHash < Hash
def [] key
super(key.downcase)
end
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:

###
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 just use Rubinius: http://pastie.textmate.org/185232

!!!
Chris
 
R

Robert Klemme

2008/4/23 said:
Or delegation

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

h = CiHash.new
h["FOO"]=1
h[:not_a_string]=2 # works, too
puts h["foo"]
puts h[:not_a_string]

Cheers

robert
 
I

Iñaki Baz Castillo

MjAwOC80LzIzLCBDaHJpcyBTaGVhIDxjbXNoZWFAZ21haWwuY29tPjoKCj4gQnV0IGhlIGFza2lu
ZyBmb3IgY2FzZS1pbnNlbnNpdGl2aXR5LiAgSWYgYSBrZXkgaXMgY3JlYXRlZCB3aXRoCj4gIHVw
cGVyY2FzZSBsZXR0ZXJzLCB5b3UncmUgb3V0IG9mIGx1Y2suICBBbmQgaWYgeW91IGxvb2sgZm9y
IGEgdmFsdWUKPiAgZm9yIGEgbm9uLXN0cmluZyBrZXksIHRoYXQncyBubyBnb29kIGVpdGhlcjoK
ClllYWgsIGZpbmFsbHkgSSd2ZSBkb25lOgoKCQljbGFzcyBJbnNlbnNpdGl2ZUhhc2ggPCBIYXNo
CgkJCWRlZiBbXShrZXkpCgkJCQlmaW5kIHt8aHwgaFswXSA9fiAvXiN7a2V5fSQvaSB9WzFdCgkJ
CWVuZAoJCWVuZAoKCkl0IHdvcmtzLiA6KQoKLS0gCknDsWFraSBCYXogQ2FzdGlsbG8KPGliY0Bh
bGlheC5uZXQ+Cg==
 
R

Robert Klemme

2008/4/23 said:
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] =3D~ /^#{key}$/i }[1]
end
end


It works. :)

... and is awfully inefficient.

Here's another way, which is more efficient for large hashes

class CiHash2 < DelegateClass(Hash)
CiString =3D 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 =3D=3D eql?
def inspect; string.inspect; end
end

def initialize
super({})
end

def []=3D(k,v)
k =3D CiString.new(k) if String =3D=3D=3D k
__getobj__[k] =3D v
end

def [](k)
k =3D CiString.new(k) if String =3D=3D=3D k
__getobj__[k]
end

# add other lookup and mutation methods
end

h =3D CiHash2.new
h["FOO"]=3D3
h["Foo"]=3D4
puts h["foo"]
puts h["fOo"]
p h

Cheers

robert

--=20
use.inject do |as, often| as.you_can - without end
 
I

Iñaki Baz Castillo

MjAwOC80LzIzLCBSb2JlcnQgS2xlbW1lIDxzaG9ydGN1dHRlckBnb29nbGVtYWlsLmNvbT46Cj4g
Li4uIGFuZCBpcyBhd2Z1bGx5IGluZWZmaWNpZW50Lgo+Cj4gIEhlcmUncyBhbm90aGVyIHdheSwg
d2hpY2ggaXMgbW9yZSBlZmZpY2llbnQgZm9yIGxhcmdlIGhhc2hlcwoKT2gsIHRoYW5rcywgSSds
bCBzcGVuZCBzb21lIHRpbWUgaW52ZXN0aWdhdGluZyB3aGF0IHlvdXIgc29sdXRpb24gKG9yCmhv
dykgZG9lcyA6KQpUaGFua3MuCgotLSAKScOxYWtpIEJheiBDYXN0aWxsbwo8aWJjQGFsaWF4Lm5l
dD4K
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top