TL;DR
- Pryで
Tempfile
オブジェクトを評価すると、File
と表示される - これはPryのデフォルトインスペクタがppであり、
Tempfile
クラスがprint_pretty
の処理をFile
クラスに移譲しているから
現象
PryでTempfile
オブジェクトを作って評価すると、File
と表示される。
[1] pry(main)> f = Tempfile.new
=> #<File:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1401-kvolc2>
もちろんTempfile
クラスはFile
クラスではなく、inspect
するとちゃんとTempfile
と表示される
[2] pry(main)> f.inspect
=> "#<Tempfile:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1401-kvolc2>"
そもそもTempfile
クラスはFile
クラスとis aの関係にない。
[3] pry(main)> f.is_a?(File)
=> false
irbではこのようなことは起きない。
irb(main):001:0> require "tempfile"
=> true
irb(main):002:0> f = Tempfile.new
=> #<Tempfile:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1422-in132m>
原因
TL;DRにも書いたが、原因はPryのデフォルトインスペクタがppであり、ppがオブジェクトのpretty_print
を要求するが、Tempfile
がFile
のDelegateClassになっており、inspect
は自前で持っているが、pretty_print
は持っていないので、その処理をFile
に移譲してしまうから。
従って、irbでもデフォルトインスペクタをppにすると同じことが起きる。
$ irb --inspect pp
irb(main):001:0> require "tempfile"
=> true
irb(main):002:0> f = Tempfile.new
=> #<File:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1493-fvvhrn>
irb(main):003:0>
逆に、Tempfile
にpretty_print
を実装すればPryでもこの問題は起きない。
[1] pry(main)> f = Tempfile.new # Fileと表示される
=> #<File:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1501-1z0rdk5>
[2] pry(main)> class Tempfile
[2] pry(main)* def pretty_print(q) # Tempfileクラスにpretty_printを追加
[2] pry(main)* q.text inspect
[2] pry(main)* end
[2] pry(main)* end
=> :pretty_print
[3] pry(main)> f # Tempfileと表示される
=> #<Tempfile:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1501-1z0rdk5>
[4] pry(main)>
また、Pryのデフォルトインスペクタをsimpleにしてもこの問題は起きない。
[1] pry(main)> f = Tempfile.new
=> #<File:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1569-1sbfpbu>
[2] pry(main)> f # デフォルトではFileと評価される
=> #<File:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1569-1sbfpbu>
[3] pry(main)> change-inspector simple
Switched to the 'simple' inspector!
[4] pry(main)> f # simpleインスペクタではTempfileと評価される
#<Tempfile:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1569-1sbfpbu>
まとめ
ちょっとTempfileについて調べてたらPryの変な挙動を見つけたのでまとめてみた。Tempfile
だけでなく、inpsect
は実装しているがpretty_print
は実装されていないDelegateClass全般で同じ問題がおきるはず。一番まっとうな解決策はrequire "pp"
されたときに、Tempfile
にpretty_print
メソッドを追加することなんだろうけど、特に実害も無いし、issue立てたりプルリクを作るほどでも無い気がする・・・?
その他
Pryのインスペクタにはもう一つ、clippedがある。これでTempfile
オブジェクトのinspectを評価するとString
になってしまう。
[1] pry(main)> f = Tempfile.new
=> #<File:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1591-1uujsu6>
[2] pry(main)> f.inspect # デフォルトインスペクタではTempfileと表示される
=> "#<Tempfile:/var/folders/5x/jy4d20b97jgcsgf4mt7dwwqr0000gn/T/20180808-1591-1uujsu6>"
[3] pry(main)> change-inspector clipped
Switched to the 'clipped' inspector!
[4] pry(main)> f.inspect # clippedインスペクタではStringと表示されてしまう。
#<String:0x7fe23d102710>
[5] pry(main)>
これは、Pryのclippedインスペクタが、60文字を超えるとオブジェクトのクラス名+IDを表示する仕様だから。
[1] pry(main)> change-inspector clipped
Switched to the 'clipped' inspector!
[2] pry(main)> "X"*58
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
[3] pry(main)> "X"*59
#<String:0x7ff6a60a5c18>
[4] pry(main)>
そういう仕様だと言われたらそうなんだけど、Tempfile
オブジェクトをinspectした結果が「String」とか言われたらちょっとびっくりしない?