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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With