From: Robert Klemme Date: 2010-02-04T17:25:06+09:00 Subject: Re: hooking subscript operations in a hash On 04.02.2010 04:11, Ralph Shnelvar wrote: > RD> On Wed, Feb 3, 2010 at 9:38 PM, Ralph Shnelvar wrote: >>> In order to help debug something, I'd like to hook the hash subscript operation. > >>> I've tried this (and several variants) in irb ... but it doesn't do what I want it to. > > >>> module RalphMod >>> def []=(index, value) >>> p index >>> p value >>> if index == 'PATH_INFO' and value == '/undefined' >>> puts 'found it!' >>> end >>> super index, value >>> end >>> end > >>> class Hash >>> extend RalphMod >>> end > >>> env = {} >>> env['X'] = 'Y' >>> env['PATH_INFO'] = '/undefined' > > >>> The values are not displayed and 'found it!' is also not displayed. > > RD> A few problems with this code. > > RD> First > > RD> class Hash > RD> extend RalphMod > RD> end > > RD> makes the method in RalphMod a method of the Hash class object not > RD> hash instances. > > RD> The way to do that would be > > RD> class Hash > RD> include RalphMod > RD> end > > RD> but this wouldn't work either because methods in included modules come > RD> after methods defined in the class, so you'll still invoke the > RD> original []= method. > > RD> What you want is something like this: > > RD> module RalphMod > RD> def []=(index, value) > RD> p index > RD> p value > RD> if index == 'PATH_INFO' and value == '/undefined' > RD> puts 'found it!' > RD> end > RD> super index, value > RD> end > RD> end > RD> env = {} > RD> env.extend RalphMod > RD> env['X'] = 'Y' > RD> env['PATH_INFO'] = '/undefined' > > RD> This effectively inserts your module between the instance of Hash > RD> referenced by the variable env and it's class. > > Yeah ... tried that ... but apparently env is going in and out of scope. Well, that's not a problem. As long as you retain a reference to the object somewhere it will stay there. > Is there any way to do it for all hash subscript operations? You have been shown solutions but frankly I would not do it. This might have totally unwanted side effects on other code which uses Hash as well. Better not modify core classes and instead either inherit them or - even better - encapsulate them in another class. This has the added advantage that nobody can modify the Hash in unwanted ways and you are exposing only that part of Hash's interface that you intend to. class RalphHash def initialize @h = {} end def []=(k,v) if k == 'PATH_INFO' and v == '/undefined' puts 'found it!' end @h[k]=v end def [](k) @h[k] end end You can also use delegate for this. http://ruby-doc.org/stdlib/libdoc/delegate/rdoc/index.html Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/