Reputation: 1387
I'm trying to dynamically create a set of classes as follows.
class Foo
attr_reader :description
end
['Alpha', 'Beta', 'Gamma'].each do |i|
klass = Class.new(Foo) do |i|
def initialize
@description = i
end
end
Object.const_set(i, klass)
end
rather than creating each class manually, e. g.:
class Alpha < Foo
def initialize
@description = 'Alpha'
end
end
What is the right way to do such a thing and how do I pass an iterator to a nested block?
Upvotes: 3
Views: 120
Reputation: 48589
how do I pass an iterator to a nested block?
By using a nested block. A def is not a block. A def cuts off the visibility of variables outside the def. A block on the other hand can see the variables outside the block:
class Foo
attr_reader :description
end
['Alpha', 'Beta', 'Gamma'].each do |class_name|
klass = Class.new(Foo) do
define_method(:initialize) do
@description = class_name
end
end
Object.const_set(class_name, klass)
end
a = Alpha.new
p a.description
--output:--
"Alpha"
You can also do what you want without having to create a nested block or the class Foo:
['Alpha', 'Beta', 'Gamma'].each do |class_name|
klass = Class.new() do
def initialize
@description = self.class.name
end
attr_reader :description
end
Object.const_set(class_name, klass)
end
--output:--
"Alpha"
"Gamma"
Upvotes: 1
Reputation: 12514
class Foo
attr_reader :description
end
['Alpha', 'Beta', 'Gamma'].each do |class_name|
eval %Q{
class #{class_name} < Foo
def initialize
@description = #{class_name}
end
end
}
end
On Execution:
Gamma.new.description
=> Gamma
Upvotes: 0
Reputation: 8467
You're close. I think you want to make description
a class instance variable (or possibly a class variable), rather than an instance variable. The description
will be "Alpha" for all objects of class Alpha
so it should be an attribute of the class. You would access it as Alpha.description
(or Alpha.new.class.description
). Here's a solution using a class instance variable:
class Foo
class << self
attr_reader :description
end
end
['Alpha', 'Beta', 'Gamma'].each do |i|
klass = Class.new(Foo)
klass.instance_variable_set(:@description, i)
Object.const_set(i, klass)
end
Upvotes: 1