On Fri, 18 Feb 2005 17:39:47 +0900, Robert Klemme <bob.news / gmx.net> wrote:
> 
> "Mark Hubbart" <discordantus / gmail.com> schrieb im Newsbeitrag
> news:de63abca050217095240cde47c / mail.gmail.com...
> > On Thu, 17 Feb 2005 17:19:54 +0900, Robert Klemme <bob.news / gmx.net>
> wrote:
> > >
> > > "Mark Hubbart" <discordantus / gmail.com> schrieb im Newsbeitrag
> > > news:de63abca050216125273686a45 / mail.gmail.com...
> > > > On Wed, 16 Feb 2005 18:19:50 +0900, Robert Klemme <bob.news / gmx.net>
> > > wrote:
> > > > >
> > > > > "Mark Hubbart" <discordantus / gmail.com> 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.
> > > > >
> > > > > <snip/>
> > > > >
> > > > > > 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<<self;self;end.class_eval do
>     define_method(name.to_sym,*a,&m)
>   end
> end
> 
> Then invoke this method via respond_to?, method_missing and method.  Then
> the method is defined on first access. What do you think?

That's an interesting way of doing it. I suppose if at a later time
the method needs to be modified, you could always undef it and let the
dyn_create method catch it the next time through.

On the other hand, the more I think about this, the more complicated
it seems to get. I'm not really as gung ho on the idea as when I first
thought of it. Maybe if it was worked into the syntax somehow, it
would be worthwhile; but I wouldn't know where to start. Perhaps a
better way to go would be to make it easier to wrap respond_to?() and
methods(). Which is coming in 2.0 anyway :)

cheers,
Mark