51 votes

Qu'est-ce que c'est & block in Ruby? Et comment est-il passé dans une méthode ici?

Vu ce morceau de code dans un livre RoR. Le premier est issu d'une vue et le second est un module d'assistance. Je ne comprends pas comment ça marche et les attributs = {}. Quelqu'un peut-il me guider vers un tutoriel pour expliquer cela?

 <% hidden_div_if(@cart.items.empty?, :id => "cart") do %>
 <%= render(:partial => "cart", :object => @cart) %>
<% end %>

module StoreHelper
 def hidden_div_if(condition, attributes = {}, &block)
  if condition
   attributes["style"] = "display: none"
  end
   content_tag("div", attributes, &block)
  end
end
 

93voto

rampion Points 38697

Les blocs sont assez de base, une partie de ruby. Elles sont délimitées par des do |arg0,arg1| ... end ou { |arg0,arg1,arg2| ... }.

Ils vous permettent de spécifier une fonction de rappel pour passer à une méthode. Ce rappel peut être invoqué deux façons - soit par la capture en spécifiant un dernier argument, avec le préfixe &, ou par à l'aide de l' yield mot-clé:

irb> def meth_captures(arg, &block)
       block.call( arg, 0 ) + block.call( arg.reverse , 1 )
     end
#=> nil
irb> meth_captures('pony') do |word, num|
       puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
       word + num.to_s
     end
in callback! word = "pony" num = 0
in callback! word = "ynop" num = 1
#=> "pony0ynop1" 
irb> def meth_yields(arg)
       yield(arg, 0) + yield(arg.upcase, 1)
     end
#=> nil
irb> meth_yields('frog') do |word, num|
       puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
       word + num.to_s
     end
in callback! word = "frog", num = 0
in callback! word = "FROG", num = 1
#=> "frog0FROG1"

Notez que notre rappel a été le même dans chacun des cas, nous pouvons supprimer la répétition de sauver notre rappel dans un objet, puis en le passant à chaque la méthode. Cela peut être fait en utilisant lambda pour capturer le rappel dans un objet, et puis passés à une méthode en préfixant avec &.

irb> callback = lambda do |word, num|
       puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
       word + num.to_s
     end
#=> #<Proc:0x0052e3d8@(irb):22>
irb> meth_captures('unicorn', &callback)
in callback! word = "unicorn", num = 0
in callback! word = "nrocinu", num = 1
#=> "unicorn0nrocinu1"
irb> meth_yields('plate', &callback)
in callback! word = "plate", num = 0
in callback! word = "PLATE", num = 1
#=> "plate0PLATE1"

Il est important de comprendre les différentes utilisations de l' & ici comme préfixe pour le dernier argument d'une fonction

  • dans une définition de fonction, elle capte tout passé bloc dans cet objet
  • dans un appel de fonction, il élargit le rappel de l'objet dans un bloc

Si vous regardez autour de blocs sont utilisés partout, en particulier dans les itérateurs, comme Array#each.

18voto

Dinesh Points 1161

Des blocs, des Proc et des lambdas (dénommé fermetures en Sciences de l'Informatique) sont l'un des aspects les plus puissants de Ruby, et aussi l'un des plus mal compris. C'est probablement parce que Ruby poignées fermetures dans un lieu unique manière. Rendre les choses plus compliquées, c'est que Ruby a quatre façons différentes d'utiliser les fermetures, dont chacun est un peu différent, et parfois absurdes. Il existe assez peu de sites avec de très bonnes informations sur la façon de fermetures de travail au sein de Ruby. Mais je n'ai pas encore trouver un bon guide définitif là-bas.

class Array
  def iterate!(&code)
    self.each_with_index do |n, i|
      self[i] = code.call(n)
    end
  end
end

array = [1, 2, 3, 4]

array.iterate! do |n|
  n ** 2
end

Les procédures, les AKA, les Procs

Les blocs sont très pratique et d'un point de vue syntaxique simple, cependant, on peut vouloir avoir beaucoup de différents blocs à notre disposition et de les utiliser plusieurs fois. En tant que tel, en passant le même bloc, encore et encore, nous obligerait à répéter soi-même. Cependant, comme le Rubis est totalement orienté objet, cela peut être manipulé très proprement en enregistrant le code réutilisable comme un objet en soi. Ce code réutilisable est appelé un Proc (de procédure). La seule différence entre les blocs et le Proc est qu'un bloc est un Proc qui ne peut être sauvé, et en tant que tel, est un temps d'utilisation de la solution. En travaillant avec les Procs, nous pouvons commencer à faire le suivant:

class Array
  def iterate!(code)
    self.each_with_index do |n, i|
      self[i] = code.call(n)
    end
  end
end

array_1 = [1, 2, 3, 4]
array_2 = [2, 3, 4, 5]

square = Proc.new do |n|
  n ** 2
end

Les Lambdas

Jusqu'à présent, vous avez utilisé Procs de deux façons, en passant directement comme un attribut et de les enregistrer en tant que variable. Ces Procs loi très similaire à ce que d'autres langues de l'appel des fonctions anonymes, ou les lambdas. Pour rendre les choses plus intéressantes, les lambdas sont disponibles au sein de Ruby trop. Prendre un coup d'oeil:

class Array
  def iterate!(code)
    self.each_with_index do |n, i|
      self[i] = code.call(n)
    end
  end
end

array = [1, 2, 3, 4]

array.iterate!(lambda { |n| n ** 2 })

puts array.inspect

Les blocs

La plus commune, la plus simple et sans doute le plus "Ruby comme" manière d'utiliser les fermetures en Ruby, c'est avec des blocs. Ils ont syntaxe familière:

array = [1, 2, 3, 4]

array.collect! do |n|
  n ** 2
end

puts array.inspect

# => [1, 4, 9, 16]

11voto

gaqzi Points 1383

L' &block est un moyen d'envoyer un morceau de code Ruby dans une méthode et d'en évaluer ce code dans le champ d'application de cette méthode. Dans votre exemple de code ci-dessus, cela signifie un partiel panier sera rendue dans un div. Je pense que le terme de fermeture est utilisé dans l'informatique.

Donc dans votre exemple, l' &block est:
<%= render:partial => "panier", :objet => @cart) %>

Bonne lecture et une explication de blocs, procs et lamdas peut être trouvé à Robert Sosinskis blog.

4voto

kch Points 25855

Re attributes = {}, c'est juste un argument de méthode avec une valeur par défaut. Donc, si vous appelez hidden_div_if(whatever), qui est, en passant seulement le premier argument, attributes serait vide par défaut de hachage.

C'est utile, car elle simplifie le réglage attributes["style"] plus tard, comme attributes n'a pas à être initialisée à une valeur de hachage de la première. (Qui peut néanmoins être fait simplement en tant que (attributes ||= {})["style"] = ….)


&block est seulement un peu plus compliqué.

Ruby méthodes peuvent prendre un dernier argument qui est un bloc, à l'aide de la syntaxe method(args) { |block_args| block_code }. &block essentiellement capture de ce bloc dans l' block variable en tant que Proc objet. Donc, block est juste une variable qui pointe vers un anonyme procédure ici.

Quand, plus tard content_tag est appelé, et &block est passé comme son dernier argument, il est étendu dans un bloc, comme si l'appel était en effet content_tag(…) { block originally passed to hidden_if_div }


Alors peut-être que j'étais vraiment à confusion ici. Ce que vous devriez google est "ruby arguments par défaut" et "ruby blocs".

3voto

jspooner Points 3963

Ruby met en œuvre des Blocs, des Proc et des lambdas qui sont considérés comme des fermetures d'usines dans la communauté informatique. Si vous commencez à apprendre Ruby vous serez rapidement et exécuter un code qui ressemble à ceci.

a = ["dog", "cat", "bird"]
a.alter_each! do |n, i|
  "#{i}_#{n}"
end

Donc ce qui se passe ici?

Nous commençons avec un tableau de noms d'animaux et d'appeler la alter_each! méthode passage d'un bloc. Dans ce bloc de code, nous pouvons spécifier la façon dont nous voulons modifier chaque élément. Notre exemple de préfixe de chaque nom d'animal avec sa position dans le tableau. Comme le alter_each! méthode parcourt chaque élément, qu'il va exécuter notre bloc en passant la valeur et l'index. Notre bloc rend compte de ces paramètres, les préfixes de l'index pour le nom et retourne le résultat. Regardons maintenant le alter_each! la méthode.

Avis de la méthode n'a pas de spécifier tous les paramètres, c'est parce que le bloc est automatiquement assigné au mot clé yield. le rendement est appelée comme une fonction en passant la valeur et l'index de chaque élément d'un tableau et en remplaçant la valeur d'origine.

class Array
  def alter_each!
    self.each_with_index do |n, i|
      self[i] = yield(n,i)
    end
  end
end

Que faire si vous avez besoin de passer un paramètre à cette méthode?

Vous pouvez modifier la signature de la méthode pour accepter les paramètres et enfin prendre le bloc avec un param commençant par une esperluette. Dans l'exemple ci-dessous notre bloc sera capturé avec le bloc &param laquelle nous allons invoquer l'appel de la méthode. C'est à la place de l'aide de rendement

class Array
  def modify_each!(add_one = true, &block)
    self.each_with_index do |n, i|
      j = (add_one) ? (i + 1) : i
      self[i] = block.call(n,j)
    end
  end
end

Article complet sur ruby blocs

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X