Monkey Patching a method and back

I need to temporarily mokey patch out a method in a certain class used
by a lib in one of my tests. That’s easy.

However, what I don’t know how to do is to restore back the orginial
(without copying in the src, of course), when I’m done. Is there any
good way to do this - that is, monkey patch temporarily, and then put
things back the way they were?

On Dec 10, 2006, at 3:35 PM, S. Robert J. wrote:

I need to temporarily mokey patch out a method in a certain class used
by a lib in one of my tests. That’s easy.

However, what I don’t know how to do is to restore back the orginial
(without copying in the src, of course), when I’m done. Is there any
good way to do this - that is, monkey patch temporarily, and then put
things back the way they were?

Sure:

#!/usr/bin/env ruby -w

class Existing
def needs_patching
:old
end
end
e = Existing.new
e.needs_patching # => :old

save the old and patch

class Existing
alias_method :saved_needs_patching, :needs_patching
def needs_patching
:new
end
end
e.needs_patching # => :new

restore the old

class Existing
undef :needs_patching
alias_method :needs_patching, :saved_needs_patching
end
e.needs_patching # => :old

END

Hope that helps.

James Edward G. II

Hi –

On Mon, 11 Dec 2006, S. Robert J. wrote:

I need to temporarily mokey patch out a method in a certain class used
by a lib in one of my tests. That’s easy.

However, what I don’t know how to do is to restore back the orginial
(without copying in the src, of course), when I’m done. Is there any
good way to do this - that is, monkey patch temporarily, and then put
things back the way they were?

I reply under mild protest, as I detest the term “monkey patching”
(and never know what people mean by it, since they mean different
things). Anyway… :slight_smile: One way to change a method temporarily,
albeit a non-thread-safe way, is with aliases – something like:

alias newname oldname
def oldname

end
alias oldname newname

That was the basis of Ruby Behaviors, a package I wrote in 2001 to do
exactly this: temporary changes to core behaviors. Matz described the
alias approach at RubyConf 2001 as a “naive” way to go about it :slight_smile:
It did however spark an interesting discussion about selector
namespaces, a discussion we’re basically still having.

There are, or were, also some other libraries on RAA that address
this. I’m afraid I don’t remember their names and am being too lazy
to look them up, but if you hunt for library stuff pertaining to
classes and methods you’ll most likely find them.

David

Hi –

On Mon, 11 Dec 2006, [email protected] wrote:

There are, or were, also some other libraries on RAA that address
this. I’m afraid I don’t remember their names and am being too lazy
to look them up, but if you hunt for library stuff pertaining to
classes and methods you’ll most likely find them.

Found it: “import-module”. It’s even thread-safe.

http://raa.ruby-lang.org/project/import_module/

David

Will this be OK even if patched and unpatched multiple times?

On Dec 10, 2006, at 4:05 PM, S. Robert J. wrote:

Will this be OK even if patched and unpatched multiple times?

You probably want to use something more robust for that. You need to
make sure you only alias the method is a saved version doesn’t
already exist.

James Edward G. II

[email protected] wrote:

In case it got lost in my reply to my reply: have a look at:

http://raa.ruby-lang.org/project/import_module/

Thanks. That’s quite a hefty module - with method am I interested in?

Hi –

On Mon, 11 Dec 2006, James Edward G. II wrote:

On Dec 10, 2006, at 4:05 PM, S. Robert J. wrote:

Will this be OK even if patched and unpatched multiple times?

You probably want to use something more robust for that. You need to make
sure you only alias the method is a saved version doesn’t already exist.

In case it got lost in my reply to my reply: have a look at:

http://raa.ruby-lang.org/project/import_module/

David

Hi –

On Mon, 11 Dec 2006, S. Robert J. wrote:

[email protected] wrote:

In case it got lost in my reply to my reply: have a look at:

http://raa.ruby-lang.org/project/import_module/

Thanks. That’s quite a hefty module - with method am I interested in?

I’m thinking something like (untested):

module M
def join
“I’m a new version of join!”
end
end

arr = [1,2,3]
Array.import_module(M) do
puts foo.join # I’m a new version of join!
end
puts foo.join # 123

so that you’d be temporarily layering different versions of the
method(s).

David

On 12/11/06, [email protected] [email protected] wrote:

I reply under mild protest, as I detest the term “monkey patching”

+1

martin