OpenStruct の inspectの謎

言語処理系とかでpritty printを作ってる人にとっては、べつに謎でもなんでもないんだろうな。

このinspectは組み込みのpメソッドで出力するときに呼ばれるメソッド。OpenStructの場合はこれ。

  def inspect
    str = "#<#{self.class}"

    Thread.current[InspectKey] ||= []
    if Thread.current[InspectKey].include?(self) then
      str << " ..."
    else
      first = true
      for k,v in @table
        str << "," unless first
        first = false

        Thread.current[InspectKey] << v
        begin
          str << " #{k}=#{v.inspect}"
        ensure
          Thread.current[InspectKey].pop
        end
      end
    end

    str << ">"
  end

何でThread.currentを使っているのか、何でinclude?でselfがいるかどうかを調べているのかが1時間くらい考えてもわからなかった。
threadに何か関係するのか?とか、ぜんぜん違う見方をしていた。

このThread.currentは要素が入れ子になっているときのために使うものだった。同じスレッドで共有しているのでv.inspectのvが自分自身でも再帰がとまるって仕組み。標準のものはよくできてるなぁ。

irb(main):002:0> require "ostruct"
require "ostruct"
=> true
irb(main):003:0> a = OpenStruct.new
a = OpenStruct.new
=> #<OpenStruct>
irb(main):004:0> a
a
=> #<OpenStruct>
irb(main):005:0> a.name = "hoge"
a.name = "hoge"
=> "hoge"
irb(main):006:0> a
a
=> #<OpenStruct name="hoge">
irb(main):008:0> a.self = a
a.self = a
=> #<OpenStruct name="hoge", self=#<OpenStruct ...>>
irb(main):009:0>