Supposons que j'ai une classe A
class A
attr_accessor :x, :y
def initialize(x,y)
@x, @y = x, y
end
end
Comment obtenir les attributs x
et y
sans savoir exactement comment ils ont été nommés.
Par exemple.
a = A.new(5,10)
a.attributes # => [5, 10]
Utilisez l'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]
Bien que la réponse de Sergio soit utile, elle renverra toutes les variables d'instance, ce qui, si j'ai bien compris la question du PO, n'est pas ce qui est demandé.
Si vous souhaitez renvoyer uniquement les "attributs" qui ont, par exemple, un mutateur, vous devez faire quelque chose de légèrement plus compliqué, tel que:
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
Cela retourne uniquement les attributs déclarés avec attr_accessor (ou avec un mutateur créé manuellement), et garde les variables d'instance internes masquées. Vous pouvez faire quelque chose de similaire si vous voulez ceux déclarés avec 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
Ce n'est peut-être pas le type DRY-est, mais si vous ne l'utilisez que pour une classe (par opposition à une classe de base dont tout hérite), cela devrait fonctionner.
Voir cet autre Stack Overflow Question . Ils surchargent 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
lorsque vous utilisez attr_accessor pour définir des attributs dans une classe, Ruby en utilisant refexion, définissez deux méthodes, pour chaque attribut déclaré, une pour obtenir la valeur et l'autre pour la définir, une variable d'instance du même nom de l'attribut
vous pouvez voir ces méthodes en utilisant
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?,..
Donc, ces attributs sont accessibles, en dehors de la classe, avec
p "#{a.x},#{a.y}"
ou à l'intérieur de la classe à travers la variable d'instance correspondante
class A
...
def attributes
[@x,@y]
end
...
end
p a.attributes #=> [5,10]
Si vous avez défini attr_writer
s/attr_accessor
s sur vos attributs, ils peuvent être facilement récupérés en faisant correspondre l'expression =$
:
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) }