如何在对象上动态创建属性并将对象分配为其值? 我有以下代码:
class Component
def initialize
end
end
class BaseClass
def initialize
end
# define class methods
def self.create_component(**args)
# create attr_accessor with name "ball"
# set ball = Component.new
end
end
class ChildClass < BaseClass
create_component :name => "ball"
create_component :name => "baseball"
def initialize
end
end
我的目标是,当ChildClass调用“ create_component”方法时,这应创建一个具有:name参数中提供的名称的属性,并将该属性实例化为“ Component”对象。
object = ChildClass.new
object.ball #=> to return object reference (Component class 1)
object.baseball #=> to return object reference (Component class 2)
答案 0 :(得分:3)
您可以这样定义BaseClass:
class Component; end
class BaseClass
@@components = []
def initialize
@@components.each do |attr|
instance_variable_set("@#{attr}", Component.new)
end
end
def self.create_component(name:)
attr_reader name.to_sym
@@components << name
end
end
class ChildClass < BaseClass
create_component :name => "ball"
create_component :name => "baseball"
end
object = ChildClass.new
object.ball
# => #<Component:0x00007fa62fbdf3f8>
object.baseball
# => #<Component:0x00007fa62fbdf3a8>
基本上,您要做三件事:
@@components
,该变量存储自定义attr_reader
名称的列表create_component
内,调用attr_reader
创建方法并将其添加到@@components
列表中initialize
内,为每个@@components
设置初始值(如果愿意,您也可以使用initialize
自变量为其提供自定义值)。答案 1 :(得分:0)
您可以按照以下步骤进行操作。
class Component
end
class BaseClass
def create_component(name)
self.class.send(:attr_accessor, name)
instance_variable_set("@#{name}", Component.new)
end
end
class ChildClass < BaseClass
end
c = ChildClass.new
c.create_component "ball"
#=> #<Component:0x000056f36c73c2e0>
c.create_component"baseball"
#=> #<Component:0x000056f36c7533f0>
c.methods & [:ball, :baseball]
#=> [:ball, :baseball]
c.instance_variables
#=> [:@ball, :@baseball]
c.ball
#=> #<Component:0x000056f36c73c2e0>
c.baseball
#=> #<Component:0x00005602be1eb560>
c.ball = 1
c.ball
#=> 1
请注意
self.class.send(:attr_accessor, name)
可以替换为
self.class.class_eval { attr_accessor name.to_sym }
将实例变量添加到BaseClass
的子类的实例无关紧要。如果将它们添加到BaseClass
的实例中,基本上是相同的问题。
答案 2 :(得分:0)
这将创建一个实例方法,例如:
def baseball
@baseball ||= Component.new
end
对于baseball=
,它仅使用常规的attr_writer
:
class Component
end
class BaseClass
def self.create_component(name:)
class_eval <<~EOB
attr_writer :#{name}
def #{name}
@#{name} ||= Component.new
end
EOB
end
end
class ChildClass < BaseClass
create_component name: "ball"
create_component name: "baseball"
end
这似乎可行:
> c = ChildClass.new
> c.ball
=> #<Component:0x00007f8b270cfa58>
> c.baseball
=> #<Component:0x00007f8b270dbdd0>