Agreed that that there might be a better solution for the original
problem, but sometimes an intermediate problem becomes interesting per
se. Anyway, the original question is how to find a single, more
abstract function replacing these ones:
def with_output_to_string
$stdout, tmp = StringIO.new, $stdout
yield
$stdout, tmp = tmp, $stdout
tmp.rewind
tmp.read
end
def with_error_to_string
$stderr, tmp = StringIO.new, $stderr
yield
$stderr, tmp = tmp, $stderr
tmp.rewind
tmp.read
end
The only difference is $stdout vs. $stderr, so the idea was to pass
:$stdout resp. :$stderr as parameter.
Interesting. Perhaps this is a direct translation of how you might do
this without an eval (untested):
module Kernel
def set_stdout(obj)
$stdout = obj
end
def set_stderr(obj)
$stderr = obj
end
end
def with_helper(msg)
temp = (msg == :stdout ? $stdout : $stderr)
send("set_#{msg}", StringIO.new)
yield
send("set_#{msg}",temp)
temp.rewind
temp.read
end
def with_output_to_string
with_helper

stdout) { yield }
end
def with_error_to_string
with_helper

stderr) { yield }
end
Of course, this doesn't sound like a great idea, as unless the real
problem is actually a whole lot more interesting, this is just
unnecessary generalization and doesn't clean things up any.
Are you looking to do this to test a codebase that writes to $stdout / $stderr?
It's perfectly reasonable to have a class or method definition like this:
class Foo
def initialize(out=$stdout,err=$stderr)
@out = out
@err = err
end
def print_to_stdout
@out.puts "something"
end
def print_to_stderr
@err.puts "something"
end
end
Now if you wanted to test that, you could pass in your StringIO
objects. Maybe you can draw some ideas from that, if not, it'd be
interesting to see what you're using this helper for.