不同命名空间继承问题:如何获取应用命名空间实例?
I've built a custom gem with the following code:
module GemNamespace class Foo; end class Bar def foo @foo ||= Foo.new end end end
In my application, I'm subclassing these gem classes under my own namespace:
module ApplicationNamespace class Foo < GemNamespace::Foo; end class Bar < GemNamespace::Bar; end end
When I call the foo method on my application's Bar instance, it spits out a GemNamespace::Foo object instead of my desired ApplicationNamespace::Foo:
bar = ApplicationNamespace::Bar.new puts bar.foo => #<GemNamespace::Foo:0x007f849d8169f0>
I want to get an instance of ApplicationNamespace::Foo instead, without having to override the foo method in my application's Bar class. How can I make this work?
The Fix: Use Dynamic Constant Lookup in the Gem
The root issue here is that the gem's Bar#foo method is hardcoding Foo.new, which Ruby resolves to GemNamespace::Foo because the method lives inside the GemNamespace module. To make this method play nicely with subclasses, we just need to adjust how it references the Foo class—making it dynamic instead of static.
Update your gem's Bar class to use one of these approaches:
Option 1: Use Class Namespace Resolution
module GemNamespace class Foo; end class Bar def foo @foo ||= self.class::Foo.new end end end
Option 2: Explicitly Fetch the Constant
module GemNamespace class Foo; end class Bar def foo @foo ||= self.class.const_get(:Foo).new end end end
Why This Works
When you create an instance of ApplicationNamespace::Bar, self inside the foo method points to that instance. So self.class returns ApplicationNamespace::Bar.
Ruby's constant lookup rules will then:
- First check if
ApplicationNamespace::Barhas its ownFooclass (it doesn't in your case) - Traverse up to the enclosing namespace
ApplicationNamespace, where it finds yourApplicationNamespace::Fooclass
This way, the method automatically uses the correct Foo subclass based on the instance's actual class—no overrides needed in your application code.
内容的提问来源于stack exchange,提问作者kudrin

