Nouveau sur Ruby, mettez vos gants de débutant.
Existe-t-il une différence (obscure ou pratique) entre les deux extraits suivants?
my_array = [:uno, :dos, :tres]
my_array.each { |item|
puts item
}
my_array = [:uno, :dos, :tres]
my_array.each do |item|
puts item
end
Je me rends compte que la syntaxe entre accolades vous permettrait de placer le bloc sur une seule ligne
my_array.each { |item| puts item }
mais en dehors de cela, existe-t-il des raisons impérieuses d'utiliser une syntaxe plutôt qu'une autre?
Ruby cookbook dit que la syntaxe du crochet a un ordre de priorité supérieur à celui de do..end
Gardez à l'esprit que la syntaxe entre crochets a une priorité plus élevée que la syntaxe do..end. Considérez les deux extraits de code suivants:
1.upto 3 do |x|
puts x
end
1.upto 3 { |x| puts x }
# SyntaxError: compile error
Le deuxième exemple ne fonctionne que lorsque des parenthèses sont utilisées, 1.upto(3) { |x| puts x }
C'est une question un peu ancienne mais je voudrais essayer d'expliquer un peu plus sur {}
Et do .. end
comme il est dit avant
la syntaxe du crochet a un ordre de priorité plus élevé que do..end
mais comment celui-ci fait la différence:
method1 method2 do
puts "hi"
end
dans ce cas, method1 sera appelé avec le bloc de do..end
et method2 sera passé à method1 en tant qu'argument! qui est équivalent à method1(method2){ puts "hi" }
mais si vous dites
method1 method2{
puts "hi"
}
alors method2 sera appelé avec le bloc, puis la valeur renvoyée sera transmise à method1 en tant qu'argument. Qui est équivalent à method1(method2 do puts "hi" end)
def method1(var)
puts "inside method1"
puts "method1 arg = #{var}"
if block_given?
puts "Block passed to method1"
yield "method1 block is running"
else
puts "No block passed to method1"
end
end
def method2
puts"inside method2"
if block_given?
puts "Block passed to method2"
return yield("method2 block is running")
else
puts "no block passed to method2"
return "method2 returned without block"
end
end
#### test ####
method1 method2 do
|x| puts x
end
method1 method2{
|x| puts x
}
#### sortie ####
#inside method2
#no block passed to method2
#inside method1
#method1 arg = method2 returned without block
#Block passed to method1
#method1 block is running
#inside method2
#Block passed to method2
#method2 block is running
#inside method1
#method1 arg =
#No block passed to method1
Généralement, la convention est d'utiliser {}
lorsque vous effectuez une petite opération, par exemple un appel de méthode ou une comparaison, etc., cela est donc parfaitement logique:
some_collection.each { |element| puts element }
Mais si vous avez une logique légèrement complexe qui va sur plusieurs lignes, utilisez do .. end
comme:
1.upto(10) do |x|
add_some_num = x + Rand(10)
puts '*' * add_some_num
end
En gros, si votre logique de bloc utilise plusieurs lignes et ne peut pas être installée sur la même ligne, utilisez do .. end
et si votre logique de bloc est simple et qu’une simple ligne de code, utilisez {}
.
Il y a deux styles courants pour choisir do end
Contre { }
Pour les blocs en Ruby:
Le premier et très commun style a été popularisé par Ruby sur Rails, et est basé sur une simple règle de single vs multi-line:
{ }
Pour les blocs d'une seule lignedo end
Pour les blocs multilignesCela a du sens car do/end lit mal dans une ligne, mais pour les blocs de plusieurs lignes, laisser une fermeture }
Suspendue à sa propre ligne est incompatible avec tout ce qui utilise end
dans Ruby, tel que définitions de module, de classe et de méthode (def
etc.) et structures de contrôle (if
, while
, case
, etc.)
Le deuxième style, moins fréquent, est connu sous le nom de sémantique, ou " Weirich Braces ", proposé par le regretté rubyist Jim Weirich:
do end
Pour les blocs de procédure{ }
Pour les blocs fonctionnelsCela signifie que lorsque le bloc est évalué pour sa valeur de retour, il devrait être chaînable et les accolades {}
Ont plus de sens pour le chaînage de méthodes.
D'autre part, lorsque le bloc est évalué pour ses effets secondaires, la valeur de retour est alors sans conséquence et le bloc ne fait que "faire" quelque chose, il n'a donc aucun sens. être enchaîné.
Cette distinction dans la syntaxe donne une signification visuelle à l'évaluation du bloc et indique si vous devez vous soucier de sa valeur de retour.
Par exemple, ici, la valeur de retour du bloc est appliquée à chaque élément:
items.map { |i| i.upcase }
Cependant, ici, il n'utilise pas la valeur de retour du bloc. Il fonctionne de manière procédurale et faire un effet secondaire avec cela:
items.each do |item|
puts item
end
Un autre avantage du style sémantique est qu'il n'est pas nécessaire de modifier les accolades pour faire/terminer simplement parce qu'une ligne a été ajoutée au bloc.
Comme observation, par coïncidence, les blocs fonctionnels sont souvent constitués d'une ligne, et procédural (par exemple, config) est multiligne. Ainsi, suivre le style de Weirich a presque le même aspect que le style Rails.
J'ai utilisé le style Weirich pendant des années, mais je me suis éloigné de celui-ci pour toujours utiliser des accolades. Je ne me souviens pas d'avoir déjà utilisé les informations du style de bloc, et la définition est un peu vague. Par exemple:
date = Timecop.freeze(1.year.ago) { format_date(Time.now) }
customer = Timecop.freeze(1.year.ago) { create(:customer) }
Sont-ils procuduels ou fonctionnels?
Et le comptage de lignes est simplement inutile à mon avis. Je sais s'il y a une ou plusieurs lignes et pourquoi exactement devrais-je changer de style simplement parce que j'ai ajouté ou supprimé des lignes?