Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!news.albasani.net!news.musoftware.de!wum.musoftware.de!de-l.enfer-du-nord.net!feeder2.enfer-du-nord.net!talisker.lacave.net!lacave.net!not-for-mail From: 7stud -- Newsgroups: comp.lang.ruby Subject: Re: looking for an "inversion" pattern Date: Sat, 16 Apr 2011 13:20:50 -0500 Organization: Service de news de lacave.net Lines: 135 Message-ID: References: NNTP-Posting-Host: bristol.highgroove.com Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Trace: talisker.lacave.net 1302978601 87918 65.111.164.187 (16 Apr 2011 18:30:01 GMT) X-Complaints-To: abuse@lacave.net NNTP-Posting-Date: Sat, 16 Apr 2011 18:30:01 +0000 (UTC) In-Reply-To: X-Received-From: This message has been automatically forwarded from the ruby-talk mailing list by a gateway at comp.lang.ruby. If it is SPAM, it did not originate at comp.lang.ruby. Please report the original sender, and not us. Thanks! For more details about this gateway, please visit: http://blog.grayproductions.net/categories/the_gateway X-Mail-Count: 381709 X-Ml-Name: ruby-talk X-Rubymirror: Yes X-Ruby-Talk: Xref: x330-a1.tempe.blueboxinc.net comp.lang.ruby:3018 Kevin Mahler wrote in post #992945: > Fearless Fool wrote in post #992929: >> I'd like to create a method +foo+ that transforms: >> >> my_obj.foo.some_method(*args) >> >> to >> >> MyClass.some_method(my_obj, *args) > > class MyClass > def self.some_method(obj, *args) > puts "MyClass.some_method:" > puts "obj: #{obj.inspect}" > puts "args: #{args.inspect}" > end > end > > def define_foo(obj, clazz, method) > obj.singleton_class.class_eval do > define_method :foo do > Class.new do > define_method method do |*args| > clazz.send(method, obj, *args) > end > end.new > end > end > end > > my_obj = "my_obj thing" > args = [1,2,3] > define_foo(my_obj, MyClass, :some_method) > my_obj.foo.some_method(*args) > > # => > # MyClass.some_method: > # obj: "my_obj thing" > # args: [1, 2, 3] > > Returning facade or proxy objects like this can be an elegant solution > to certain problems. It's rather high on the abstraction ladder, though, > and without knowing the context I would wonder if more direct solutions > are possible. I don't know what's conceptually easier to understand, but in ruby there is no limit to how high you can stack singleton methods, e.g.: obj.foo obj.foo.some_method If obj.foo() returns obj's singleton class, then some_method() is being called as a class method of the singleton class. That means some_method is a method inside the singleton class's singleton class: obj's class ^ | | singleton2: some_method() ^ | | singleton1: foo() -> returns singleton1 ^ | | obj obj.foo.some_method And you can add as many singleton classes to the method lookup path as you want. For instance, if you have this call: obj.foo.some_method.do_stuff and obj.foo.some_method() returns singleton2, then do_stuff() is being called as a class method of singleton2, i.e. do_stuff() is a method in a parent class, singleton3, above singleton2. So in the original example at the top of the post, if the creating-a-new-anonymous-class-with-a-method-named-some_method-and-returning-an-instance-of-that-class is too hard to understand, you could do this: class MyClass def self.some_method(obj, *args) puts "MyClass.some_method:" puts "obj: #{obj.inspect}" puts "args: #{args.inspect}" end end def define_foo(obj, clazz, method) obj.singleton_class.class_eval do singleton = self define_method :foo do #Class.new do #define_method method do |*args| #clazz.send(method, obj, *args) #end #end.new #In here, self is equal to the obj that #will eventually call foo()--not obj.singleton_class. #Hence, the need to do singleton = self above. singleton.singleton_class.class_eval do define_method method do |*args| clazz.send(method, obj, *args) end end singleton #return the singleton class end end end my_obj = "my_obj thing" args = [1,2,3] define_foo(my_obj, MyClass, :some_method) my_obj.foo.some_method(*args) --output:-- MyClass.some_method: obj: "my_obj thing" args: [1, 2, 3] -- Posted via http://www.ruby-forum.com/.