これを行う正しい方法は、Dan が言うようにスタブ フレームワークを実際に使用することです。
たとえば、rspec では次のようにします。
it "reads the file contents" do
File.should_receive(:open) {|name|
if name.include?("retval")
"0\n"
else
"1\n"
end
}
File.open("foo retval").should == "0\n"
File.open("other file").should == "1\n"
end
しかし、好奇心旺盛な人のために、外部ライブラリなしでそれを行う半安全な方法を次に示します。考えられるのは、スタブによって影響を受けるコードができるだけ少なくなるように、スタブを分離することです。
このスクリプトにisolated-patch.rb
次の名前を付けました。
class File
class << self
alias_method :orig_open, :open
def stubbed_open(name, &block)
if name.include?("retval")
return "0\n"
else
return "1\n"
end
end
end
end
def get_size(path)
# contrived example
File.open(path) {|fh|
# change bytesize to size on ruby 1.8
fh.read.bytesize
}
end
# The stub will apply for the duration of the block.
# That means the block shouldn't be calling any methods where file opening
# needs to work normally.
# Warning: not thread-safe
def stub_file_open
class << File
alias_method :open, :stubbed_open
end
yield
ensure
class << File
alias_method :open, :orig_open
end
end
if __FILE__ == $0
stub_file_open do
val = File.open("what-retval") { puts "this is not run" }
puts "stubbed open() returned: #{val.inspect}"
size = get_size("test.txt")
puts "obviously wrong size of test.txt: #{size.inspect}"
end
# you need to manually create this file before running the script
size = get_size("test.txt")
puts "size of test.txt: #{size.inspect}"
end
デモ:
> echo 'foo bar' > test.txt
> ruby isolated-patch.rb
stubbed open() returned: "0\n"
obviously wrong size of test.txt: "1\n"
size of test.txt: 8