ruby 如何将STDOUT捕获到字符串中?

2cmtqfgy  于 8个月前  发布在  Ruby
关注(0)|答案(9)|浏览(92)
puts "hi"
puts "bye"

字符串
我想存储到目前为止的代码的STDOUT(在这种情况下,hi \nbye到一个变量,说'结果',并打印它)

puts result


我这样做的原因是我已经将R代码集成到我的Ruby代码中,当R代码运行时,其输出被提供给STDOUT,但是输出不能在代码内部访问以进行一些计算。如果这令人困惑,对不起。所以“puts result”行应该给我打招呼。

kiz8lqtg

kiz8lqtg1#

将stdout捕获为字符串的方便函数.

下面的方法是一个方便的通用工具,用于捕获标准输出并将其作为字符串返回。(我经常在单元测试中使用这个方法,我想验证打印到标准输出的内容。)特别注意使用ensure子句来恢复$标准输出(并避免惊讶):

def with_captured_stdout
  original_stdout = $stdout  # capture previous value of $stdout
  $stdout = StringIO.new     # assign a string buffer to $stdout
  yield                      # perform the body of the user code
  $stdout.string             # return the contents of the string buffer
ensure
  $stdout = original_stdout  # restore $stdout to its previous value
end

字符串
例如:

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

wb1gzix0

wb1gzix02#

将标准输出重定向到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

字符串
在实践中,这可能不是一个好主意,但至少现在你知道这是可能的。

6psbrbz9

6psbrbz93#

如果您的项目中有activesupport,您可以执行以下操作:

output = capture(:stdout) do
  run_arbitrary_code
end

字符串
关于Kernel.capture的更多信息可以在here中找到

8wigbo56

8wigbo564#

你可以通过在反引号内调用你的R脚本来做到这一点,就像这样:

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

字符串
有关在Ruby中运行子进程的更多信息,请查看this Stack Overflow question

sulc1iza

sulc1iza5#

捕获Ruby代码 * 和 * 子进程的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

kmbjn2e3

kmbjn2e36#

对于大多数实际用途,您可以将任何响应writeflushsyncsync=tty?的内容放入$stdout中。
在这个例子中,我使用了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或文件将有问题,因为多个线程试图同时同步读取和写入。

mi7gmzs6

mi7gmzs67#

Minitest版本:
assert_output如果你需要确保是否生成了一些输出:

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

字符串
Assert输出
或者如果你真的需要捕获它,使用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


捕获IO
Minitest本身可以在从1.9.3开始的任何Ruby版本中使用

nfg76nw0

nfg76nw08#

对于RinRuby,请知道R有capture.output

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

puts R.captured

字符串

rn0zuynd

rn0zuynd9#

感谢@girasquid的回答。我将其修改为单个文件版本:

def capture_output(string)
  `echo #{string.inspect}`.chomp
end

# example usage
response_body = "https:\\x2F\\x2Faccounts.google.com\\x2Faccounts"
puts response_body #=> https:\x2F\x2Faccounts.google.com\x2Faccounts
capture_output(response_body) #=> https://accounts.google.com/accounts

字符串

相关问题