How to modify Hash to track key insertions?

M

m4dc4p

I am trying to figure out how I can modify the Hash object so that I am
notified each time a key is inserted in a Hash when it is constructed
using the syntax below:

a = { "x" => "1", "y" => "2" }

I've tried overriding []=, but that will only get called when the Hash
is constructed explicitly.

Here's a little bit of code showing what I've tried and the output I'd
like to see. Thanks for any help!

class Hash
alias :eek:ld_assignment :[]=
def []=(key, value)
puts "#{key} => #{value}"
old_assignment(key, value)
end
end

puts "Creating a"
a = { "x" => "1", "y" => "2" }
puts "Creating b"
b = Hash.new
b["1"] = "x"
b["2"] = "y"

# Expected output
# Creating a
# x => 1
# y => 2
# Creating b
# 1 => x
# 2 => y

# Actual output
# Creating a
# Creating b
# 1 => x
# 2 => y

p.s. I'm ultimately doing this to get to an OrderedHash. I looked at
Ara's code but the problem is I need to *replace* the functionality of
Hash - it's not an option for me to explicitly create an OrderedHash
object.
p.p.s. Is there a way to avoid the alias statement for []=? For some
reason, calling super in there would give a NoMethodError.
 
D

Daniel Schierbeck

m4dc4p said:
I am trying to figure out how I can modify the Hash object so that I am
notified each time a key is inserted in a Hash when it is constructed
using the syntax below:

a = { "x" => "1", "y" => "2" }

I've tried overriding []=, but that will only get called when the Hash
is constructed explicitly.

Here's a little bit of code showing what I've tried and the output I'd
like to see. Thanks for any help!

class Hash
alias :eek:ld_assignment :[]=
def []=(key, value)
puts "#{key} => #{value}"
old_assignment(key, value)
end
end

puts "Creating a"
a = { "x" => "1", "y" => "2" }
puts "Creating b"
b = Hash.new
b["1"] = "x"
b["2"] = "y"

# Expected output
# Creating a
# x => 1
# y => 2
# Creating b
# 1 => x
# 2 => y

# Actual output
# Creating a
# Creating b
# 1 => x
# 2 => y

p.s. I'm ultimately doing this to get to an OrderedHash. I looked at
Ara's code but the problem is I need to *replace* the functionality of
Hash - it's not an option for me to explicitly create an OrderedHash
object.
p.p.s. Is there a way to avoid the alias statement for []=? For some
reason, calling super in there would give a NoMethodError.

Personally I'd like to see (private?) methods Hash#get and Hash#set that
should be used internally for getting and setting values. That way,
you'd only have to override one method when wanting to change Hash's
behaviour.

class StrHash
def set(key, value)
raise TypeError unless value.respond_to? :to_str
super(key, value.to_str)
end
end

In your case:

class Hash
alias_method :__set__, :set

def set(key, value)
puts "#{key} => #{value}"
__set__(key, value)
end
end


Cheers,
Daniel
 
R

Robert Klemme

m4dc4p said:
I am trying to figure out how I can modify the Hash object so that I
am notified each time a key is inserted in a Hash when it is
constructed using the syntax below:

a = { "x" => "1", "y" => "2" }

I've tried overriding []=, but that will only get called when the Hash
is constructed explicitly.

Here's a little bit of code showing what I've tried and the output I'd
like to see. Thanks for any help!

p.s. I'm ultimately doing this to get to an OrderedHash. I looked at
Ara's code but the problem is I need to *replace* the functionality of
Hash - it's not an option for me to explicitly create an OrderedHash
object.

It's usually difficult to fiddle with built in classes as they employ some
optimizations. What's the problem with replacing "h = {1=>2, 3=>4}" by "h
= OrdererdHash.create(1=>2, 3=>4)"? Note that if you manipulate the hash
constructor {} you'll affect *all* hashes created in your app and libs -
something which might produce side effects (even if it's "only"
performance) you don't want.

My 0.02 EUR: stick with the explicit approach and drop manipulating built
in constructs.

Kind regards

robert
 

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

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top