Rubyには、ファイルに書き出すと見せかけて文字列を生成する、StringIO
というクラスがあります。便利に使えるのですが、少しハマった箇所がありました。
StringIO
とは
まず、ファイルやパイプなどに対して読み書き、ファイル内の位置移動などを司るIO
というクラスがあります。読み書きを行うメソッドが、実際に出力する先をIO
で取るようにすれば、実際のアクセス先がどこであろうと利用可能です。
これに対して、StringIO
は、String
をIO
のインターフェースで扱えるようにしたものです。引数としてIO
を取るメソッドにStringIO
を渡せば、値を文字列として回収できます。
なお、StringIO
とIO
の間に継承関係はなく、ダックタイピングとして実装されています。
値の回収に失敗する例
ということで、StringIO
で値を取得しようとしたのですが、失敗したことがありました。
sio = StringIO.new
SomeAPI.download(key, output: sio)
data = sio.read
IO
だからread
すればいいと思ったのですが、これではdata
に取れる値は空文字列となってしまいます。
失敗の要因と改善策
失敗の要因ですが、StringIO
は現在の位置も記録しているので、追記を繰り返してStringIO
へ書き出した場合、位置が末端に来ています。そのままread
を行っても、すでに末端にいるので何も取れません。
もちろんrewind
してからread
でもいいのですが、そんなことをしなくても、StringIO#string
を使えばバッファとして持っている文字列をそのまま得ることができます。