Given a Module Foo
, I would like to extend this module, but not preserve the module name Foo
.
# sscce (irb)
module Foo
class Foo; end
end
module Bar
include Foo
end
> Foo::Foo
Foo::Foo
> Bar.ancestors
[Bar, Foo]
> Bar::Foo
Foo::Foo
How can I get Bar::Foo
to be Bar::Foo
(not Foo::Foo
) without redefining the class?
I've attempted include
and prepend
as well as include Foo.clone
with the same result. I think it's safe to assume that it's referencing the original class definition, fine, but I'd still like to have the class Foo
actually belong to Bar
.
CodePudding user response:
maybe something like this could work?
module Foo
class Foo
def foo
puts "inside: #{self.class}"
end
end
end
module Bar
class Foo < ::Foo::Foo; end
end
now when you do:
a = Foo::Foo.new
a.foo # inside: Foo::Foo
and if you do
b = Bar::Foo.new
b.foo # inside: Bar::Foo
instead of trying to include/extend Foo
in a tricky way just create a new class inside the Bar
module and rely on inheritance?
CodePudding user response:
You cannot make a class belong to a module by inclusion. Even more - a class doesn't belong to a module even without inclusion (only a reference to a class is available as a module constant). When you import Foo
to Bar
, you bring there the constants and instance methods from Foo
, that's why you have access to Foo::Foo
by using the Bar::Foo
constant and it points to the uniquely identified class Foo::Foo
.
If you want to have the class Bar::Foo
, it will be a different class uniquely identified by this "address". And if you want to have it identical to Foo::Foo
, you'll have to use the included
hook in module Foo
and then do some heavy metaprogramming stuff to create a new class from the old one and assign it to a constant with the same name from the new module.
Or, maybe it could be enough just to clone the class:
module Foo
class Foo; end
def included(mod)
mod.const_set('Foo', self::Foo.clone)
end
end
module Bar
include ::Foo
end
obj1 = Foo::Foo.new
obj2 = Bar::Foo.new
Foo::Foo == Bar::Foo # false
But I'm not sure if cloning is enough for all the cases.