23

假设我有一堂课A

class A
  attr_accessor :x, :y

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

在不知道它们的确切命名方式的情况下,我如何获取x和属性。y

例如

a = A.new(5,10)
a.attributes # => [5, 10]
4

6 回答 6

36

使用内省,卢克!

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]
于 2012-04-04T07:46:40.480 回答
16

虽然 Sergio 的回答有帮助,但它会返回所有实例变量,如果我正确理解 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

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

于 2014-03-02T18:38:31.890 回答
13
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

这可能不是 DRY-est,但如果您只关心为一个类执行此操作(而不是所有东西都继承自的基类),那么这应该可行。

于 2016-08-11T07:12:22.253 回答
3

请参阅其他堆栈溢出问题。他们覆盖attr_accessor.

  def self.attr_accessor(*vars)
    @attributes ||= []
    @attributes.concat vars
    super(*vars)
  end

  def self.attributes
    @attributes
  end

  def attributes
    self.class.attributes
  end
于 2014-03-20T17:28:06.640 回答
2

如果您在属性上定义了attr_writers/ attr_accessors,则可以通过匹配正则=$表达式轻松检索它们:

A.instance_methods.each_with_object([]) { |key, acc| acc << key.to_s.gsub(/=$/, '') if key.match(/\w=$/) }

或者

A.instance_methods.each_with_object([]) { |key, acc| acc << key if key = key.to_s.match(/^(.*\w)=$/)&.[](1) }
于 2017-12-29T15:11:25.353 回答
1

当您使用 attr_accessor 在类中定义属性时,Ruby 使用 refexion 定义了几个方法,对于声明的每个属性,一个获取值,另一个设置,一个与属性同名的实例变量

你可以看到这个方法使用

p A.instance_methods

[:x, :x=, :y, :y=, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?,..

所以这个属性是可访问的,在类之外,有

p "#{a.x},#{a.y}"

或者类内部通过对应的实例变量

class A
  ...
  def attributes
    [@x,@y]
  end
  ...
end
p a.attributes   #=> [5,10]
于 2012-04-04T15:15:13.253 回答