From: Robert Klemme Date: 2005-06-07T16:55:33+09:00 Subject: Re: making a duck Eric Mahurin wrote: > --- Robert Klemme wrote: > >> Eric Mahurin wrote: >>> Regarding duck-typing... Is there an easy way make a >> "duck"? >>> i.e. an object that responds to enough methods to be an >>> acceptable argument to a certain methods. For example, if >> I >>> have a method that takes aString and uses the #size and >> #[i] >>> methods, I could pass it something that looked just enough >> like >>> a String to work: >>> >>> alphabet = Object.duck(:[],proc{|i|?a+i},:size,proc{26}) >> >> Why aren't you satisfied with >> >> class Alpha >> def [](i) ?a+i end >> def size() 26 end >> end >> alphabet = Alpha.new >> >> or >> >> alphabet = Object.new >> def alphabet.[](i) ?a+i end >> def alphabet.size() 26 end >> >> You can even squeeze that on one line if you feel the need >> for it. I >> mean, you don't generate those methods dynamically or get >> them from >> somewhere else so why not just use the std approach? > > For the example I gave above, I think you are correct. The > examples I gave in response to David Black are probably better > ones. With those, a simple "def" won't cut it. You need > define_method. But, using define_method is cumbersome from an > object because you first need to make it have a singleton > class, then use "send" to access it from that class because it > it a private method. Another solution to the problem of > "making a duck" would be to have a > Object#define_singleton_method: > > class Object > def define_singleton_method(name,&block) > klass = (class << self;self;end) > klass.send(:define_method,name,&block) > self > end > end Btw, you can also use class eval: class Object def define_singleton_method(name,&block) klass = (class << self;self;end).class_eval do define_method(name,&block) end self end end and also o=Object.new class < Then, for example, you could do this to make a set be useful > for a method that uses == for comparison: > > seteq = Object.new. > define_singleton_method(:==,&set.method(:include?)) This does not work. You cannot transfer a method from one class to another: 09:14:01 [ruby]: cat define.rb class Foo def test() bar() end def bar() "FOO::BAR" end end class Bar def bar() "BAR::BAR" end end bar = Bar.new bar_kl = (class< I'm not sure why this isn't in Object right now. It seems like > the rest of the *singleton_method* methods are there. Probably because it doesn't work - at least not completely the way you like to have it. Btw, and if you're borrowing implementations from other classes then you can directly use an instance of that class... Kind regards robert