Подтвердить что ты не робот

Как я могу записать STDOUT в строку?

puts "hi"
puts "bye"

Я хочу сохранить STDOUT кода до сих пор (в этом случае hi\nbye в переменную say "result" и распечатать его)

puts result

Причина, по которой я это делаю, - это интегрировать R-код в свой код Ruby, вывод которого передается STDOUT по мере запуска R-кода, но выход из этого кода не может быть доступен внутри кода для выполнения некоторых оценок. Извините, если это сбивает с толку. Поэтому строка "puts result" должна дать мне привет и до свидания.

4b9b3361

Ответ 1

Перенаправить стандартный вывод в объект 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

На практике это, вероятно, не очень хорошая идея, но, по крайней мере, теперь вы знаете, что это возможно.

Ответ 2

Удобная функция для захвата стандартного вывода в строку...

Следующий метод представляет собой удобный инструмент общего назначения для захвата стандартного вывода и возврата его в виде строки. (Я часто использую это в модульных тестах, где хочу проверить что-то, напечатанное на стандартный вывод.) Обратите особое внимание на использование условия 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

Ответ 3

Если в вашем проекте доступна активная поддержка, вы можете сделать следующее:

output = capture(:stdout) do
  run_arbitrary_code
end

Более подробную информацию о Kernel.capture можно найти здесь

Ответ 4

Вы можете сделать это, обратившись к своему R script внутри backticks, например:

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

Для получения дополнительной информации о запуске подпроцессов в Ruby, просмотрите этот вопрос о переполнении стека.

Ответ 5

Для большинства практических целей вы можете поместить что-нибудь в $stdout, который отвечает на write, flush, sync, sync= и tty?.

В этом примере я использую модифицированный Queue из stdlib.

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 или файла будет проблематичным с несколькими потоками, которые пытаются синхронизировать чтение и запись одновременно.

Ответ 6

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

Сам TG45 доступен в любой версии Ruby, начиная с 1.9.3.

Ответ 7

Для RinRuby, пожалуйста, знайте, что R имеет capture.output:

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

puts R.captured 

Ответ 8

Захват stdout (или stderr) для кода Ruby и подпроцессов

# 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

Я получил вдохновение от Жона.

Ответ 9

Кредит на ответ @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