ruby introspection

Forma más rápida/de una línea para listar attr_accessors en Ruby?



introspection (5)

No hay forma (de una sola línea o de otro tipo) de enumerar todos los métodos definidos por attr_accessor y solo los métodos definidos por attr_accessor sin definir su propio attr_accessor.

Aquí hay una solución que anula attr_accessor en MyBaseClass para recordar qué métodos se han creado usando attr_accessor:

class MyBaseClass def self.attr_accessor(*vars) @attributes ||= [] @attributes.concat vars super(*vars) end def self.attributes @attributes end def attributes self.class.attributes end end class SubClass < MyBaseClass attr_accessor :id, :title, :body end SubClass.new.attributes.inspect #=> [:id, :title, :body]

¿Cuál es la forma más corta y attr_accessor listar todos los métodos definidos con attr_accessor ? Me gustaría que sea así, si tengo una clase MyBaseClass , cualquier cosa que amplíe eso, puedo obtener attr_accessor ''s definido en las subclases. Algo como esto:

class MyBaseClass < Hash def attributes # ?? end end class SubClass < MyBaseClass attr_accessor :id, :title, :body end puts SubClass.new.attributes.inspect #=> [id, title, body]

¿Qué tal mostrar solo las definiciones attr_reader y attr_writer ?


Aquí hay una alternativa que usa un mixin en lugar de herencia:

module TrackAttributes def attr_readers self.class.instance_variable_get(''@attr_readers'') end def attr_writers self.class.instance_variable_get(''@attr_writers'') end def attr_accessors self.class.instance_variable_get(''@attr_accessors'') end def self.included(klass) klass.send :define_singleton_method, :attr_reader, ->(*params) do @attr_readers ||= [] @attr_readers.concat params super(*params) end klass.send :define_singleton_method, :attr_writer, ->(*params) do @attr_writers ||= [] @attr_writers.concat params super(*params) end klass.send :define_singleton_method, :attr_accessor, ->(*params) do @attr_accessors ||= [] @attr_accessors.concat params super(*params) end end end class MyClass include TrackAttributes attr_accessor :id, :title, :body end MyClass.new.attr_accessors #=> [:id, :title, :body]


Dando seguimiento a la respuesta de Christian, pero modificando para usar ActiveSupport :: Concern ...

module TrackAttributes extend ActiveSupport::Concern included do define_singleton_method(:attr_reader) do |*params| @attr_readers ||= [] @attr_readers.concat params super(*params) end define_singleton_method(:attr_writer) do |*params| @attr_writers ||= [] @attr_writers.concat params super(*params) end define_singleton_method(:attr_accessor) do |*params| @attr_accessors ||= [] @attr_accessors.concat params super(*params) end end def attr_readers self.class.instance_variable_get(''@attr_readers'') end def attr_writers self.class.instance_variable_get(''@attr_writers'') end def attr_accessors self.class.instance_variable_get(''@attr_accessors'') end end


Extraiga los atributos en una matriz, attr_accessor a una constante , luego attr_accessor en attr_accessor .

class SubClass < MyBaseClass ATTRS = [:id, :title, :body] attr_accessor(*ATTRS) end

Ahora puedes acceder a ellos a través de la constante:

puts SubClass.ATTRS #=> [:id, :title, :body]


Definiciones de clase

class MyBaseClass attr_writer :an_attr_writer attr_reader :an_attr_reader def instance_m end def self.class_m end end class SubClass < MyBaseClass attr_accessor :id def sub_instance_m end def self.class_sub_m end end

Llamar como métodos de clase

p SubClass.instance_methods - Object.methods p MyBaseClass.instance_methods - Object.methods

Llamar como métodos de instancia

a = SubClass.new b = MyBaseClass.new p a.methods - Object.methods p b.methods - Object.methods

Ambos producirán el mismo

#=> [:id, :sub_instance_m, :id=, :an_attr_reader, :instance_m, :an_attr_writer=] #=> [:an_attr_reader, :instance_m, :an_attr_writer=]

¿Cómo saber cuáles son el lector de escritor y el programa de acceso?

attr_accessor es tanto attr_writer como attr_reader

attr_reader muestra no = después del nombre del método

attr_writer genera an = después del nombre del método

Siempre puede usar una expresión regular para filtrar esa salida.