web-dev-qa-db-fra.com

Utilisation de do block vs accolades {}

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?

111
Alan Storm

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 }

98
YOU

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
69
bkdir

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 {}.

39
nas

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:

  • Utilisez des accolades { } Pour les blocs d'une seule ligne
  • Utilisez do end Pour les blocs multilignes

Cela 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:

  • Utilisez do end Pour les blocs de procédure
  • Utilisez des accolades { } Pour les blocs fonctionnels

Cela 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.

5
Andrew Vit

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?

1
iGEL