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

假设我有一个A

 class A attr_accessor :x, :y def initialize(x,y) @x, @y = x, y end end 

如何在不知道它们的确切命名的情况下获取xy属性。

例如

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

使用内省,卢克!

 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) ax # => 5 ay # => 10 a.attrs # => [5, 10] 

虽然塞尔吉奥的答案有所帮助,但它将返回所有实例变量,如果我正确理解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声明的那些,你可以做类似的事情。

 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,但是如果你只关心为一个类做这个(而不是一切inheritance自的基类),那么这应该有效。

请参阅此其他Stack Overflow问题 。 它们覆盖了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 

当您使用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 "#{ax},#{ay}" 

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

 class A ... def attributes [@x,@y] end ... end p a.attributes #=> [5,10] 

如果您在属性上定义了attr_writer s / attr_accessor ,则可以通过匹配=$ regexp轻松检索它们:

 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) }