From: Robert Klemme Date: 2005-02-18T17:39:47+09:00 Subject: Re: adding a dynamic method handler? (long post) "Mark Hubbart" schrieb im Newsbeitrag news:de63abca050217095240cde47c@mail.gmail.com... > On Thu, 17 Feb 2005 17:19:54 +0900, Robert Klemme wrote: > > > > "Mark Hubbart" schrieb im Newsbeitrag > > news:de63abca050216125273686a45@mail.gmail.com... > > > On Wed, 16 Feb 2005 18:19:50 +0900, Robert Klemme > > wrote: > > > > > > > > "Mark Hubbart" schrieb im Newsbeitrag > > > > news:de63abca0502152303763354f7@mail.gmail.com... > > > > > Hi, > > > > > > > > > > I've been using method_missing overly much in my code lately, and > > it's > > > > > prompted me to think a lot about it's limitations. > > > > > > > > > > > > > > > > > So, any thoughts? > > > > > > > > I'm wondering in which situation you need this. Although I understand > > the > > > > benefits of your approach I don't see the use case for this. > > > > > > Basically this is for any time that you want the code re-use and ease > > > of implementation afforded by method_missing, but the benefits of > > > still having the methods behave mostly as if they were actually > > > defined, rather than handled dynamically. This is useful for quickly > > > defining wrapper objects, or objects that delegate to multiple other > > > objects. > > > > > > The idea is that this would be a way of dynamically creating methods > > > for an object, without resorting to relatively permanent methods like > > > "class << self; define_method(:foo){...}; end". > > > > I'm sorry if I am being stubborn (or dump), but this is still pretty much > > abstract. I'd like to know which concrete use case made this behavior > > necessary. > > Maybe stubborn, but that's not always a bad thing. There are many > things I'm very glad Matz is stubborn about :) > > I don't think I ever implied that this behavior was *necessary*. You > can implement similar functionality with what is currently available. > It's just a pain in the neck to do it; You either have to break down > and def a bunch of methods, or override respond_to? and method in your > class. And sometimes neither of those is the *best* solution. > > I did give a specific use case where it would be very useful, though. > When wrapping a class, or doing runtime refactoring (like what > pathname does, which is, for the most part, a refactored wrapper for > File and Dir), this could be very handy. Like method_missing, it would > allow you to handle large amounts of similar methods at once, letting > you condense code; while still getting almost all the benefits of > actually defining each individual method. > > class DirectoryItem > def initialize(path) > @path = path > end > [...] > def dynamic_method(name) > @@file_methods = (File.methods - Object.methods).map{|s|s.to_sym} > @@dir_methods = (Dir.methods - Object.methods).map{|s|s.to_sym} > if @@file_methods.include? name > if File.method(name).arity == 1 > lambda{ File.send(name, @path) } > elsif name == :truncate > lambda{|len| File.send(name, @path, len) } > elsif File.method(name).arity == 2 > lambda{|path| File.send(name, @path, path) } > end > elsif @@dir_methods.include? name > # handle Dir methods here > end > end > end > > The equivalent portion of code using 'def' would be much, much longer, > and very repetitive. The equivalent code using method_missing would be > about the same length, but if anyone tried to check it's capabilities, > it would seem to almost be an empty object. Although I agree to that - wouldn't it be more efficient to define all forwarding methods in DirectoryItem class once and for all? That way you get these benefits: - faster as methods can be invoked directly and no lambdas have to be created - reduced mem usage as not every instance has its own copy of the lambdas Drawback is of course that methods added to File and Dir later don't get invoked - but it's unlikely in this case I'd say. Also, a suggestion for improvement: wrap dynamic_method with a method similar to this, which will reduce the number of created lambdas: # untested def dyn_create(name) m = dynamic_method(name) class<