[ruby-list:50875] Re: パス名なのかIO(っぽい)オブジェクトなのかを検出する方法

From: Tadashi Saito <tad.a.digger@...>
Date: 2020-02-21 12:08:57 UTC
List: ruby-list #50875
斎藤と申します。

> ・StringやPathnameなど、パス名(っぽい)場合は、File.openして読み書きする

「パス名」は文字列のはずなので、respond_to?(:to_str)とか:to_sで
場合分けするのはどうでしょうか?
少なくともIO, StringIOにはないメソッドのようでした。

別のやり方として、「IOっぽい」という判定にrespond_to?(:pos)を追加するのもありかもしれません。
ただこちらは、あまり調べていません。

--
斎藤 匡


2020年2月20日(木) 13:58 Tietew <tietew@tietew.net>:

> 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