43 votes

Comment puis-je rediriger temporairement stderr en Ruby?

J'aimerais temporairement rediriger stderr dans un script Ruby pour la durée d'un bloc, veillant à ce que je le réinitialiser à sa valeur d'origine à la fin du bloc.

J'ai eu du mal à trouver comment faire cela dans le rubis docs.

64voto

molf Points 34978

En Ruby, $stderr désigne le flux de sortie qui est actuellement utilisé comme stderr, alors qu' STDERR est la valeur par défaut flux stderr. Il est facile d'attribuer temporairement un autre flux de sortie d' $stderr.

require "stringio"

def capture_stderr
  # The output stream must be an IO-like object. In this case we capture it in
  # an in-memory IO object so we can return the string value. You can assign any
  # IO object here.
  previous_stderr, $stderr = $stderr, StringIO.new
  yield
  $stderr.string
ensure
  # Restore the previous value of stderr (typically equal to STDERR).
  $stderr = previous_stderr
end

Maintenant, vous pouvez effectuer les opérations suivantes:

captured_output = capture_stderr do
  # Does not output anything directly.
  $stderr.puts "test"
end

captured_output
#=> "test\n"

Le même principe fonctionne aussi pour d' $stdout et STDOUT.

17voto

louism Points 1648

Ici est un résumé de la solution (crédit va à David Heinemeier Hansson):

def silence_streams(*streams)
  on_hold = streams.collect { |stream| stream.dup }
  streams.each do |stream|
    stream.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null')
    stream.sync = true
  end
  yield
ensure
  streams.each_with_index do |stream, i|
    stream.reopen(on_hold[i])
  end
end

Utilisation:

silence_streams(STDERR) { do_something }

10voto

gunn Points 3050

Essentiellement la même chose que @molf réponse, et a le même usage:

require "stringio"
def capture_stderr
  real_stderr, $stderr = $stderr, StringIO.new
  yield
  $stderr.string
ensure
  $stderr = real_stderr
end

Il utilise StringIO très légèrement de façon plus concise, et préserve $stderr comme ce qu'il était avant capture_stderr a été appelé.

6voto

zhon Points 691

J'aime la StringIO réponses. Mais si vous appelez d'un processus externe, et $stderr = StringIO.new ne fonctionne pas, vous pouvez écrire stderr dans un fichier temporaire:

require 'tempfile'

def capture_stderr
  backup_stderr = STDERR.dup
  begin
    Tempfile.open("captured_stderr") do |f|
      STDERR.reopen(f)
      yield
      f.rewind
      f.read
    end
  ensure
    STDERR.reopen backup_stderr
  end
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X