puts "hi"
puts "bye"
私はこれまでにコードのSTDOUTを保存したい(この場合、こんにちは\ nbyeを変数に「結果」と言って出力する)
puts result
私がこれをしている理由は、Rコードを私のRubyコードに統合しており、その出力はRコードが実行されるとSTDOUTに与えられますが、出力はコード内でアクセスできませんこれがわかりにくい場合は申し訳ありませんが、「puts result」行にこんにちはとさようならが表示されます。
確かに標準出力を変数にリダイレクトできます。例えば:
# 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
実際には、これはおそらく素晴らしいアイデアではありませんが、少なくとも今では可能だとわかっています。
次のメソッドは、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
プロジェクトでactivesupportが利用可能な場合は、次を実行できます。
output = capture(:stdout) do
run_arbitrary_code
end
Kernel.capture
に関する詳細情報は こちら にあります。
これを行うには、次のようにバックティック内でRスクリプトを呼び出します。
result = `./run-your-script`
puts result # will contain STDOUT from run-your-script
Rubyでのサブプロセスの実行の詳細については、 this Stack Overflow question をご覧ください。
最も実用的な目的のために、$stdout
は、write
、flush
、sync
、sync=
および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またはファイルを使用すると、複数のスレッドが読み取りと書き込みを同時に同期しようとすると問題が発生します。
Minitest
バージョン:
assert_output
何らかの出力が生成されるかどうかを確認する必要がある場合:
assert_output "Registrars processed: 1\n" do
puts 'Registrars processed: 1'
end
または、本当にキャプチャする必要がある場合は、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
Minitest
自体は、任意のRuby 1.9.3
から始まるバージョンで利用可能です]
RinRubyの場合、Rにはcapture.output
:
R.eval <<EOF
captured <- capture.output( ... )
EOF
puts R.captured
# 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 からインスピレーションを得ました。