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を使えばバッファとして持っている文字列をそのまま得ることができます。