块傻块rspec测试

时间:2014-05-20 05:03:55

标签: ruby-on-rails ruby methods block

我作为练习给了我以下测试:

require "silly_blocks"

describe "some silly block functions" do

  describe "reverser" do
    it "reverses the string returned by the default block" do
      result = reverser do
        "hello"
      end
      result.should == "olleh"
    end

    it "reverses each word in the string returned by the default block" do
      result = reverser do
        "hello dolly"
      end
      result.should == "olleh yllod"
    end
  end

  describe "adder" do
    it "adds one to the value returned by the default block" do
      adder do
        5
      end.should == 6
    end

    it "adds 3 to the value returned by the default block" do
      adder(3) do
        5
      end.should == 8
    end
  end

  describe "repeater" do
    it "executes the default block" do
      block_was_executed = false
      repeater do
        block_was_executed = true
      end
      block_was_executed.should == true
    end

    it "executes the default block 3 times" do
      n = 0
      repeater(3) do
        n += 1
      end
      n.should == 3
    end

    it "executes the default block 10 times" do
      n = 0
      repeater(10) do
        n += 1
      end
      n.should == 10
    end

  end

end

我能够使用以下代码解决它们:

def reverser
k = []
  x = yield.split(" ")
  x.each do |y|
    n = y.reverse
  k.push(n)
end

m = k.join(" ")
m
end

def adder(num=1, &block)
  block.call + num
end

def repeater(num=1, &block)
    for i in (1..num) do
        block.call
    end
end

然而,我对其中的一些概念并不了解。例如:

  1. & & block参数中的符号是什么意思?
  2. 同样是什么是block.call,我假设其调用的实际块对象在哪里?
  3. 如果我想要实现其他目的,我理论上可以在块上使用另一种方法吗?
  4. 我还可以在哪里学习更多关于积木的信息
  5. 这项练习有点高于我目前的知识。

1 个答案:

答案 0 :(得分:3)

  1. 这意味着"这是块参数"。您不必将其称为&block,因此需要有一种方法将其与其他参数分开。相同的表示法用于将参数作为块传递给块而不是普通参数(见下文)

  2. block.callyield完全相同。不同之处在于您可以使用block来访问块本身而无需立即调用它。例如,您可以存储块以供以后执行。这是一种常见的模式,称为懒惰评估。

  3. 是的,您还可以传递与do / end块不同的内容作为&block参数。请参阅下面的一些示例。

  4. @UriAgassi为您提供了一个很好的链接。

  5. 以下是您可以作为块参数传递的其他一些内容。首先,只是一个简单的方法,用于演示:

    def reverser(&block)
      block.call.reverse
    end
    

    您现在可以传递标准块

    reverser do
      "hello"
    end
    #=> "olleh"
    

    或者,在替代块语法中,用于内联样式

    reverser { "hello" }
    #=> olleh
    

    您还可以传递lambda或proc,它类似于块。 通过使用&块表示法,您可以将变量作为块参数传递:

    my_block = lambda { "hello world!" }
    reverser(&my_block)
    #=> "!dlrow olleh"
    

    或者,替代lambda语法

    my_block = -> { "hello world!" }
    reverser(&my_block)
    #=> "!dlrow olleh"
    

    您甚至可以使用现有方法并将其作为块参数传递 在这里你可以看到块的巨大优势:它们被评估 执行block.call时,而不是加载代码时。在这里 意味着字符串每次都会相应改变。

    def foobar
      "foobar at #{Time.now}"
    end
    reverser(&method(:foobar))
    #=> "0020+ 15:42:90 02-50-4102 ta raboof"
    #=> "0020+ 31:52:90 02-50-4102 ta raboof"
    

    你可以用这个来做很酷的事情,例如:

    [1, 2, 3].each(&method(:puts))
    1
    2
    3
    #=> [1, 2, 3]
    

    但请记住,不要过分,Ruby就是表达性和可读性的代码。在增强代码时使用这些技术,但如果可能,请使用更简单的方法。

    最后,这里也是一个懒惰评估的例子:

    class LazyReverser
      def initialize(&block)
        @block = block
      end
    
      def reverse
        @block.call.reverse
      end
    end
    
    reverser = LazyReverser.new do
      # some very expensive computation going on here,
      # maybe we do not even need it, so lets use the
      # lazy reverser!
    
      "hello dolly"
    end
    
    # now go and do some other stuff
    
    # it is not until later in the program, that we can decide
    # whether or not we even need to call the block at all
    if some_condition
      reverser.reverse
      #=> "yllod olleh"
    else
      # we did not need the result, so we saved ourselves
      # the expensive computation in the block altogether!
    end