@m_seki の

I like ruby tooから引っ越し

文字列からクラス/モジュールへの変換のイディオムで

文字列で表現されたクラス/モジュールを、class/moduleに変換するイディオムにこういうのありますよね。

def get_class(klass)
  klass.split(/::/).inject(Object) { |c, n| c.const_get(n) }
end

実験するとこう。

$ irb
>> def foo(klass)
>> klass.split(/::/).inject(Object) { |c, n| c.const_get(n) }
>> end
=> nil
>> module A; module B; module C; end; end; end
=> nil
>> foo('A::B::C')
=> A::B::C

見つかるケースではうまく動くんだけど、見つからなくて、かつ、同じ名前がルートにあるとき、期待しない結果となります。

>> foo('A::B::C::A')
=> A

がぼん。

これはこういうことでした。

>> Object.const_get('A').const_get('B').const_get('C')
=> A::B::C
>> Object.const_get('A').const_get('B').const_get('C').const_get('A')
=> A

それで、なにが言いたいかというと、auto_link.rbAmazonよりも先にASINが処理されると、ルートにAmazonが定義されるので失敗しちゃうのです。

こんな風に直すとうまくいくようになりました。もっとていねいに例外があげられるかもしれないけど。

      def get_class(str)
        it = str.split(/::/).inject(Object) do |klass, s|
          klass.const_get(s)
        end
        raise NameError unless it.name == str
        it
      end