RSpecのshouldはもう古い！新しい記法expectを使おう！


RspecのVersion2.11から

```ruby:old_spec.rb
foo.should eq(bar)
foo.should_not eq(bar)
```

を

```ruby:new_spec.rb
expect(foo).to eq(bar)
expect(foo).not_to eq(bar)
```

というように書くようになりました。

別にshouldを使った記法がなくなったわけではありませんが、
https://github.com/rspec/rspec-expectations
のREADME.mdには、もう新しいSyntaxの説明しか載っていないし、今後はexpectの方を使っていくほうがいいでしょう。


http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
には、新しいSyntaxを導入した背景が説明されています。
簡潔に書くと、shouldだとBasicObjectを継承したクラスのテストを書くときに不具合が起こるみたいですね。

## 移行方法

### 基本

基本的には、上に書いたように、

- `foo.should` を `expect(foo).to` に
- `foo.should_not` を `expect(foo).not_to` に

置き換えるだけです。

### 比較演算子をとる

ただし、	shouldの後に直接オペレータをとる記法は使えなくなりました。
具体的には、

```ruby:old_operator_expectations.rb
foo.should == bar
"a string".should_not =~ /a regex/
[1, 2, 3].should =~ [2, 1, 3]

foo.should < bar  # <=, >, >= も同様
```

を

```ruby:new_operator_expectations.rb
expect(foo).to eq bar
expect("a string").not_to match /a regex/
expect([1, 2, 3]).to match_array [2, 1, 3]

expect(foo).to be < bar  # <=, >, >= も同様
```

のように変えます。
つまり、

- `==`の代わりに`eq`
- 正規表現関係の`=~`の代わりに`match`
- 配列の`=~`の代わりに`match_array`

を使えばいいんですね。

shouldの後に比較演算子`<`をとる記法の代わりは、`be <`というように`be`を入れれば解決します。
`should(to) less than`より`should(to) be less than`の方が英語的に正しいので、これはこれでOKですね。

### ブロックをとる

また、このexpect記法だと、ブロックをとることができるので、

```ruby:old_block_expectations.rb
lambda { do_something }.should raise_error(SomeError)
```

を

```ruby:new_block_expectations.rb
expect { something }.to raise_error(SomeError)
```

と書けるので、統一感があっていいですね。

## 移行が終わったら

```ruby:config/initializers/rspec.rb
RSpec.configure do |config|
  config.expect_with :rspec do |c|
    c.syntax = :expect    # disables `should`
  end
end
```

とすると、今後shouldを使った書き方ができなくなります。

ちなみにデフォルトでは

```ruby:
    c.syntax = [:should, :expect]  # enables both `should` and `expect`
```

と設定したのと同じになっています。


## 他のシチュエーションの書き方一覧

基本的に置き換えは上記の通り行うと済みますが、参照用に
https://github.com/rspec/rspec-expectations
に載っている他の書き方をそのまま転載しておきます。


### Equivalence

```ruby
expect(actual).to eq(expected)  # passes if actual == expected
expect(actual).to eql(expected) # passes if actual.eql?(expected)
```

Note: The new `expect` syntax no longer supports `==` matcher.

### Identity

```ruby
expect(actual).to be(expected)    # passes if actual.equal?(expected)
expect(actual).to equal(expected) # passes if actual.equal?(expected)
```

### Comparisons

```ruby
expect(actual).to be >  expected
expect(actual).to be >= expected
expect(actual).to be <= expected
expect(actual).to be <  expected
expect(actual).to be_within(delta).of(expected)
```

### Regular expressions

```ruby
expect(actual).to match(/expression/)
```

Note: The new `expect` syntax no longer supports `=~` matcher.

### Types/classes

```ruby
expect(actual).to be_an_instance_of(expected)
expect(actual).to be_a_kind_of(expected)
```

### Truthiness

```ruby
expect(actual).to be_true  # passes if actual is truthy (not nil or false)
expect(actual).to be_false # passes if actual is falsy (nil or false)
expect(actual).to be_nil   # passes if actual is nil
```

### Expecting errors

```ruby
expect { ... }.to raise_error
expect { ... }.to raise_error(ErrorClass)
expect { ... }.to raise_error("message")
expect { ... }.to raise_error(ErrorClass, "message")
```

### Expecting throws

```ruby
expect { ... }.to throw_symbol
expect { ... }.to throw_symbol(:symbol)
expect { ... }.to throw_symbol(:symbol, 'value')
```

### Yielding

```ruby
expect { |b| 5.tap(&b) }.to yield_control # passes regardless of yielded args

expect { |b| yield_if_true(true, &b) }.to yield_with_no_args # passes only if no args are yielded

expect { |b| 5.tap(&b) }.to yield_with_args(5)
expect { |b| 5.tap(&b) }.to yield_with_args(Fixnum)
expect { |b| "a string".tap(&b) }.to yield_with_args(/str/)

expect { |b| [1, 2, 3].each(&b) }.to yield_successive_args(1, 2, 3)
expect { |b| { :a => 1, :b => 2 }.each(&b) }.to yield_successive_args([:a, 1], [:b, 2])
```

### Predicate matchers

```ruby
expect(actual).to be_xxx         # passes if actual.xxx?
expect(actual).to have_xxx(:arg) # passes if actual.has_xxx?(:arg)
```

### Ranges (Ruby >= 1.9 only)

```ruby
expect(1..10).to cover(3)
```

### Collection membership

```ruby
expect(actual).to include(expected)
expect(actual).to start_with(expected)
expect(actual).to end_with(expected)
```

#### Examples

```ruby
expect([1,2,3]).to include(1)
expect([1,2,3]).to include(1, 2)
expect([1,2,3]).to start_with(1)
expect([1,2,3]).to start_with(1,2)
expect([1,2,3]).to end_with(3)
expect([1,2,3]).to end_with(2,3)
expect({:a => 'b'}).to include(:a => 'b')
expect("this string").to include("is str")
expect("this string").to start_with("this")
expect("this string").to end_with("ring")
```