[ruby-list:50874] パス名なのかIO(っぽい)オブジェクトなのかを検出する方法
From:
Tietew <tietew@...>
Date:
2020-02-20 04:49:29 UTC
List:
ruby-list #50874
Net::SFTPのPRで議論になったのですが、オブジェクトがIO(っぽい)なのかパス
名なのかを検出するいい方法は無いか? という問題です。
やりたいこと:
渡されたオブジェクトが、
・StringやPathnameなど、パス名(っぽい)場合は、File.openして読み書きする
・IOやStringIOなど、IO(っぽい)場合は、そのまま読み書きする
・(オプション)上記いずれでもない場合は適切な例外を投げる
該当のPR:
https://github.com/net-ssh/net-sftp/pull/102
経緯としては、Net::SFTPは転送ファイルがIOかどうか、respond_to?(:read/:write)
で調べてるのですが、これにPathnameを渡すと、Pathname#read/writeが存在す
るためにIOと判断してしまい、一見不可思議な挙動になることです。
書き込み時:
・バイナリをwriteしようとしてEncodingError
・チャンクを何度かwriteするので最後のチャンクしか書き込まれない
読み込み時:
・IO#posを呼ぼうとしてNoMethodError
で、#to_pathがあったらパス名としてto_pathを呼んでStringにしてしまおうと
したのが件のPRのところ、File#to_pathがあるためにファイルを再オープンして
しまうと指摘がありました。
それならば、Pathname#openがあることを利用して、
・openできればopen('wb')する
・#read/writeがあればそのまま
・さもなければ::File.openに渡す
にしようかと考えたところ、Tempfile#open()が存在するためにArgumentErrorに
なることが判明します。
今のところ、Pathnameオブジェクトだけ特別扱いする方法しか思いつかないのですが、
file = file.to_s if path.is_a?(Pathname)
何かいい方法はありますでしょうか?
--
Tietew <tietew@tietew.net>
Blog: http://www.tietew.jp/
PGP: 26CB 71BB B595 09C4 0153 81C4 773C 963A D51B 8CAA