( For non-french readers : I am not giving up writing in english … Read the next post! )
Si vous venez d’un autre langage, le terme procédure (associé au terme fonction) doit vous dire quelque chose. Vaguement ….
Allez quelques connaissances (méconnaissances) tirées de ma mémoire pour poser les bases.
Par exemple, en PHP il existe deux types de fonctions. Les fonctions natives (built-in) et les fonctions “codées” par l’utilisateur.
Ces dernières se séparent en deux types : les fonctions et les procédures.
La différence entre les deux ? Une procédure est un groupe d’instructions qui ne renvoie pas de valeur. Une fonction est une procédure qui renvoie une valeur.
Et ruby dans tout ça ??
C’est complètement différent et je dirai même plus les procédures Ruby sont très éloignés des procédures PHP. En ruby il n’y a que des objets (les méthodes sont des objets) et les méthodes renvoient toujours une valeur.
Vous avez déjà vu ou même codé des choses comme ceci :
[1,2,3,4,5,6].each do |nb|
# Un code quelconque : des instructions ...
end
C’ette méthode est native à Enumerable (module que la classe Array inclut)
La méthode Array#each prend 0 paramètre mais un block. Le block est tout ce qui se trouve entre do et end.
On pourrait le représenter en Ruby comme ceci :
def each(&block)
# Un truc compliqué à écrire en ruby
end
Ne vous y trompez pas “&block” n’est pas un argument. C’est la notation ruby pour dire que la méthode each s’accompagne obligatoirement d’un block.
Autre exemple :
class Bar
def my_proc(&procedure)
@foo_proc = procedure
end
def recall
@foo_proc.call
end
end
bar = Bar.new
bar.my_proc do
# Pas de code
end
#=> #<Proc:0x00000>
Il se trouve que la procédure est une instance de la classe Proc.
Sans trop de surprise mêmes les procédures sont des objets. Et oui, en ruby tout est objet.
Quel est l’intérêt me direz-vous?
Cela change tout !!! En PHP les prcoédures sont codées en dur, en ruby on peut générer à la volée des suites d’instructions sans pour autant avoir à implémenter une méthode !!!
Illustration :
On sait que les blocks sont des instances de la classe Proc. La solution est facile, il suffit de créer des instances de Proc et les passer comme blocks d’une méthode acceptant un block.
p1 = Proc.new do
puts "Je suis p1"
end
p2 = Proc.new do
puts "Je suis p2"
end
bar = Bar.new
bar.my_proc(&p1)
# Je suis p1
#=> nil
bar.foo_proc
#=> #<Proc:0x164564ab>
bar.recall
# Je suis p1
#=> nil
bar.my_proc(&p2)
# Je suis p2
#=> #<Proc:0x054ecdab>
bar.recall
# Je suis p2
#=> nil
bar2 = Bar.new
bar2.my_proc(&p2)
# Je suis p2
#=> #<Proc:0x054ecdab>
bar2.instance_eval("@foo_proc") == bar.instance_eval("@foo_proc")
#=> true
Vous avez compris l’intérêt? Les blocks sont bien des suites d’instructions mais plus que cela, ce sont des objets !!! L’illustration précédente montre qu’on peut partager des suites d’instructions entre différents objets, générer ces instructions dynamiquement !
En route pour la méta-programmation avec Ruby !!!