benjohn / fysh.org wrote:
> I also like it because I don't think that there's anything especially
> fundamental about classes. With predicate classes, all you're really
> saying is that "if I've got something that can do x and y, then I know
> that I can equally validly think of it as something that can do z".

The concept really piqued my interest, and since ruby gives us such nice
metaprogramming abilities, why not do it?


module DuckTyping
   @@quacks = Hash.new{ |h,k| h[k] = {} }

   def ducktype(*reqs, &block)
     o = Object
     before = o.methods
     o.class_eval(&block)
     after = o.methods

     for methodname in (after - before)
       @@quacks[methodname.to_sym][reqs] = o.instance_method(methodname.to_sym)
       o.send(:remove_method, methodname.to_sym)
     end
   end

   def ducktype_method(methodname)
     @@quacks[methodname.to_sym].each do |reqs, m|
       if reqs.all?{ |r| self.respond_to?(r) }
         return m
       end
     end
     return nil
   end

   def method_missing(methodname, *args, &block)
     if m = ducktype_method(methodname)
       m.bind(self).call(*args, &block)
     else
       super
     end
   end
end
Object.module_eval{ include DuckTyping }


ducktype :quack do
   def quack_loudly
     quack.upcase
   end
end


class Duck
   def quack
     "quack!"
   end
end

class Dog
   def bark
     "woof!"
   end
end

Duck.new.quack_loudly #=> "QUACK!"
Dog.new.quack_loudly  #=> NoMethodError


nifty?