定数STDOUTとグローバル変数$stdout、そしてRubyの出力のバッファリング(loggerとかで厄介)

結論を先に:STDOUTは定数だから変更しない方が良いです。
あと、Loggerクラスを使ってログを出力する場合には

$stdout.sync = true

しておいたほうが良いです。

STDOUTと$stdoutの違い

Kernelモジュール>特殊変数
variable $>

$> -> object

$stdout -> object

標準出力です。
組み込み関数 Kernel.#print、Kernel.#puts や Kernel.#p などのデフォルトの出力先となります。 初期値は Object::STDOUT です。 コマンドラインオプションオプション -i を指定した場合には 読み込み元と同じ名前のファイルを表します。
$stdout に代入するオブジェクトには write という名前のメソッドが定義されていなければいけません。
自プロセスの標準出力をリダイレクトしたいときには、 以下のように $stdout に代入すれば十分です。
variable $> (Ruby 1.9.3)

In Ruby, what is the difference between $stdout (preceded by a dollar sign) and STDOUT (in all caps)? When doing output redirection, which should be used and why? The same goes for $stderr and STDERR.

$stdout is a global variable that represents the current standard output. STDOUT is a constant representing standard output and is typically the default value of $stdout.
With STDOUT being a constant, you shouldn't re-define it, however, you can re-define $stdout without errors/warnings (re-defining STDOUT will raise a warning).

  • STDOUT is a global constant, so it should not be changed
  • $stdout is a predefined variable, so it can be changed.

If you are using the shell to do redirection, for example:

$ ruby test.rb > test.log

Then it doesn't matter which one you use as the file descriptor for your script is being determined before your script is executed.
However, if you are trying to change the file descriptor for stdout from within your Ruby script, for example to send output to a rotating set of log files based on the current day of the week, then you'll want to make sure you use $stdout

Difference between $stdout and STDOUT in Ruby - Stack Overflow

「定数」を復習する

定数

例:

FOOBAR

アルファベット大文字 ([A-Z]) で始まる識別子は定数です。 定数の定義 (と初期化) は代入によって行われますが、メソッドの中では定義できません。一度定義された定数に再び代入を行おうとすると警告メッセージが出ます。定義されていない定数にアクセスすると例外 NameError が発生します。
定数はその定数が定義されたクラス/モジュール定義の中(メソッド本体やネストしたクラス/モジュール定義中を含みます)、クラスを継承しているクラス、モジュールをインクルードしているクラスまたはモジュールから参照することができます。クラス定義の外(トップレベル)で定義された定数は Object に所属することになり ます。
変数と定数 (Ruby 1.9.3)

ポイント:

  • 一度定義された定数に再び代入を行おうとすると警告メッセージが出ます。が、代入できます。
  • 定数の定義 (と初期化) は代入によって行われますが、メソッドの中では定義できません。クラス/モジュールまたはトップレベルで定義します。

標準出力をバッファリングしないようにするときはSTDOUT.sync = trueではなく$stdout.sync = trueしたほうがいい?

IO#syncとは

instance method IO#sync

sync -> bool

現在の出力が同期モードならば true を返します。そうでない場合は false を返します。

ではIO#sync=は

instance method IO#sync=

sync=(newstate)

自身を同期モードに設定すると、出力関数の呼出毎にバッファがフラッシュされます。
[PARAM] newstate:
自身を同期モードに設定するかを boolean で指定します。

ということで、$stdout.sync = true すると標準出力がバッファリングされずに随時出力されます。

STDOUT.sync = true と $stdout.sync = true の違いを確認してみる
pry(main)> $stdout.class
=> IO
pry(main)> STDOUT.sync
=> false
pry(main)> $stdout.sync
=> false
pry(main)> $stdout.sync = true
=> true
pry(main)> STDOUT.sync
=> true
pry(main)> STDOUT.sync
=> false
pry(main)> STDOUT.sync = true
=> true
pry(main)> $stdout.sync
=> true

……一緒でしたw

結論

STDOUT自身を変更するのではないので、STDOUT.sync = trueでも問題は無いようですが、でも定数を触るよりも、定数を初期値としている変数を触った方が良さそうに感じます。