Hi --
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?
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
···
On Sun, 24 Dec 2006, Michal Kwiatkowski wrote:
dblack@wobblini.net wrote:
--
Q. What's a good holiday present for the serious Rails developer?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
aka The Ruby book for Rails developers!
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)