如何在Rspec中使用yield self

时间:2012-05-18 22:15:24

标签: ruby rspec yield

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

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

第二组代码类似。其中一个'it'语句被触发,然后调用'given_thing_with'方法,同时将':status'哈希赋值作为参数传递。在'given_thing_with'方法中,以'Thing.new'作为参数触发'yield'。这是我遇到麻烦的地方。当我尝试运行此代码时,出现“block to yield”错误。我理解,yield传递的任何属性都将从调用'given_thing_with'方法的'it'语句返回到pipe括号中的'thing'。我可以得到新的

我不明白为什么在'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

你可以申请清理它的一个习惯用法是从你对象的初始化者中产生自我。假设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

2 个答案:

答案 0 :(得分:0)

本书中的示例有点令人困惑,因为Thing的实现未显示。要完成这项工作,您需要像这样编写Thing

class Thing
  def initialize
    yield self
  end
end

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

答案 1 :(得分:0)

本书代码存在2个问题。

1。设置初始化程序以自行生成

创建Thing对象时,它需要一个初始化程序,并且需要自己屈服。

class Thing
  def initialize
    yield self
  end
end

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

2。修复“产生阻止的块”错误

这不是那么明显,与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代码来说不是一个好形式,但它可以工作。

<强>附加。一系列收益如何用于设置“Thing”对象的参数

问题已经解决,但这解释了它的工作原理。

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