Robert Klemme
2/18/2005 8:36:00 AM
"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?
Kind regards
robert