So I’m trying to figure out how I can allow an end user to decide which
modules to mixin to a instance of a class, but I’m not sure if it’s
possible. An example of what I would like.
module Thing
@bar = 5
end
class Foo
def initialize
@bar = 0
@foo = 2
end
end
class FooBar < Foo
def initialize(*modules)
@bar = 1
modules.each do |module_name|
eval(“include #{module_name.to_s.capitalize}”)
end
end
end
test = FooBar.new(:thing)
In the previous example, test would be an instance of FooBar, and it’s
@bar would be 5 (from the module Thing), and it’s @foo would be 2, from
it’s superclass. Is that possible? The previous returns a nomethoderror
for “include” in the instance of test. And it might have several other
errors since I just typed it up.
On Wednesday 29 July 2009 12:34:30 Ch Ba wrote:
@bar = 0
end
end
test = FooBar.new(:thing)
In the previous example, test would be an instance of FooBar, and it’s
@bar would be 5 (from the module Thing), and it’s @foo would be 2, from
it’s superclass. Is that possible? The previous returns a nomethoderror
for “include” in the instance of test. And it might have several other
errors since I just typed it up.
module Thing
def bar
5
end
end
class Foo
attr_reader :bar
attr_reader :foo
def initialize
@bar = 0
@foo = 2
end
end
class FooBar < Foo
def initialize(*modules)
super()
@bar = 1
modules.each do |module_name|
klass = Kernel.const_get(module_name)
extend klass
end
end
end
test = FooBar.new(:Thing)
puts test.bar
puts test.foo
Not exactly what you are looking for, but close.
On 30.07.2009 00:16, spox wrote:
On Wednesday 29 July 2009 12:34:30 Ch Ba wrote:
So I’m trying to figure out how I can allow an end user to decide which
modules to mixin to a instance of a class, but I’m not sure if it’s
possible. An example of what I would like.
module Thing
@bar = 5
end
This does not work as it defines a member of module Thing with value 5.
You would rather need something like this:
module Thing
attr_writer :bar
def bar
@bar ||= 5
end
end
But this does not solve the initialization problem. For that you need a
bit more complex logic (see below).
modules.each do |module_name|
for “include” in the instance of test. And it might have several other
attr_reader :foo
modules.each do |module_name|
Not exactly what you are looking for, but close.
I believe what OP wants can be achieved doing something like this
(untested):
module Thing
attr_acessor :bar
def initialize
# deliberately no super here
self.bar = 5
end
end
class FooBar
def initialize(*modules)
super()
@bar = 1
modules.each do |mod|
extend mod
begin
mod.instance_method(:initialize).bind(self).call()
rescue NameError
# ignore
end
end
end
end
test = FooBar.new(Thing)
puts test.bar
puts test.foo
Kind regards
robert
On 30.07.2009 16:21, Brian C. wrote:
def self.extended(obj)
obj.instance_eval do
@bar = 5
end
end
end
That’s a nice idea to use #extended!
@bar = 1
Thing, then you can use Object.const_get as others have pointed out. Or
build a hash:
ALLOWED_MODULES = {
:thing => Thing,
}
…
extend ALLOWED_MODULES[mod]
May I suggest to use #fetch in that case - the error might be a bit more
telling.
Kind regards
robert
Ch Ba wrote:
The previous returns a nomethoderror
for “include” in the instance of test.
Use “extend” rather than “include” if you want to add a module to a
single object, rather than to a class.
I think this does what you want:
module Thing
def self.extended(obj)
obj.instance_eval do
@bar = 5
end
end
end
class Foo
def initialize
@bar = 0
@foo = 2
end
end
class FooBar < Foo
def initialize(*modules)
super()
@bar = 1
modules.each do |mod|
extend mod
end
end
end
test = FooBar.new(Thing)
p test
If you want to pass a symbol like :thing instead of the actual module
Thing, then you can use Object.const_get as others have pointed out. Or
build a hash:
ALLOWED_MODULES = {
:thing => Thing,
}
…
extend ALLOWED_MODULES[mod]
Robert K. wrote:
ALLOWED_MODULES = {
:thing => Thing,
}
…
extend ALLOWED_MODULES[mod]
May I suggest to use #fetch in that case - the error might be a bit more
telling.
Yes, that’s a good idea. I’m in the habit of writing things like
extend(ALLOWED_MODULES[mod] || (raise “Unknown module
#{mod.inspect}”))
but I thought that might clutter the sample code in this case. I always
forget about Hash#fetch.
Another way is:
ALLOWED_MODULES = Hash.new { raise “Oi!” }
ALLOWED_MODULES.merge!({
… etc
})