web-dev-qa-db-ja.com

STDOUTを文字列にキャプチャするにはどうすればよいですか?

puts "hi"
puts "bye"

私はこれまでにコードのSTDOUTを保存したい(この場合、こんにちは\ nbyeを変数に「結果」と言って出力する)

puts result

私がこれをしている理由は、Rコードを私のRubyコードに統合しており、その出力はRコードが実行されるとSTDOUTに与えられますが、出力はコード内でアクセスできませんこれがわかりにくい場合は申し訳ありませんが、「puts result」行にこんにちはとさようならが表示されます。

34
script_kiddie

標準出力をStringIOオブジェクトにリダイレクトする

確かに標準出力を変数にリダイレクトできます。例えば:

# Set up standard output as a StringIO object.
foo = StringIO.new
$stdout = foo

# Send some text to $stdout.
puts 'hi'
puts 'bye'

# Access the data written to standard output.
$stdout.string
# => "hi\nbye\n"

# Send your captured output to the original output stream.
STDOUT.puts $stdout.string

実際には、これはおそらく素晴らしいアイデアではありませんが、少なくとも今では可能だとわかっています。

41
Todd A. Jacobs

標準出力を文字列にキャプチャする便利な関数...

次のメソッドは、stdoutをキャプチャして文字列として返す便利な汎用ツールです。 (私は、stdoutに出力されたものを検証したい単体テストでこれを頻繁に使用します。)特に$ _stdoutを復元する(そして驚かないようにする)ためのensure節の使用に注意してください。

def with_captured_stdout
  original_stdout = $stdout
  $stdout = StringIO.new
  yield
  $stdout.string
ensure
  $stdout = original_stdout
end

したがって、たとえば:

>> str = with_captured_stdout { puts "hi"; puts "bye"}
=> "hi\nbye\n"
>> print str
hi
bye
=> nil
61
fearless_fool

プロジェクトでactivesupportが利用可能な場合は、次を実行できます。

output = capture(:stdout) do
  run_arbitrary_code
end

Kernel.captureに関する詳細情報は こちら にあります。

9
Dimitris Zorbas

これを行うには、次のようにバックティック内でRスクリプトを呼び出します。

result = `./run-your-script`
puts result  # will contain STDOUT from run-your-script

Rubyでのサブプロセスの実行の詳細については、 this Stack Overflow question をご覧ください。

8
girasquid

最も実用的な目的のために、$stdoutは、writeflushsyncsync=およびtty?

この例では、stdlibから変更された Queue を使用します。

class Captor < Queue

  alias_method :write, :Push

  def method_missing(meth, *args)
    false
  end

  def respond_to_missing?(*args)
    true
  end
end

stream = Captor.new
orig_stdout = $stdout
$stdout = stream

puts_thread = Thread.new do
  loop do
    puts Time.now
    sleep 0.5
  end
end

5.times do
  STDOUT.print ">> #{stream.shift}"
end

puts_thread.kill
$stdout = orig_stdout

タスクの完了後にデータを見るだけでなく、積極的にデータを操作する場合は、このようなものが必要です。 StringIOまたはファイルを使用すると、複数のスレッドが読み取りと書き込みを同時に同期しようとすると問題が発生します。

1
Kimmo Lehto

Minitestバージョン:


assert_output何らかの出力が生成されるかどうかを確認する必要がある場合:

assert_output "Registrars processed: 1\n" do
  puts 'Registrars processed: 1'
end

assert_output


または、本当にキャプチャする必要がある場合は、capture_ioを使用します。

out, err = capture_io do
  puts "Some info"
  warn "You did a bad thing"
end

assert_match %r%info%, out
assert_match %r%bad%, err

capture_io

Minitest自体は、任意のRuby 1.9.3から始まるバージョンで利用可能です]

0
Artur Beljajev

RinRubyの場合、Rにはcapture.output

R.eval <<EOF
captured <- capture.output( ... )
EOF

puts R.captured 
0
Koert Vrieswijk

Ruby codeand)サブプロセスの両方のstdout(またはstderr)をキャプチャします。

# capture_stream(stream) { block } -> String
#
# Captures output on +stream+ for both Ruby code and subprocesses
# 
# === Example
#
#    capture_stream($stdout) { puts 1; system("echo 2") }
# 
# produces
# 
#    "1\n2\n"
#
def capture_stream(stream)
  raise ArgumentError, 'missing block' unless block_given?
  orig_stream = stream.dup
  IO.pipe do |r, w|
    # system call dup2() replaces the file descriptor 
    stream.reopen(w) 
    # there must be only one write end of the pipe;
    # otherwise the read end does not get an EOF 
    # by the final `reopen`
    w.close 
    t = Thread.new { r.read }
    begin
      yield
    ensure
      stream.reopen orig_stream # restore file descriptor 
    end
    t.value # join and get the result of the thread
  end
end

Zhon からインスピレーションを得ました。

0
hagello