OpenStruct のコードリーディング(Ruby)

~/Documents/Ruby/コードリーディング/ostruct.rb の一部

class OpenStruct
  def initialize(hash=nil)
    #Hash{@table}
    @table = {}
    if hash
      hash.each_pair do |k, v|
        k = k.to_sym
        @table[k] = v
      end
    end
  end
  attr_reader :table
  
  def modifiable
    #@modifiable >> Hash{@table}
    begin
      @modifiable = true    #@modefiable は他に出てこない。
    rescue
      raise RuntimeError, "can't modify frozen #{self.class}", caller(3)
    end
    @table
  end
  protected :modifiable
  
  def new_ostruct_member(name)
    #String{name} -> Symbol{name} >> Symbol{name}
    name = name.to_sym
    unless singleton_class.method_defined?(name)    #特異メソッドが定義されていなければ定義する。Object#singleton_class
      define_singleton_method(name) { @table[name] }
      define_singleton_method("#{name}=") { |x| modifiable[name] = x }
    end
    name
  end
  protected :new_ostruct_member
  
  def method_missing(mid, *args)    # mid は呼び出しに失敗したメソッド名
   #Symbol{mid}, *args -> len, mname, err >> Object{args[0] or @table[mid]}
    len = args.length
    if mname = mid[/.*(?==\z)/m]    #「=」で終わる文字列のその前の部分を取り出す。正規表現の「(?=pat)」は「肯定先読み」なんだって。「m」は「.」が改行にもマッチするようにする。
      if len != 1
        raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)    #Kernel.#caller
      end
      modifiable[new_ostruct_member(mname)] = args[0]    #@table に args[0] を入れる。またそれが返り値。
    elsif len == 0
      if @table.key?(mid)
        new_ostruct_member(mid)
        @table[mid]
      end
    else
      err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
      err.set_backtrace caller(1)
      raise err
    end
  end
  
  def [](name)
    @table[name.to_sym]
  end
  
  def []=(name, value)
    modifiable[new_ostruct_member(name)] = value
  end
end

 
正規表現の「(?=pat)」については以下。
正規表現 (Ruby 2.3.0)
先読みを使ったパターン - 先読み - Ruby正規表現の使い方