C’est la visibilité par défaut d’une méthode, elle n’a pas de particularité.
Contrairement à d’autres langages, les méthodes privées sont aussi héritées dans les classes descendantes.
class Animal
attr_accessor :name, :age, :weight
def initialize(name, weight, age)
@name = name
@weight = weight
@age = age
end
def to_s
"I'm #{name}, I have #{age} years and I weigh #{weight} KG."
end
def older?(animal)
age > animal.age
end
def bigger?(animal)
weight > animal.weight
end
protected :age
private :weight
end
class Dog < Animal
end
class Cat < Animal
def to_s
"I'm #{name}, I have #{age} years and I weigh #{weight} (but I have lost some kg)."
end
end
Animal#weight est privée, pourtant si j’appelle le Cat#to_s, j’aurai bien “I’m garfield, I have 3 years and I weigh 10 (but I have lost some kg).” ce qui signifie que l’on a bien accès à la méthode.
Les autres méthodes de la classe peuvent accéder à la méthode privée, mais uniquement pour l’objet courant. Dans l’exemple garfield.bigger?(snoopy) renverra une erreur car je ne peux pas invoquer weight sur snoopy depuis garfield.
Cette notion de contexte est très importante car même l’invocation sur self ne fonctionnera pas. Si dans mon to_s j’utilisais self.weight j’aurai droit à une erreur d’invocation de méthode privée.
Contrairement à d’autres langage comme java, le fait de définir une méthode protected, ne signifie pas qu’elle pourra uniquement être appelée dans une classe descendante. On a vu que même les méthodes privées étaient héritées.
En effet en ruby une méthode protected est très proche d’une méthode privée. La nuance se trouve au niveau du contexte. Si on a vu que l’invocation de bigger? renvoyait une erreur, dans le cadre d’un attribut protected comme age cela fonctionne, je peux donc invoquer Animal#older?
Les attributs protégés sont donc accessibles aux autres objets de la classe mais aussi aux objets de classe héritées. Par exemple ici je peux accéder à Dog#weight depuis Cat#weight car ils descendent tout deux de Animal.
L’introspection est la capacité pour un objet de s’auto-examiner:
p garfield.class
# Cat
p garfield.class.ancestors
# [Cat, Animal, Object, Kernel]
p garfield.methods.sort
# ["==", "===", "=~", "__id__", "__send__", "age", "age=", "bigger?", "class", "clone", "display", "dup", "enum_for", "eql?", "equal?", "extend", "freeze", "frozen?", "hash", "id", "inspect", "instance_eval", "instance_exec", "instance_of?", "instance_variable_defined?", "instance_variable_get", "instance_variable_set", "instance_variables", "is_a?", "kind_of?", "method", "methods", "name", "name=", "nil?", "object_id", "older?", "private_methods", "protected_methods", "public_methods", "respond_to?", "send", "singleton_methods", "taint", "tainted?", "tap", "to_a", "to_enum", "to_s", "type", "untaint", "weight="]
p garfield.methods(false)
# []
# Object.const_get("RUBY_VERSION")
p garfield.class.ancestors.last.const_get("RUBY_VERSION")
# 1.8.7
On peut par exemple lister toute la hiérarchie de classes parentes, tout comme les constantes et les méthodes définies. Le paramètre false sur methods permet de ne lister que nos propres méthodes et pas celles héritées.
Ici Cat ne définit aucune méthode qui lui est propre, d’où le tableau vide.
Il faut visualiser la méta-programmation comme du code qui crée du code.
class Cat
STATES = ["hungry", "sated"].freeze
attr_accessor :state
STATES.each do |state|
define_method "#{state}?" do
state == self.state
end
end
end
garfield.state = "hungry"
p garfield.hungry?
# true
p garfield.sated?
# false
Ici je peux ré-ouvrir ma class Cat à la volée et y définir des méthodes en fonction d’attributs existants. La clé se trouve dans le define_method qui permet de créer des méthodes dynamiquement.
On a vu dans la première partie des méthodes à la visibilité privée. Toutefois en ruby il n’est pas possible de complètement cacher une méthode.
p garfield.send :weight
# 10
Cat.send :public, :weight
p garfield.weight
# 10
Celle ci peut toujours être invoquée avec send. De même il est possible de changer la visibilité d’une méthode au runtime ! Vous l’aurez compris, ces concepts très puissants sont à utiliser avec parcimonie.
L’équipe Synbioz.
Libres d’être ensemble.