Нечто подобное может вам помочь:
class TeeIO < IO
def initialize orig, file
@orig = orig
@file = file
end
def write string
@file.write string
@orig.write string
end
end
Большинство методов в IO
, которые действительно выводят, в конечном итоге используют write
, поэтому вам нужно только переопределить этот один метод. Вы можете использовать это так:
#setup
tee = TeeIO.new $stdout, File.new('out.txt', 'w')
$stdout = tee
# Now lots of example uses:
puts "Hello"
$stdout.puts "Extending IO allows us to expicitly use $stdout"
print "heres", :an, :example, "using", 'print', "\n"
48.upto(57) do |i|
putc i
end
putc 10 #newline
printf "%s works as well - %d\n", "printf", 42
$stdout.write "Goodbye\n"
После этого примера в и консоли и в файл одинаково записывается следующее:
Hello
Extending IO allows us to expicitly use $stdout
heresanexampleusingprint
0123456789
printf works as well - 42
Goodbye
Я не буду утверждать, что этот метод является стойким к ошибкам, но он должен работать для простого использования стандартного вывода. Протестируйте его для использования.
Обратите внимание, что вам не нужно использовать reopen
на $stdout
, если вы не хотите перенаправить вывод из дочернего процесса или неработающего расширения. Простое присвоение ему другого IO
объекта будет работать для большинства целей.
RSpec
Командная строка RSpec принимает ссылку на $stdout
до . Вы можете запустить любой код для его переназначения, так что это не работает. reopen
все еще работает в этом случае, так как вы изменяете фактический объект, на который указывает и $stdout
, и ссылку, которая есть у RSpec, но это не дает вам выходной сигнал для обоих.
Одним из решений является обезьяна-патч $stdout
, например:
$out_file = File.new('out.txt', 'w')
def $stdout.write string
$out_file.write string
super
end
Это работает, но, как со всеми исправлениями обезьян, будьте осторожны. Было бы безопаснее использовать команду tee
вашей ОС.