From: George Ogata Date: 2006-12-16T11:18:11+09:00 Subject: Re: method_missing question On 12/15/06, Peter Szinek wrote: > Now, the problem is I would like to write the above example like this: > > book do > title > price > end > > i.e. without the Ps. > P's sole purpose is to define method_missing - I did not want to > override Object.method_missing since I would like to release this code > to the wild and I think it could collide with my potential future user's > Object.method_missing. > > I have then experimented with modules (mimicking namespace > functionality) but that still did not provide the possibility to omit > the class name. I would need something equivalent to include - you can > omit the module name if you include the module - but with classes. > > I have no idea if this is possible in Ruby, but is there something like > run this code in a different context or something? Hi Peter, This sort of thing probably already exists somewhere, but I don't know what it's called. (The 'script' that Michael mentioned looks like something else to me... ?) So anyway, here's a starting point. The trick is to use instance_eval to change the value of 'self' within the block. class Node # Rename all existing methods to start with '__', so they're not # likely to collide with your attribute names. We'll leave some # methods alone, since they're necessary for some basic operations. methods = (instance_methods + private_instance_methods) methods = methods - %w'__send__ __id__ initialize inspect' methods.each{|m| alias_method("__#{m}", m); undef_method(m)} def method_missing(*args, &block) key, val = *args if block args.length == 1 or raise ArgumentError, "value and block given" node = Node.new __instance_variable_set("@#{key}", node) node.__instance_eval(&block) return node else args.length <= 2 or raise ArgumentError, "too many arguments" if args.length > 1 __instance_variable_set("@#{key}", val) end return __instance_variable_get("@#{key}") end end end ### Usage node = Node.new node.root do a 1 b 2 c do d 3 e 4 end end p node.root.c.d #=> 3 p node.root.c #=> # p node #=> #>