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.