Подтвердить что ты не робот

Что это за блок в Ruby? И как это передается в методе здесь?

Пила этот кусок кода в книге Ruby on Rails. Это первое из представления, а второе - вспомогательный модуль. Я не понимаю, как это работает &block и attributes={}. Может ли кто-нибудь научить меня чему-то объяснять?

<% 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
4b9b3361

Ответ 1

Блоки - довольно основная часть рубина. Они разделены символом do |arg0,arg1| ... end или { |arg0,arg1,arg2| ... }.

Они позволяют указать обратный вызов для перехода к методу. Этот обратный вызов может быть вызван двумя способами: либо путем захвата его, указав конечный аргумент с префиксом & или используя ключевое слово yield:

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"

Обратите внимание, что наш обратный вызов был одинаковым в каждом случае - мы можем удалить повторение, сохраняя наш обратный вызов в объекте, а затем передавая его каждому метод. Это можно сделать, используя lambda, чтобы зафиксировать обратный вызов в объекте, а затем передается методу, префикс его &.

irb> callback = lambda do |word, num|
       puts "in callback! word = #{word.inspect}, num = #{num.inspect}"
       word + num.to_s
     end
#=> #<Proc:[email protected](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"

Важно понимать различные применения & здесь как префикс последнего аргумента функции

  • в определении функции, он захватывает любой переданный блок в этот объект
  • в вызове функции он расширяет данный объект обратного вызова в блок

Если вы смотрите вокруг блоков, используются повсюду, особенно в итераторах, например Array#each.

Ответ 2

Блоки, Procs и lambdas (называемые закрытием в Computer Science) являются одним из самых мощных аспектов Ruby, а также одним из самых непонятых. Вероятно, это связано с тем, что Ruby закрывает ручки довольно уникальным образом. Усложнение сложностей заключается в том, что Ruby имеет четыре разных способа использования закрытий, каждый из которых немного отличается, а иногда и бессмыслен. Существует довольно много сайтов с очень хорошей информацией о том, как замыкания работают внутри Ruby. Но мне еще предстоит найти хорошее, окончательное руководство.

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

Процедуры, AKA, Procs

Блоки очень удобны и синтаксически просты, однако мы можем захотеть иметь много разных блоков в нашем распоряжении и использовать их несколько раз. Таким образом, повторение одного и того же блока снова и снова потребует от нас повторения. Однако, поскольку Ruby полностью объектно-ориентированный, это можно обрабатывать довольно чисто, сохраняя повторно используемый код как сам объект. Этот многоразовый код называется Proc (short для процедуры). Единственное различие между блоками и Procs заключается в том, что блок - это Proc, который нельзя сохранить, и, как таковой, является одноразовым решением. Работая с Procs, мы можем начать делать следующее:

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

Лямбда

До сих пор вы использовали Procs двумя способами, передавая их напрямую как атрибут и сохраняя их как переменную. Эти Procs действуют очень похоже на то, что другие языки называют анонимными функциями, или лямбдами. Чтобы сделать вещи более интересными, лямбды доступны в Ruby тоже. Посмотрите:

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

Блоки

Самый распространенный, самый простой и, возможно, самый "похожий на Ruby" способ использования закрытий в Ruby - это блоки. Они имеют следующий знакомый синтаксис:

array = [1, 2, 3, 4]

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

puts array.inspect

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

Ответ 3

&block - это способ отправки части кода Ruby в метод, а затем оценки этого кода в объеме этого метода. В приведенном выше примере кода означает, что частичная именованная тележка будет отображаться в div. Я думаю, что термин closure используется для этого в информатике.

Итак, в вашем примере &block:

<%= render(:partial => "cart", :object => @cart) %>

Некоторое хорошее чтение и объяснение блоков, procs и lamdas можно найти в блог Роберта Сосински.

Ответ 4

Re attributes = {}, это просто аргумент метода со значением по умолчанию. Поэтому, если вы вызываете hidden_div_if(whatever), то есть передаете только первый аргумент, attributes будет по умолчанию пустым хешем.

Это полезно, потому что это упрощает установку attributes["style"] позже, так как attributes не нужно сначала инициализировать хэш. (Что, тем не менее, можно было бы сделать просто как (attributes ||= {})["style"] = ….)


&block только немного сложнее.

Ruby-методы могут принимать последний аргумент, являющийся блоком, используя специальный синтаксис method(args) { |block_args| block_code }. &block в основном фиксирует этот блок в переменной block как объект Proc. Таким образом, block - это просто переменная, указывающая на анонимную процедуру здесь.

Когда вызывается content_tag, а &block передается в качестве последнего аргумента, он расширяется в блок, например, если вызов действительно content_tag(…) { block originally passed to hidden_if_div }


Так что, может быть, я действительно запутался здесь. То, что вы должны использовать Google, это "аргументы ruby ​​default" и "ruby blocks".

Ответ 5

Ruby реализует блоки, Procs и лямбды, которые называются замыканиями в сообществе компьютерных наук. Если вы начнете изучать Ruby, вы быстро столкнетесь с кодом, который выглядит следующим образом.

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

Так что происходит здесь?

Мы начинаем с массива имен животных и вызываем alter_each! метод передачи блока. В этом блоке кода мы можем указать, как мы хотим изменить каждый элемент. Наш пример будет префикс каждого имени животного с его позицией в массиве. Как alter_each! метод выполняет итерацию через каждый элемент, который будет выполнять наш блок, передавая значение и индекс. Наш блок фиксирует эти параметры, префиксы индекса к имени и возвращает результат. Теперь давайте посмотрим на alter_each! Метод.

Обратите внимание, что метод не задает никаких параметров, поскольку блок автоматически присваивается ключевому слову yield. yield вызывается как функция, передающая значение и индекс каждого элемента в массиве и переопределяющее исходное значение.

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

Что делать, если вам нужно передать параметр этому методу?

Вы можете изменить подпись метода для принятия параметров и, наконец, поймать блок с параметром, начинающимся с амперсанда. В приведенном ниже примере наш блок будет захвачен параметром параметра & block, который будет вызываться методом вызова. Это вместо использования урожая

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

Полная статья о блоках ruby ​​

Ответ 6

Он работает следующим образом:

@cart.items.empty? - это кодирование

:id => "cart" Становится атрибутом по соглашению, которое вы можете удалить {} при хэшировании параметров, если он последний.

блок

render(:partial => "cart", :object => @cart)

поэтому внутри функции, если тележка пуста, она добавит атрибут стиль со значением "display: none"

Затем он создаст тег div, заполненный содержимым результата выполнения блока, который будет результатом рендеринга частичной тележки с содержимым @cart.