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
块是ruby的一个相当基本的部分。 它们由do |arg0,arg1| ... end
分隔 do |arg0,arg1| ... end
或{ |arg0,arg1,arg2| ... }
{ |arg0,arg1,arg2| ... }
。
它们允许你指定一个callback传递给一个方法。 这个callback可以通过两种方式来调用 – 通过指定一个带有前缀的最后一个参数来捕获它,或者使用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"
请注意,我们的callback在每种情况下都是相同的 – 我们可以通过将callback保存在一个对象中,然后将其传递给每个方法来删除重复。 这可以通过使用lambda
来捕获对象中的callback来完成,然后通过在&
前面加上前缀来传递给方法。
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"
理解&
here的不同用法作为函数的最后一个参数的前缀很重要
- 在一个函数定义中,它捕获任何通过该对象的块
- 在函数调用中,它将给定的callback对象扩展成一个块
如果你看看周围的块是遍地的,特别是在迭代器,像Array#each
。
块,Proc和lambda(在计算机科学中被称为闭包)是Ruby最强大的方面之一,也是最容易被误解的方面之一。 这可能是因为Ruby以一种相当独特的方式处理闭包。 让事情变得更复杂的是Ruby有四种不同的方式来使用闭包,每种方式都有点不同,有时也是荒谬的。 有相当多的网站提供了关于Ruby中的闭包如何工作的很好的信息。 但我还没有find一个好的,权威性的指导。
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(程序的简称)。 块和Procs之间的唯一区别是块是一个Proc,不能被保存,因此是一次性使用的解决scheme。 通过使用Proc,我们可以开始执行以下操作:
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
Lambdaexpression式
到目前为止,您已经用两种方式使用Procs,直接将它们作为属性传递并将它们保存为variables。 这些Procs与其他语言称为匿名函数或lambdaexpression式的行为非常相似。 为了使事情更有趣,lambdas也可以在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]
&block
是一种将一段Ruby代码发送到一个方法,然后在该方法的范围内评估代码的方法。 在上面的示例代码中,这意味着部分命名的购物车将在一个div中呈现。 我认为封闭这个术语在计算机科学中是用来做这个的。
所以在你的例子中, &block
是:
<%= render(:partial => "cart", :object => @cart) %>
Robert Sosinski的博客中提供了一些很好的阅读材料,以及对块,过程和拉姆达的解释。
重新attributes = {}
,这只是一个默认值的方法参数。 所以如果你调用hidden_div_if(whatever)
,也就是只传递第一个参数, attributes
会默认为一个空的散列。
这很有用,因为它稍后简化了设置attributes["style"]
,因为attributes
不必首先初始化为散列。 (尽pipe如此,它可以简单地作为(attributes ||= {})["style"] = …
)
&block
只是稍微复杂一些。
Ruby方法可以使用特殊的语法method(args) { |block_args| block_code }
method(args) { |block_args| block_code }
。 &block
基本上将该block
作为Proc
对象捕获到block
variables中。 所以block
只是一个指向匿名程序的variables。
当后面的content_tag
被调用, &block
被作为最后一个parameter passing时,它被扩展成一个块,就像调用的确是content_tag(…) { block originally passed to hidden_if_div }
所以也许我在这里很困惑。 你应该谷歌什么是“ruby默认参数”和“ruby块”。
Ruby实现了在计算机科学界被称为闭包的Blocks,Procs和lambdas。 如果你开始学习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
如果你需要传递一个参数给这个方法呢?
你可以修改方法签名来接受params,最后用一个以&符号开头的参数来捕获块。 在下面的例子中,我们的块将被捕获到&block param,我们将调用call方法。 这是在使用收益的地方
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块的全文
它是这样工作的:
@cart.items.empty?
是编纂
:id => "cart"
按照惯例成为属性,如果它是最后一个参数,可以删除参数哈希上的{}。
该块是
render(:partial => "cart", :object => @cart)
所以在该function中,如果购物车是空的,则会添加具有值“display:none”的属性样式
然后它将创build一个填充执行块的结果的内容的div标签,这将是用@cart的内容渲染局部视图购物车的结果。