Reputation: 571
My program has following structure:
module M1
class A
def action
C.new.foo
end
end
class C
def foo
puts "M1::C foo"
end
end
end
module M2
class A
def action
C.new.foo
end
end
class C
def foo
puts "M2::C foo"
end
end
end
As both M1::A
and M2::A
share same code, I've been thinking of putting common code inside separate class (or module) and inherit from it (include it). Something like this:
class ABase
def action
C.new.foo
end
end
module M1
class A < ABase
end
class C
def foo
puts "M1::C foo"
end
end
end
module M2
class A < ABase
end
class C
def foo
puts "M2::C foo"
end
end
end
However, when I tried, I've got into trouble with name resolution uninitialized constant ABase::C
. What is the proper way to achieve code sharing in this case?
Upvotes: 2
Views: 106
Reputation: 211610
Due to the way constants are resolved based on definition scope and not in inherited scopes you'll need to bridge that with a method call:
class ABase
def action
# Within this scope only constants defined in `ABase` are resolved.
# As ABase::C and ::C (root-level) don't exist, C can't be resolved.
# However, a method `c` defined in a subclass will be.
c.new.foo
end
end
module M1
class A < ABase
def c
C
end
end
class C
def foo
puts "M1::C foo"
end
end
end
module M2
class A < ABase
# This resolves C as either M2::A::C, M2::ABase::C, M2::C or ::C,
# whichever it finds first.
def c
C
end
end
class C
def foo
puts "M2::C foo"
end
end
end
Then you get the expected results:
M1::A.new.action
# => M1::C foo
M2::A.new.action
# => M2::C foo
Upvotes: 1