0

これは、Rspec book (page 149) から抜粋した、Rspec でヘルパー メソッドを作成する方法の説明です。この例では、「モノ」オブジェクトが作成されたときにトリガーされる「set_status」というメソッドがあることを前提としています。

どちらのコード セットも、新しい「モノ」オブジェクトを作成し、ステータスを設定してから、「fancy_stuff」を実行します。最初のコード セットは、私には完全に明確です。それがトリガーした「it」ステートメントの 1 つ。その後、オプションを指定して「create_thing」メソッドを呼び出します。新しい「モノ」オブジェクトが作成され、「オプション」属性をパラメータとして「set_status」メソッドが呼び出されます。

2 番目のコード セットも同様です。「it」ステートメントの 1 つがトリガーされ、「:status」ハッシュ割り当てをパラメーターとして渡しながら「given_thing_with」メソッドを呼び出します。「given_thing_with」メソッド内で、「Thing.new」をパラメータとして「yield」がトリガーされます。これは私が問題を抱えているところです。このコードを実行しようとすると、「block given to yield」というエラーが表示されます。「given_thing_with」メソッドを呼び出した「it」ステートメントから、yield によって渡されるすべての属性がパイプ ブレース内の「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

これをさらにクリーンアップするために適用できるイディオムの 1 つは、オブジェクトの初期化子から 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

本のコードには2つの問題があります。

1.初期化子を設定してそれ自体を生成する

Thingオブジェクトを作成するときは、初期化子とyield自体が必要です。

class Thing
  def initialize
    yield self
  end
end

ただし、これだけでも、少なくとも私のシステムであるRuby1.9.3ではエラーが発生します。具体的には、エラーは「yieldに与えられたブロック(SyntaxError)」です。これは私たちが望んでいることなので、あまり意味がありません。とんでもない、それは私が得るエラーです。

2.「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コードには適していませんが、機能します。

追加。一連のyieldが「Thing」オブジェクトのパラメータを設定するためにどのように機能するか

問題はすでに修正されていますが、これはそれがどのように機能するかを説明しています。

  • 「呼び出し元ブロック」は、パラメーターを使用して「given_thing_with」メソッドを呼び出します
  • そのメソッドは、「呼び出し元ブロック」に新しい「モノ」とブロックを生成します(これを「生成ブロック」と呼びます)。
  • 「yieldブロック」を実行するには、Thingクラスに初期化と「yieldself」が必要です。そうでない場合、ブロックが無視されるため、「set_status」メソッドは実行されません。
  • 新しい「Thing」はすでに「callerblock」にあり、ステータスが設定されているため、関連するメソッドが実行されます。
于 2012-05-20T12:16:54.210 に答える
0

の実装が示されていないため、本の例は少し混乱してThingいます。これを機能させるには、次Thingのように記述する必要があります。

class Thing
  def initialize
    yield self
  end
end

given_thing_with呼び出されると newThingが生成され、それが構築されるとそれ自体が生成されます。これは、内部コード ブロック ( を含むものthing.set_status) が実行されると、新しく構築された への参照を持つことを意味しThingます。

于 2012-05-20T02:08:39.930 に答える