On 8/12/07, Thomas Hafner <thomas / hafner.nl.eu.org> wrote:
> "Gregory Brown" <gregory.t.brown / gmail.com> wrote/schrieb <b37300880708111035o2af744e1g2411e061054095ee / mail.gmail.com>:
>
> > What problem do you need this for... it sounds like you could get by
> > with a different (and better) approach, but we'd need to know a little
> > more about what you're trying to do.
>
> 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.