LoginSignup
2
0

More than 5 years have passed since last update.

PryでTempfileオブジェクトを評価するとFileと表示される

Last updated at Posted at 2018-08-08

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を要求するが、TempfileFileの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> 

逆に、Tempfilepretty_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"されたときに、Tempfilepretty_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」とか言われたらちょっとびっくりしない?

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0