# Reverting module changes

**URL:** <https://www.ruby-forum.com/t/reverting-module-changes/80328>\
**Category:** Ruby\
**Created:** [December 24, 2006, 4:00am UTC](https://www.ruby-forum.com/t/reverting-module-changes/80328 "2006-12-24T04:00:44Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![azreal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/58f4c7/32.png) [@azreal](https://www.ruby-forum.com/u/azreal)\
**Post date:** [December 24, 2006, 4:00am UTC](https://www.ruby-forum.com/t/reverting-module-changes/80328/1 "2006-12-24T04:00:44Z")

</div>

Hi,

I want to mock standard Kernel.system with my own method and then  
revert back to the original version. I was able to do the former, but  
not the latter. Currently I’m overwriting Kernel.system method  
definition with:

def system\_should\_return what  
Kernel.module\_eval “def system(\*args) #{what.inspect} end”  
end

I don’t a have idea how going back to the original state can be done.  
Thanks in advance for any help on this.

Cheers,  
mk

---

<div class="post-metadata">

**Author:** ![azreal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/58f4c7/32.png) [@azreal](https://www.ruby-forum.com/u/azreal)\
**Post date:** [December 24, 2006, 4:08am UTC](https://www.ruby-forum.com/t/reverting-module-changes/80328/2 "2006-12-24T04:08:45Z")

</div>

On 12/23/06, Michal K. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I don’t a have idea how going back to the original state can be done.  
> Thanks in advance for any help on this.

Maybe there’s something more elegant. But I’d first alias the  
original method, redefine it, then when I was done, I’d redefine it  
again to just call the alias.  
-Mat

---

<div class="post-metadata">

**Author:** ![azreal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/58f4c7/32.png) [@azreal](https://www.ruby-forum.com/u/azreal)\
**Post date:** [December 24, 2006, 4:26am UTC](https://www.ruby-forum.com/t/reverting-module-changes/80328/3 "2006-12-24T04:26:46Z")

</div>

Mat S. wrote:

> > I don’t a have idea how going back to the original state can be done.  
> > Thanks in advance for any help on this.
> 
> Maybe there’s something more elegant. But I’d first alias the  
> original method, redefine it, then when I was done, I’d redefine it  
> again to just call the alias.

Thanks, aliasing was what I was looking for. Does code below look OK or  
can be improved?

def system\_should\_return what  
Kernel.module\_eval \<\<-EOV  
alias\_method :orig\_system, :system  
def system(\*args)  
#{what.inspect}  
end  
EOV  
end

def restore\_system\_behaviour  
Kernel.module\_eval \<\<-EOV  
def system()  
orig\_system  
end  
EOV  
end

Cheers,  
mk

---

<div class="post-metadata">

**Author:** ![azreal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/58f4c7/32.png) [@azreal](https://www.ruby-forum.com/u/azreal)\
**Post date:** [December 24, 2006, 4:44am UTC](https://www.ruby-forum.com/t/reverting-module-changes/80328/4 "2006-12-24T04:44:48Z")

</div>

Hi –

On Sun, 24 Dec 2006, Michal K. wrote:

> > >
> 
> def system\_should\_return what  
> def system()  
> orig\_system  
> end  
> EOV  
> end

I like to avoid the string version of module\_eval (and similar), and  
use the block version instead, where possible. To do that with your  
code, you could do:

def system\_should\_return(what)  
Kernel.module\_eval do  
alias\_method :orig\_system, :system  
define\_method(:system) {|\*args| what.inspect }  
end  
end

def restore\_system\_behaviour  
Kernel.module\_eval do  
alias\_method :system, :orig\_system  
end  
end

Note also that there’s a library, available via RAA, that lets you do  
temporary changes to core behaviors:

[http://raa.ruby-lang.org/project/import\_module/](http://raa.ruby-lang.org/project/import_module/)

Actually there a couple of such libraries (including my Ruby  
Behaviors), but that one is the most full-featured. It might come in  
handy if you do a lot of this or need thread safety.

David

---

<div class="post-metadata">

**Author:** ![azreal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/58f4c7/32.png) [@azreal](https://www.ruby-forum.com/u/azreal)\
**Post date:** [December 24, 2006, 5:26am UTC](https://www.ruby-forum.com/t/reverting-module-changes/80328/5 "2006-12-24T05:26:51Z")

</div>

removed\_email\_address@domain.invalid wrote:

> def restore\_system\_behaviour  
> Kernel.module\_eval do  
> alias\_method :system, :orig\_system  
> end  
> end

I’ve tried to make a more versatile version of this that works for any  
module and method. I’ve ended up with the following code:

class Module  
class Stub  
def initialize procedure  
@procedure = procedure  
end

```
def and_return value
  @procedure.call value
end

```

end

def override! method  
Stub.new(lambda do |value|  
alias\_method((“orig\_” + method.to\_s).to\_sym, method)  
define\_method(method) { value }  
end)  
end

def restore! method  
alias\_method(method, (“orig\_” + method.to\_s).to\_sym)  
end  
end

With this code, to override the system method you can write (syntax  
inspired by RSpec):

```
Kernel.override!(:system).and_return false

```

and then to restore:

```
Kernel.restore! :system

```

Can you suggest any improvements to this code?

> Note also that there’s a library, available via RAA, that lets you do  
> temporary changes to core behaviors:
> 
> [http://raa.ruby-lang.org/project/import\_module/](http://raa.ruby-lang.org/project/import_module/)

Wow, very cool. Thanks!

Cheers,  
mk

---

<div class="post-metadata">

**Author:** ![azreal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/58f4c7/32.png) [@azreal](https://www.ruby-forum.com/u/azreal)\
**Post date:** [December 24, 2006, 11:03am UTC](https://www.ruby-forum.com/t/reverting-module-changes/80328/6 "2006-12-24T11:03:38Z")

</div>

The Stubba portion of Mocha ([http://mocha.rubyforge.org](http://mocha.rubyforge.org)) allows you to  
temporarily replace the implementation of a Module method within a  
test.

require ‘test/unit’  
require ‘test/unit/ui/console/testrunner’  
require ‘rubygems’  
require ‘stubba’

class Test1 \< Test::Unit::TestCase

def test\_should\_force\_system\_to\_return\_false  
Kernel.stubs(:system).returns(false)  
assert\_equal false, Kernel.system(‘echo’)  
end

end

class Test2 \< Test::Unit::TestCase

def test\_should\_not\_be\_affected\_by\_other\_test  
assert\_equal true, Kernel.system(‘echo’)  
end

end

class OrderedTests \< Test::Unit::TestCase

def self.suite  
suite = Test::Unit::TestSuite.new(‘OrderedTests’)  
suite \<\< Test1.suite  
suite \<\< Test2.suite  
end

end

Test::Unit::UI::Console::TestRunner.run(OrderedTests)

---

<div class="post-metadata">

**Author:** ![azreal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/58f4c7/32.png) [@azreal](https://www.ruby-forum.com/u/azreal)\
**Post date:** [December 24, 2006, 6:16am UTC](https://www.ruby-forum.com/t/reverting-module-changes/80328/7 "2006-12-24T06:16:57Z")

</div>

On Dec 23, 2006, at 19:00, Michal K. wrote:

> Thanks in advance for any help on this.  
> Its simpler to not overwrite Kernel#system.

If your class looks something like:

$ cat runner.rb  
class Runner

def run(command)  
puts command  
system command  
end

end

Use open classes and inheritance to add a system that works when you  
want it. Restoring the real system for the Runner class is as simple  
as removing the method again.

$ cat test\_runner.rb  
require ‘test/unit’  
require ‘runner’

class Runner  
attr\_accessor :commands, :results  
def system(command)  
@commands \<\< command  
@results.shift  
end  
end

class TestRunner \< Test::Unit::TestCase

def setup  
@runner = Runner.new  
@runner.commands = []  
@runner.results = []  
end

def test\_run  
@runner.results \<\< false

```
 assert_equal false, @runner.run("exit 1")

 assert @runner.results.empty?
 assert_equal 1, @runner.commands.length
 assert_equal 'exit 1', @runner.commands.first

```

end

end

$ ruby test\_runner.rb  
Loaded suite test\_runner  
Started  
exit 1  
.  
Finished in 0.000369 seconds.

1 tests, 4 assertions, 0 failures, 0 errors

If you want to get rid of the “exit 1” use util\_capture from  
ZenTest’s test/zentest\_assertions.rb

–  
Eric H. - removed\_email\_address@domain.invalid - [http://blog.segment7.net](http://blog.segment7.net)

I LIT YOUR GEM ON FIRE!

---

<div class="post-metadata">

**Author:** ![azreal](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/58f4c7/32.png) [@azreal](https://www.ruby-forum.com/u/azreal)\
**Post date:** [December 24, 2006, 2:33pm UTC](https://www.ruby-forum.com/t/reverting-module-changes/80328/8 "2006-12-24T14:33:52Z")

</div>

Hi –

On Sun, 24 Dec 2006, Michal K. wrote:

> > end  
> > class Module  
> > def override! method
> 
> With this code, to override the system method you can write (syntax  
> inspired by RSpec):
> 
> Kernel.override!(:system).and\_return false
> 
> and then to restore:
> 
> Kernel.restore! :system
> 
> Can you suggest any improvements to this code?

A couple of things, but be warned I am still early in my coffee today  
🙂

You don’t need to\_sym in those calls to alias\_method; it will take a  
string. In fact, you can do this:

“orig\_#{method}”

which will work for either.

The ! is generally used for methods that come in pairs: override and  
override! It indicates that one is the “dangerous” version of the  
operation. In this case, there’s only one of each, and the name  
itself describes what’s happening, so I’d lose the !'s. (I’ll keep  
them in my examples below, though.)

I would avoid “and\_return”, which is a kind of odd method name (it  
leaves me thinking: don’t methods always return something?). It’s  
better just to tell the method what you want, and not string it across  
multiple method calls. Just give it two arguments, or a hash of  
arguments.

Here’s another version, for your reading pleasure. Use only as  
desired.

class Module

def override(opts)  
method, value = opts.values\_at(:method, :value)  
alias\_method “orig\_#{method}”, method  
define\_method(method) { value }  
end

def restore(method)  
alias\_method method,“orig\_#{method}”  
end

end

Kernel.override(:method =\> “system”, :value =\> 3)  
puts system  
Kernel.restore(:system)  
system(“date”)

What would be more general would be a way to specify the new behavior  
arbitrarily, with a code block, which the import-module library does.

David
