文字列で表現されたクラス/モジュールを、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.rbでAmazonよりも先に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