2014-01-24 1 views
5

Я хочу знать, выходной поток который используется Рубином для печати этих вещей в командной строке:

irb(main):001:0> a="test" 
=> "test" 
irb(main):002:0> puts a 
test 
=> nil 
irb(main):003:0> a 
=> "test" 

используется $stdout для irb(main):002:0> и irb(main):003:0>? И есть ли какое-либо изменение в значении $stdout между этими двумя вызовами?

Кроме того, может ли кто-нибудь указать мне на источник Ruby, откуда эти вещи печатаются/записываются?

+3

Is '=> nil' вас смущает? Возвращение 'nil' не имеет ничего общего с STDOUT или STDERR. Это потому, что 'puts' возвращает нуль, о чем сообщается IRB. –

ответ

8

Да. И это легко проверить/доказать самому себе. Попробуйте в командной строке:

ruby -e 'puts "foo"' > test.out 
cat test.out 

Выход будет:

foo 

Рубин использует канал STDOUT для вывода на консоль. Затем ОС перенаправляет этот STDOUT на «test.out».

Попробуйте с:

ruby -e 'STDOUT.puts "foo"' > test.out 

, и вы получите тот же результат.

Если мы делаем:

ruby -e 'STDERR.puts "foo"' > test.out 
foo 
cat test.out 

Вы ничего не увидите в файле, а «Foo» будет написано в консоли на канале STDERR.

Ruby определяет $stdout как глобальный, который вы можете изменить, и STDOUT как константу, которую вы не должны изменять. Аналогичным образом доступны $stderr и STDERR.

Теперь, где это получает удовольствие, и доказывает ваш вопрос. Попробуйте это:

ruby -e '$stdout = STDERR; puts "foo"' > test.out 

, и вы будете иметь те же результаты, что и при выводе I в STDERR, потому что, в puts использовал значение для $stdout, чтобы выбрать выходной поток, и написал STDERR. Эти значения потока собираются Ruby из ОС при запуске интерпретатора и запоминаются во время выполнения сценария. Вы можете изменить их , если необходимо, и Ruby забудет эти настройки, когда переводчик выйдет, и перезагрузится в нормальное состояние в следующий раз.

Вы не должны полагаться на подразумеваемое/невидимое поведение изменения $stdout, хотя это приводит к ДЕЙСТВИТЕЛЬНО запутанному коду. Вместо этого я настоятельно рекомендую использовать явный STDERR.puts в любое время, когда вы пишете в STDERR, и голой puts для обычного вывода на STDOUT. Если вы смешаете вывод с обоими, то, вероятно, было бы лучше использовать STDOUT.puts и STDERR.puts, но это ваш звонок.

Теперь IRB такое же, как обычный скрипт работает в толкователя, насколько используя $stdout так писать вывод в IRB к $stdout работает так же:

irb(main):001:0> $stdout 
#<IO:<STDOUT>> 
irb(main):002:0> $stderr 
#<IO:<STDERR>> 

И:

irb(main):003:0> $stdout.puts 'foo' 
foo 
nil 
irb(main):004:0> $stderr.puts 'foo' 
foo 
nil 

И наконец:

irb(main):007:0> $stdout.isatty 
true 
irb(main):008:0> $stdout.isatty 
true 

Мы не можем рассказать разницу, пока мы не посмотрим немного ниже; Они оба канала TTY, со стандартным STDOUT и номерами каналов Stderr:

irb(main):009:0> $stdout.fileno 
1 
irb(main):010:0> $stderr.fileno 
2 

Надеется, что помогает «splain его.


Я просто понял, что отчетность IRB о возвращаемом значении puts может сбивать с толку вас, заставляя вас думать, что STDOUT меняется. То, что возвращается nil, не имеет ничего общего с STDOUT или STDERR. Это потому, что puts возвращает ноль, о котором сообщается IRB.

+0

Отличный ответ! Я нашел это очень полезным. –

1

Причина, по которой происходит, заключается в том, что IRB вызывает проверку объекта после каждой операции.

Показать объект # инспектировать полную информацию:

http://ruby-doc.org/core-2.1.0/Object.html#method-i-inspect

Мы можем доказать это переопределение инспектировать так:

~ $ irb 
>> class Foo 
>> def inspect 
>> 'hi' 
>> end 
>> end 
=> nil 
>> foo = Foo.new 
=> hi 

Единственное, в вашем случае, удара $ STDOUT является результаты вашей команды puts.

Надеюсь, это поможет!

Смежные вопросы