廃止されるかもしれないautoloadの代わりを用意する

Rubyのautoloadは廃止されるかもしれないので、代わりの方法を用意しておきたい。

Rubyにはconst_missingというヤバいメソッドがある。このメソッドは未定義の定数にアクセスした時、NameErrorが発生する前に処理をフックする事ができる。superを呼べばそのままNameErrorがraiseされ、値を返せば、それが未定義定数の値として使用されるのだ。Rubyにはこういう悪魔のような邪悪なメソッドがしれっと用意されているので恐ろしい…

このconst_missingの中で必要なファイルをrequireし、const_getで取得できなかった定数を取得して返せばautoloadの代わりになりそうだ。

# autoloader.rb

require "set"

module AutoLoader

  def auto_require hash
    @autoloading = hash
  end

  def const_missing const
    @missing_const ||= Set.new

    if @missing_const.include? const
      super
    end
    @missing_const.add const

    file = @autoloading[const]
    if file.nil?
      super
    end

    require file

    const_get(const)
  end
end

const_getで定数が取得できないとまたconst_missingが呼ばれ無限再帰してしまうので、その対策も忘れずに。

自動ロードされるhoge.rbにはTest::Hogeクラスの定義を書いておく

# hoge.rb

class Test::Hoge
  def to_s
    "test_hoge"
  end
end

自動ロードする側はextendして機能をクラスに取り込む。

# main.rb

require "./autoloader"

class Test
  extend AutoLoader
  
  auto_require :Hoge => "./hoge.rb", :Fuga => "./fuga.rb"

  def get_hoge
    Hoge.new
  end
end

puts Test.new.get_hoge

これを実行してみると…

$ ruby main.rb
test_hoge

できた。

これが必要になる日は来るのでしょうか?