Oui, c'est un peu déroutant au début.
Dans Ruby, les méthodes peuvent recevoir un bloc de code afin d'effectuer des segments de code arbitraires.
Lorsqu'une méthode attend un bloc, elle l'invoque en appelant la yield
fonction.
C'est très pratique, par exemple, pour parcourir une liste ou pour fournir un algorithme personnalisé.
Prenons l'exemple suivant:
Je vais définir une Person
classe initialisée avec un nom et fournir une do_with_name
méthode qui, lorsqu'elle est invoquée, passerait simplement l' name
attribut au bloc reçu.
class Person
def initialize( name )
@name = name
end
def do_with_name
yield( @name )
end
end
Cela nous permettrait d'appeler cette méthode et de passer un bloc de code arbitraire.
Par exemple, pour imprimer le nom, nous ferions:
person = Person.new("Oscar")
#invoking the method passing a block
person.do_with_name do |name|
puts "Hey, his name is #{name}"
end
Imprime:
Hey, his name is Oscar
Remarquez, le bloc reçoit, en paramètre, une variable appelée name
(NB vous pouvez appeler cette variable comme bon vous semble, mais il est logique de l'appeler name
). Lorsque le code invoque, yield
il remplit ce paramètre avec la valeur de @name
.
yield( @name )
Nous pourrions fournir un autre bloc pour effectuer une action différente. Par exemple, inversez le nom:
#variable to hold the name reversed
reversed_name = ""
#invoke the method passing a different block
person.do_with_name do |name|
reversed_name = name.reverse
end
puts reversed_name
=> "racsO"
Nous avons utilisé exactement la même méthode ( do_with_name
) - c'est juste un bloc différent.
Cet exemple est trivial. Les utilisations les plus intéressantes sont de filtrer tous les éléments d'un tableau:
days = ["monday", "tuesday", "wednesday", "thursday", "friday"]
# select those which start with 't'
days.select do | item |
item.match /^t/
end
=> ["tuesday", "thursday"]
Ou, nous pouvons également fournir un algorithme de tri personnalisé, par exemple basé sur la taille de la chaîne:
days.sort do |x,y|
x.size <=> y.size
end
=> ["monday", "friday", "tuesday", "thursday", "wednesday"]
J'espère que cela vous aide à mieux le comprendre.
BTW, si le bloc est facultatif, vous devez l'appeler comme:
yield(value) if block_given?
Si n'est pas facultatif, il suffit de l'invoquer.
ÉDITER
@hmak a créé un repl.it pour ces exemples: https://repl.it/@makstaks/blocksandyieldsrubyexample