リファクタリングRuby読書記録(6.20-8.3)

読んだ。

  • 委譲の隠蔽とその逆
  • 自己カプセル化フィールド
  • 値から参照へ

あたりがおもしろかった。フィールドアクセスについての派閥があるというのを初めて知った。クラス内では自由にフィールドにアクセスできるべき、という直接変数アクセス派とクラス内でも必ずgetter/setterを使うべきという間接変数アクセス派がある。自分は直接変数アクセスから始めるタイプだな。

リファクタリングRuby読書記録(6.9-6.19)

Rubyらしいテクニックが増えてきた。興味深かったのは以下4つ。

  • サンドイッチメソッドの抽出
  • クラスアノテーションの導入
  • 動的メソッド定義
  • 動的レセプタから動的メソッド定義へ

それぞれのテクニックを組み合わる手法もサンプルとして紹介されており、勉強になった。

Rubyでstdoutl/errを標準出力/エラーとファイルの両方に出力する

stdout/stderrをファイルにも出力したくていろいろ調べて、いい感じの解決方法を見つけたのでメモしておく。

ruby-listにmatzが投稿していた(Re: puts,printの出力をファイルにも出力するには)。

これを実行すると、こうなる。

defout = Object.new
defout.instance_eval{@ofile=open("/tmp/test.log", "w")}
class <<defout
  def write(str)
    STDOUT.write(str)
    @ofile.write(str)
  end
end
$stdout = defout

puts 'aaa'
$ ruby ./test.rb
aaa
$ cat ./test.log
aaa

なるほど、標準出力と標準エラーにputsされている。便利。

これができると、次はstdoutとstderrの両方をファイルにも出力したくなる。その場合はこうしちゃえばいい。

defout = Object.new
defout.instance_eval{@ofile=open("/tmp/test.log", "a")}
class <<defout
  def write(str)
    STDOUT.write(str)
    @ofile.write(str)
    @ofile.flush
  end
end
$stdout = defout

deferr = Object.new
deferr.instance_eval{@ofile=open("/tmp/test.log", "a")}
class <<deferr
  def write(str)
    STDERR.write(str)
    @ofile.write(str)
    @ofile.flush
  end
end
$stderr = deferr

puts 'aaa'
warn 'bbb'
puts 'ccc'
$ ruby ./test.rb
aaa
bbb
ccc
$ cat ./test.log
aaa
bbb
ccc

flushしないとtest.logにstdoutが先に全て出力され、その後にstderrが出力されてしまうようだ。また、この方法だとsystemのような子プロセスの出力はteeされないので注意しないといけない。