[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Reverting module changes

Michal Kwiatkowski

12/24/2006 2:56:00 AM

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

7 Answers

Mat Schaffer

12/24/2006 3:08:00 AM

0

On 12/23/06, Michal Kwiatkowski <constant.beta@gmail.com> wrote:
> 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.

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

Michal Kwiatkowski

12/24/2006 3:23:00 AM

0

Mat Schaffer wrote:
> On 12/23/06, Michal Kwiatkowski <constant.beta@gmail.com> wrote:
> > 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.
>
> 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

dblack

12/24/2006 3:44:00 AM

0

Michal Kwiatkowski

12/24/2006 4:23:00 AM

0

dblack@wobblini.net wrote:
> 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

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/impo...

Wow, very cool. Thanks!

Cheers,
mk

Eric Hodel

12/24/2006 5:16:00 AM

0

On Dec 23, 2006, at 19:00, Michal Kwiatkowski wrote:
> 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.

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

James Mead

12/24/2006 10:02:00 AM

0

The Stubba portion of Mocha (http://mocha.rub...) 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)

--
James.
http://blog.floe...

dblack

12/24/2006 1:32:00 PM

0