如何获取通过attr_reader或attr_accessor定义的属性

use*_*942 20 ruby metaprogramming

假设我有一堂课 A

class A
  attr_accessor :x, :y

  def initialize(x,y)
    @x, @y = x, y
  end
end
Run Code Online (Sandbox Code Playgroud)

如何在不知道它们的确切名称的情况下获取xy归属.

例如

a = A.new(5,10)
a.attributes # => [5, 10]
Run Code Online (Sandbox Code Playgroud)

Ser*_*sev 32

使用内省,卢克!

class A
  attr_accessor :x, :y

  def initialize(*args)
    @x, @y = args
  end

  def attrs
    instance_variables.map{|ivar| instance_variable_get ivar}
  end
end

a = A.new(5,10)
a.x # => 5
a.y # => 10
a.attrs # => [5, 10]
Run Code Online (Sandbox Code Playgroud)

  • 注意:attrs将返回*all*实例变量,而不仅仅是`attr_accessor`所暴露的变量 (3认同)
  • @Jonah:是的,那是当时的假设。更精确的方法可以参考[这个答案](http://stackoverflow.com/a/34440466/125816)。 (2认同)

Nic*_*fon 14

虽然塞尔吉奥的答案有所帮助,但它会返回所有实例变量,如果我理解OP的问题,那就不是问了什么.

如果你只想返回有例如mutator的'属性',你必须做一些稍微复杂的事情,例如:

attrs = Hash.new
instance_variables.each do |var|
  str = var.to_s.gsub /^@/, ''
  if respond_to? "#{str}="
    attrs[str.to_sym] = instance_variable_get var
  end
end
attrs
Run Code Online (Sandbox Code Playgroud)

这仅返回使用attr_accessor(或使用手动创建的mutator)声明的属性,并保持内部实例变量隐藏.如果你想要用attr_reader声明的那些,你可以做类似的事情.


mar*_*ers 9

class A
  ATTRIBUTES = [:x, :y]
  attr_accessor *ATTRIBUTES

  def initialize(x,y)
    @x, @y = x, y
  end

  def attributes
    ATTRIBUTES.map{|attribute| self.send(attribute) }
  end
end
Run Code Online (Sandbox Code Playgroud)

这可能不是DRY-est,但是如果你只关心为一个类做这个(而不是一切继承自的基类),那么这应该有效.