From: David Alan Black Date: 2001-08-20T09:11:43+09:00 Subject: [ruby-talk:20000] Re: pose_as Hello -- On Mon, 20 Aug 2001 jweirich@one.net wrote: > I was reading someone commenting about Objective C yesterday. They > said that Objective C was able to do > > [NewClass poseAs: [OldClass class]]; > > (note Smalltalk like syntax). Thereafter any time [OldClass new] was > executed, an object of class NewClass would be created instead. > > This sounded like a useful thing to have when doing testing > (e.g. replacing the construction of a real object with a testable Mock > version), so I wondered if the same could be done in Ruby. Here's the > result ... Interesting idea, though I haven't thought of anywhere I'd use it. Do you have ideas or examples? > ---------------------------------------------------------------------- > class Class > def pose_as(other_class) > if other_class.methods.include?("_unposed_new_") > fail "Another class is already posing as #{other_class.name}" > end > other_class.class_eval <<-EOS > class << self > alias _unposed_new_ new > @@use_original = false > def new(*args) > if @@use_original > _unposed_new_(*args) > else > @@use_original = true > result = #{name}.new(*args) > @@use_original = false > result > end > end > end > EOS > end I don't get the @@use_original logic. When would the first (true) part of the 'if' get executed? The only thing that ever happens when @@use_original is true is for the poser's #new to get called. And that #new, presumably, doesn't know or care about @@use_original. > def unpose > if not self.methods.include?("_unposed_new_") > fail "No class is posing as #{self.name}" > end > self.class_eval <<-EOS > class << self > alias new _unposed_new_ > remove_method :_unposed_new_ > end > EOS > end > end I think you could economize on "<<" operators :-) though I'm not 100% sure this code does exactly what yours does... see what you think: class Class def pose_as(other_class) other_class.instance_eval <<-EOS if methods.include?("_unposed_new_") fail "Another class is already posing as #{name}" end alias _unposed_new_ new def new(*args,&block) #{name}.new(*args,&block) end EOS end def unpose if not methods.include?("_unposed_new_") fail "No class is posing as #{name}" end class << self alias new _unposed_new_ remove_method :_unposed_new_ end end end (And I wonder whether Ruby has some incredible, three-line equivalent up its sleeve....) > I'm not suggesting this as a standard part of Ruby, but I do think it > is a tribute to the flexibility of the language to allow expressing > this kind of stuff within the language. Of course, that great flexibility itself *is* a standard part of Ruby :-) David -- David Alan Black home: dblack@candle.superlink.net work: blackdav@shu.edu Web: http://pirate.shu.edu/~blackdav