Hi --
> Phlip wrote:
>
> > Yaser Sulaiman wrote:
> >
> > > 3- Is the following considered as monkey patching, or is it something
else?
> > >
> > > class String
> > > def foo
> > > "bar"
> > > end
> > > end
> > >
> >
> > No, that is simply extending the class with a new method.
> >
>
> Ah, but that's the interesting part: how do you know that somebody
> else didn't already add a String#foo method? In that case, it *would*
> be monkey patching. Even worse: which of the two methods would be
> considered monkey patching and which one wouldn't, would depend
> entirely on the *load order* of those two snippets of code.
>
> That's why I don't think distinguishing between adding and changing
> methods makes sense: either both are monkey patching or neither are.
>
This was true, and quite deeply examined, well before the term "monkey
patching" came along to cloud the issue
Adding a new method involves a kind of Prisoners' Dilemma, situation,
where if either of us is the only one to add that particular method,
we "win", but if we both do it, we lose. Changing methods, however,
can be done in a relatively low-impact way, if you chain them rather
than really changing them.
That is not entirely true. For one the array has each_with_index but I
could not find collect_with_index. If you look at the order of block
arguments passed by each_with_index and implement collect_with_index
the same way then if somebody else implements another one it must work
the same or they did it wrong
So if exact implementation of an extension can be logically deduced
from existing functionality adding it should not break anything,
Unfortunately it's rarely possible.
I'll put in a plug for what I believe is by far the safest way to
extend core functionality, namely #extend. A classic case is the
desire to have #gsub! not return nil when the string doesn't change.
module MyGsubBang
def gsub!(*args, &block)
super(*args, &block) || self
end
end
str = "abc".extend(MyGsubBang)
Among other advantages, this way of doing it forces you to think
carefully about the specific objects, and not throw too large a
blanket over what is actually a tiny problem (having one or two
objects that you want to behave different from the norm).
The problem with this approach is that either you want it on 1-2
objects and then it's very local and the objects need not be strings
anyway, you can just make a special object for the purpose.
If you want strings that are used in particular piece of code to be
extended you can do it on the entry point(s). However, it's tedious
and error-prone this way. (The concern about changing the strings is
not in place here if you gsub! them anyway, and you can dup)
The problem is that if the strings ever leave your code they are still
patched so in the end patching *all* strings in some way seems the
cleanest possible solution. Perhaps by adding a different method like
gsub!! or gsub!non_nil (assuming at least one is a valid identifier).
That's why some sort of namespacing was requested so many times. It
makes patching in methods so much cleaner - only you would see the
methods you have added or modified.
Thanks
Michal
···
On 02/01/2009, David A. Black <dblack@rubypal.com> wrote:
On Fri, 2 Jan 2009, Jörg W Mittag wrote: