Ruby - Utiliser les blocs pour faire du refactoring - partie 2
Suite à l’article d’hier
(Utiliser les blocs pour faire du refactoring),
on m’a demandé la différence entre block.call et yield. C’est parti.
On s’était arrêté là:
class Bidule
def un
helper('un') { puts 'Au milieu de la méthode un' }
end
def deux
helper('deux') do
puts 'Ceci est le milieu de la méthode deux'
end
end
private
def helper(argument, &block)
puts "Début de la méthode #{argument}"
block.call
puts "Fin de la méthode #{argument}"
end
end
bidule = Bidule.new
bidule.un
bidule.deuxEssayons de remplacer block.call par yield:
class Bidule
def un
helper('un') { puts 'Au milieu de la méthode un' }
end
def deux
helper('deux') do
puts 'Ceci est le milieu de la méthode deux'
end
end
private
def helper(argument, &block)
puts "Début de la méthode #{argument}"
yield
puts "Fin de la méthode #{argument}"
end
end
bidule = Bidule.new
bidule.un
bidule.deuxLorsqu’on lance le programme, on voit qu’il n’y a pas de différences:
$ ruby test.rb
Début de la méthode un
Au milieu de la méthode un
Fin de la méthode un
Début de la méthode deux
Ceci est le milieu de la méthode deux
Fin de la méthode deuxOk, donc block.call et yield c’est pareil ? Attends encore. Essayons
maintenant de supprimer le &block:
class Bidule
def un
helper('un') { puts 'Au milieu de la méthode un' }
end
def deux
helper('deux') do
puts 'Ceci est le milieu de la méthode deux'
end
end
private
def helper(argument)
puts "Début de la méthode #{argument}"
yield
puts "Fin de la méthode #{argument}"
end
end
bidule = Bidule.new
bidule.un
bidule.deuxToujours pas de différences ! Par contre, on ne pourra pas appeler
block.call sans avoir défini &block:
def helper(argument)
puts "Début de la méthode #{argument}"
block.call
puts "Fin de la méthode #{argument}"
endLe code ci-dessus donnera évidemment une erreur:
$ ruby test.rb
Début de la méthode un
test.rb:16:in `helper': undefined local variable or method `block' for
#<Bidule:0x9eaf6ec> (NameError)Toutes ces expérimentations nous ammène à une première conclusion: Les blocs sont implicites, et donc ils sont partout. Ce que confirme, s’il en est encore besoin, la session irb suivante:
>> def foo(arg)
>> puts arg
>> end
=> :foo
>> foo('ok') { puts 'I am in a block' }
okLe contenu du bloc n’est jamais évalué, mais ne provoque pas d’erreur
lors de l’appel de foo.
Seconde conclusion, block.call et yield fonctionnent à l’identique.
Bien que je préfère block.call, qui me force à documenter la méthode
avec le &block.
À demain.