0

这是对如何在 Rspec 中创建辅助方法的描述,取自 Rspec 书(第 149 页)。此示例假定有一个名为“set_status”的方法,该方法在创建“Thing”对象时触发。

两组代码都创建了一个新的“Thing”对象,设置状态,然后执行“fancy_stuff”。第一组代码对我来说非常清楚。它触发的“it”语句之一,然后使用选项调用“create_thing”方法。创建一个新的“Thing”对象,并使用“options”属性作为参数调用“set_status”方法。

第二组代码类似。触发“it”语句之一,然后调用“given_thing_with”方法,同时将“:status”哈希分配作为参数传递。在“given_thing_with”方法中,“yield”被触发,以“Thing.new”作为参数。这是我遇到麻烦的地方。当我尝试运行此代码时,我收到“block given to yield”错误。我知道,yield 传递的任何属性都将从调用“given_thing_with”方法的“it”语句返回到管括号中的“事物”。我可以得到新的

我不明白为什么在'yield'命令之后没有在'given_thing_with'方法中调用代码块。换句话说,我无法在该块中编写代码来运行。

在此先感谢您的帮助。

这个问题的其余部分直接引用自 Rspec 书:

describe Thing do
  def create_thing(options)
    thing = Thing.new
    thing.set_status(options[:status])
    thing
  end

  it "should do something when ok" do
    thing = create_thing(:status => 'ok')
    thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
    ...
  end

  it "should do something else when not so good" do
    thing = create_thing(:status => 'not so good')
    thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
    ...
  end
end

您可以应用的一个习惯用法来进一步清理它是从对象中的初始化程序中产生 self 。假设 Thing 的 initialize() 方法执行此操作并且 set_status() 也执行此操作,您可以这样编写前面的内容:

describe Thing do
  def given_thing_with(options)
    yield Thing.new do |thing| 
      thing.set_status(options[:status])
    end
  end

  it "should do something when ok" do
    given_thing_with(:status => 'ok') do |thing|
      thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
      ... 
    end
  end

  it "should do something else when not so good" do
    given_thing_with(:status => 'not so good') do |thing|
      thing.do_fancy_stuff(1, true, :move => 'left', :obstacles => nil)
      ... 
    end
  end
end
4

2 回答 2

0

书中的示例有点混乱,因为Thing没有显示 的​​实现。要完成这项工作,您需要这样编写Thing

class Thing
  def initialize
    yield self
  end
end

given_thing_with被调用时,它会产生一个 new Thing,它会在构造时产生自己。这意味着当执行内部代码块(包含 的代码块thing.set_status)时,它将引用新建的Thing

于 2012-05-20T02:08:39.930 回答
0

书中的代码有两个问题。

1. 设置初始化器以产生自身

当 Thing 对象被创建时,它需要一个初始化器并且需要 yield 本身。

class Thing
  def initialize
    yield self
  end
end

但是,仅此一项仍然会导致错误,至少在我的系统上是 Ruby 1.9.3。具体来说,错误是“给产量(SyntaxError)的块”。这没有多大意义,因为这是我们希望它做的事情。不管怎样,这就是我得到的错误。

2.修复'block given to yield'错误

这并不那么明显,并且与 Ruby 或 'yield' 语句有关,但是使用本书中所写的 'do...end'创建一个块,如下所示会导致错误。

yield Thing.new do |thing| 
  thing.set_status(options[:status])
end

修复此错误很简单,只需使用大括号“{...}”创建块,如下所示。

yield Thing.new { |thing| 
  thing.set_status(options[:status])
}

这对于多行 Ruby 代码来说不是很好的形式,但它可以工作。

额外的。一系列收益如何设置“事物”对象的参数

问题已经解决,但这解释了它是如何工作的。

  • “调用者块”使用参数调用“given_thing_with”方法
  • 该方法向“调用者块”返回一个新的“事物”和一个块(我将其称为“屈服块”)
  • 要执行“yield block”,Thing 类需要初始化和 'yield self',否则 'set_status' 方法将永远不会运行,因为该块将被忽略
  • 新的“事物”已经在“调用者块”中并且已经设置了它的状态,现在执行了相关的方法
于 2012-05-20T12:16:54.210 回答