一般的なメソッドをモジュールまたはクラスに移動し、別のモジュールで名前空間が設定されている新しいクラスに含める/継承することで、ドライにしようとしています。同じモジュールの下に 2 つのクラスの名前空間がある場合、同じ名前空間の下にある限り、モジュール名を含めずにそれらを呼び出すことができます。しかし、名前空間スコープの変更とは異なるモジュールからメソッドが含まれている場合、それを回避する理由や方法がわかりません。
例えば。このコードは機能し、「バー」を返します。
module Foo
class Bar
def test_it
Helper.new.foo
end
end
end
module Foo
class Helper
def foo
'bar'
end
end
end
Foo::Bar.new.test_it
しかし、メソッド test_it をモジュールに移動すると、もう機能しません: NameError: uninitialized constant Mixins::A::Helper.
module Mixins; end
module Mixins::A
def self.included(base)
base.class_eval do
def test_it
Helper.new.foo
end
end
end
end
module Foo
class Bar
include Mixins::A
end
end
module Foo
class Helper
def foo
'bar'
end
end
end
Foo::Bar.new.test_it
さらに、class_eval がブロックではなく文字列を評価している場合、スコープは Foo ではなく Foo::Bar になります。
module Mixins; end
module Mixins::A
def self.included(base)
base.class_eval %q{
def test_it
Helper.new.foo
end
}
end
end
module Foo
class Bar
include Mixins::A
end
end
module Foo
class Helper
def foo
'bar'
end
end
end
Foo::Bar.new.test_it
誰かがアイデアを持っていますか?
編集:
Wizard と Alex のおかげで、美しくはありませんが機能する次のコードになりました ( Rails ヘルパーの定数化を使用していることに注意してください)。
module Mixins; end
module Mixins::A
def self.included(base)
base.class_eval do
def test_it
_nesting::Helper
end
def _nesting
@_nesting ||= self.class.name.split('::')[0..-2].join('::').constantize
end
end
end
end
module Foo
class Helper
end
class Bar
include Mixins::A
end
end
module Foo2
class Helper
end
class Bar
include Mixins::A
end
end
Foo::Bar.new.test_it #=> returns Foo::Helper
Foo2::Bar.new.test_it #=> returns Foo2::Helper