[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

In This Thread

Prev Next