How to modify Hash to track key insertions?

Discussion in 'Ruby' started by m4dc4p, Nov 23, 2005.

  1. m4dc4p

    m4dc4p Guest

    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.
    m4dc4p, Nov 23, 2005
    #1
    1. Advertising

  2. m4dc4p wrote:
    > 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
    Daniel Schierbeck, Nov 23, 2005
    #2
    1. Advertising

  3. m4dc4p wrote:
    > 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!


    <snip/>

    > 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
    Robert Klemme, Nov 24, 2005
    #3
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dmitri Shvetsov

    Inheritanse, insertions and not only that

    Dmitri Shvetsov, Apr 7, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    348
    Michael Mayer [C# MVP]
    Apr 10, 2004
  2. Marcio DeBarros
    Replies:
    0
    Views:
    318
    Marcio DeBarros
    Oct 9, 2003
  3. Replies:
    7
    Views:
    382
  4. rp
    Replies:
    1
    Views:
    495
    red floyd
    Nov 10, 2011
  5. Une bévue
    Replies:
    5
    Views:
    141
    Une bévue
    Aug 10, 2006
Loading...

Share This Page