在 class 定义中使用方法参数 (Ruby)
Use method arguments inside class definition (Ruby)
我正在尝试向所有对象添加一个方法,该方法允许动态向实例添加变量。但是,我有 运行 问题,当我开始 class
块时,方法参数超出范围,因此不再可用。
如何从 class
块中访问方法参数?或者有更好的方法吗?
class Object
def addvar(name, value = nil)
puts name # => "test"
class << self
puts name # => returns nil!
attr_accessor name # => nil is not a symbol nor a string (TypeError)
end
self.instance_variable_set("@" + name.to_s, value)
end
end
x = Object.new
x.addvar("test", 3)
也可以将 eval 与字符串替换一起使用,但出于安全原因,我宁愿避免这样做:
class Object
def addvar(name, value = nil)
eval("class << self
attr_accessor :#{name}
end
self.#{name} = #{value}")
end
end
x = Object.new
x.addvar(:test, 3)
puts x.test
您可能需要 instance_variable_set
, instance_variable_get
和 Ruby 中的其他元编程方法。老实说,这就是 attr_accessor
在幕后使用的东西。
以下代码通过使用 define_singleton_method
:
向调用 add_var
方法的对象添加单例方法
class Object
def addvar(name, value = nil)
instance_name = "@#{name}"
instance_variable_set(instance_name, value)
define_singleton_method(name) do
instance_variable_get(instance_name)
end
define_singleton_method("#{name}=") do |new_value|
instance_variable_set(instance_name, new_value)
end
end
end
x = Object.new
x.addvar("test1", 3)
p x.test1
p Object.new.test1
=> 3
=> 1.rb:20:in `<main>': undefined method `test1' for #<Object:0x007fc98b161e10> (NoMethodError)
如果要为 class 的任何对象声明方法,可以在 class 上使用 define_method
:
class Object
def addvar(name, value = nil)
instance_name = "@#{name}"
instance_variable_set(instance_name, value)
self.class.send(:define_method, name) do
instance_variable_get(instance_name)
end
self.class.send(:define_method, "#{name}=") do |new_value|
instance_variable_set(instance_name, new_value)
end
end
end
x = Object.new
x.addvar("test1", 3)
p x.test1
p Object.new.test1
=> 3
=> nil
顺便说一下,你仍然可以使用 attr_accessor
,你可以在 class 对象上调用它:
class Object
def addvar(name, value = nil)
instance_variable_set("@#{name}", value)
self.class.send(:attr_accessor, name)
end
end
x = Object.new
x.addvar("test1", 3)
p x.test1
x.test1 = 5
p x.test1
p Object.new.test1
我正在尝试向所有对象添加一个方法,该方法允许动态向实例添加变量。但是,我有 运行 问题,当我开始 class
块时,方法参数超出范围,因此不再可用。
如何从 class
块中访问方法参数?或者有更好的方法吗?
class Object
def addvar(name, value = nil)
puts name # => "test"
class << self
puts name # => returns nil!
attr_accessor name # => nil is not a symbol nor a string (TypeError)
end
self.instance_variable_set("@" + name.to_s, value)
end
end
x = Object.new
x.addvar("test", 3)
也可以将 eval 与字符串替换一起使用,但出于安全原因,我宁愿避免这样做:
class Object
def addvar(name, value = nil)
eval("class << self
attr_accessor :#{name}
end
self.#{name} = #{value}")
end
end
x = Object.new
x.addvar(:test, 3)
puts x.test
您可能需要 instance_variable_set
, instance_variable_get
和 Ruby 中的其他元编程方法。老实说,这就是 attr_accessor
在幕后使用的东西。
以下代码通过使用 define_singleton_method
:
add_var
方法的对象添加单例方法
class Object
def addvar(name, value = nil)
instance_name = "@#{name}"
instance_variable_set(instance_name, value)
define_singleton_method(name) do
instance_variable_get(instance_name)
end
define_singleton_method("#{name}=") do |new_value|
instance_variable_set(instance_name, new_value)
end
end
end
x = Object.new
x.addvar("test1", 3)
p x.test1
p Object.new.test1
=> 3
=> 1.rb:20:in `<main>': undefined method `test1' for #<Object:0x007fc98b161e10> (NoMethodError)
如果要为 class 的任何对象声明方法,可以在 class 上使用 define_method
:
class Object
def addvar(name, value = nil)
instance_name = "@#{name}"
instance_variable_set(instance_name, value)
self.class.send(:define_method, name) do
instance_variable_get(instance_name)
end
self.class.send(:define_method, "#{name}=") do |new_value|
instance_variable_set(instance_name, new_value)
end
end
end
x = Object.new
x.addvar("test1", 3)
p x.test1
p Object.new.test1
=> 3
=> nil
顺便说一下,你仍然可以使用 attr_accessor
,你可以在 class 对象上调用它:
class Object
def addvar(name, value = nil)
instance_variable_set("@#{name}", value)
self.class.send(:attr_accessor, name)
end
end
x = Object.new
x.addvar("test1", 3)
p x.test1
x.test1 = 5
p x.test1
p Object.new.test1