Monkey Patching a method and back

S

S. Robert James

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?
 
J

James Edward Gray II

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
:eek:ld
end
end
e = Existing.new
e.needs_patching # => :eek:ld

# 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 # => :eek:ld

__END__

Hope that helps.

James Edward Gray II
 
D

dblack

Hi --

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... :) 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 :)
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

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
D

dblack

Hi --

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

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
J

James Edward Gray II

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 Gray II
 
D

dblack

Hi --

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

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
D

dblack

Hi --

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

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top