Reputation: 1015
Suppose I have two modules:
module Test1
attr_accessor :a, :b
@a = 0.0
@b = 0.0
end
module Test2
attr_accessor :c, :d
@c = 0.0
@d = 0.0
end
Now, I want to conditionally mix these modules into a class. This is what I've tried:
require './Test1.rb'
require './Test2.rb'
class MyClass
def initialize(mode)
if mode == 0
(class << self; include Test1; end)
elsif mode == 1
(class << self; include Test2; end)
else
class << self
include Test1
include Test2
end
end
end
end
This is the behavior I am seeing:
obj = MyClass.new(0)
obj.a #=> nil
Also @a
is nil
in instance methods within the class. I feel that I am not understanding something important here. I would like to understand why what I'm doing isn't working and also what the correct way to achieve my desired functionality is.
Upvotes: 7
Views: 3040
Reputation: 1015
I thought of a way to work around this problem, so I thought I'd share it. I'd still like to see if anyone knows of a better way to achieve what I was trying to.
Module Test1
attr_accessor :a, :b
def init1
@a = 0.0
@b = 0.0
end
end
class MyClass
def initialize
if mode == 0
(class << self; include Test1; end)
init1
elsif mode == 1
...
end
end
Upvotes: 2
Reputation: 51151
You have this behaviour because these instance variables you set in modules belong to modules themselves instead of belonging to MyClass
instances. Consider this code:
Test1.instance_variable_get(:@a)
# => 0.0
To solve this issue, you could use extend
instead of include
:
module Test1
attr_accessor :a, :b
def self.extended(object)
object.a, object.b = 0.0, 0.0
end
end
module Test2
attr_accessor :c, :d
def self.extended(object)
object.c, object.d = 0.0, 0.0
end
end
And in your class:
require './Test1.rb'
require './Test2.rb'
class MyClass
def initialize(mode)
if mode == 0
extend Test1
elsif mode == 1
extend Test2
else
extend Test1
extend Test2
end
end
end
Upvotes: 11