How to get attributes that were defined through attr_reader or attr_accessor

前端 未结 6 1571
温柔的废话
温柔的废话 2020-12-15 05:10

Suppose I have a class A

class A
  attr_accessor :x, :y

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

How can I get

相关标签:
6条回答
  • 2020-12-15 05:38

    See this other Stack Overflow Question. They override 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
    
    0 讨论(0)
  • 2020-12-15 05:39

    Use introspection, Luke!

    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]
    
    0 讨论(0)
  • 2020-12-15 05:52

    when you use attr_accessor to define attributes in a class, Ruby using refexion, define a couple of methods, for each attribute declared, one to get the value and other to set, an instance variable of the same name of the attribute

    you can see this methods using

    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?,..
    

    So this attributes are accesible, outside the class, with

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

    or inside the class through the corresponding instance variable

    class A
      ...
      def attributes
        [@x,@y]
      end
      ...
    end
    p a.attributes   #=> [5,10]
    
    0 讨论(0)
  • 2020-12-15 05:55
    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
    

    This may not be the DRY-est, but if you are only concerned with doing this for one class (as opposed to a base class that everything inherits from), then this should work.

    0 讨论(0)
  • 2020-12-15 05:55

    If you have attr_writers/attr_accessors defined on your attributes, than they can be easily retrieved by matching the =$ regexp:

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

    OR

    A.instance_methods.each_with_object([]) { |key, acc| acc << key if key = key.to_s.match(/^(.*\w)=$/)&.[](1) }
    
    0 讨论(0)
  • 2020-12-15 06:05

    While Sergio's answer helps, it will return all the instance variables, which if I understand correctly the OP's question, is not what is asked.

    If you want to return only the 'attributes' that have e.g. a mutator, you have to do something slightly more complicated such as:

    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
    

    This returns only the attributes declared with attr_accessor (or with a manually created mutator), and keep the internal instance variables hidden. You can do something similar if you want the ones declared with attr_reader.

    0 讨论(0)
提交回复
热议问题