二つの変数を比較するとき;
- 変数の値だけを比べる eql eq
- 変数の値だけでなく、インスタンスのobject_idまで比べる equal be
もう少し掘り下げると、それぞれ以下のような仕組みになっている。
eql
Matcherの場所はここ。実際にはObject#eql?を呼んでいる。> arr.eql? :a => 1, :b => 2
=> true
equal
Matcherの場所はここ。実際にはObject#equal?を呼んでいる> arr.equal? :a => 1, :b => 2
=> false
eq
eqの定義はDSLの方にあるらしい。be
Matcherの定義はここ。beに引数があればBeSameAs#matches?がshouldによって呼ばれる仕組みになっている。整理して実際に試してみよう。以下のようにString, Array, Fixnumの型のインスタンスについてそれぞれeq, eql, equal, beのマッチャでSpecを実施してみた。
# ./tmp_spec.rb
require 'rspec'
describe 'eq' do
it('should find two strings are equal') { "".should eq ""}
it('should find two Arrays are equal') { {:a => 1}.should eq :a => 1 }
it('should find two Fixnums are equal') { 1.should eq 1 }
end
describe 'eql' do
it('should find two strings are equal') { "".should eql ""}
it('should find two Arrays are equal') { {:a => 1}.should eql :a => 1 }
it('should find two Fixnums are equal') { 1.should eql 1 }
end
describe 'equal' do
it('should find two Strings are equal') { "".should equal ""}
it('should find two Arrays are equal') { {:a => 1}.should equal :a => 1 }
it('should find two Fixnums are equal') { 1.should equal 1 }
end
describe 'be' do
it('should find two strings are equal') { "".should be ""}
it('hould find two Arrays are equal') { {:a => 1}.should be :a => 1 }
it('should find two Fixnums are equal') { 1.should be 1 }
end
結果は以下のとおり。equalとbeでは String, Arrayではobject_idまで同じかチェックしている。
$ rspec tmp_spec.rb -f doc
eq
should find two strings are equal
should find two Arrays are equal
should find two Fixnums are equal
eql
should find two strings are equal
should find two Arrays are equal
should find two Fixnums are equal
equal
should find two Strings are equal (FAILED - 1)
should find two Arrays are equal (FAILED - 2)
should find two Fixnums are equal
be
should find two strings are equal (FAILED - 3)
hould find two Arrays are equal (FAILED - 4)
should find two Fixnums are equal
Failures:
1) equal should find two Strings are equal
Failure/Error: it('should find two Strings are equal') { "".should equal ""}
expected # => ""
got # => ""
Compared using equal?, which compares object identity,
but expected and actual are not the same object. Use
'actual.should == expected' if you don't care about
object identity in this example.
# ./tmp_spec.rb:16:in `block (2 levels) in '
2) equal should find two Arrays are equal
Failure/Error: it('should find two Arrays are equal') { {:a => 1}.should equal :a => 1 }
expected # => {:a=>1}
got # => {:a=>1}
Compared using equal?, which compares object identity,
but expected and actual are not the same object. Use
'actual.should == expected' if you don't care about
object identity in this example.
Diff:{:a=>1}.==({:a=>1}) returned false even though the diff between {:a=>1} and {:a=>1} is empty. Check the implementation of {:a=>1}.==.
# ./tmp_spec.rb:17:in `block (2 levels) in '
3) be should find two strings are equal
Failure/Error: it('should find two strings are equal') { "".should be ""}
expected # => ""
got # => ""
Compared using equal?, which compares object identity,
but expected and actual are not the same object. Use
'actual.should == expected' if you don't care about
object identity in this example.
# ./tmp_spec.rb:22:in `block (2 levels) in '
4) be hould find two Arrays are equal
Failure/Error: it('hould find two Arrays are equal') { {:a => 1}.should be :a => 1 }
expected # => {:a=>1}
got # => {:a=>1}
Compared using equal?, which compares object identity,
but expected and actual are not the same object. Use
'actual.should == expected' if you don't care about
object identity in this example.
Diff:{:a=>1}.==({:a=>1}) returned false even though the diff between {:a=>1} and {:a=>1} is empty. Check the implementation of {:a=>1}.==.
# ./tmp_spec.rb:23:in `block (2 levels) in '
Finished in 0.01339 seconds
12 examples, 4 failures
Failed examples:
rspec ./tmp_spec.rb:16 # equal should find two Strings are equal
rspec ./tmp_spec.rb:17 # equal should find two Arrays are equal
rspec ./tmp_spec.rb:22 # be should find two strings are equal
rspec ./tmp_spec.rb:23 # be hould find two Arrays are equal
でもこのFixnumの比較に関しては Specが成功してしまう。
describe 'be' do
it('should find two Fixnums are equal') { 1.should be 1 }
end
これはFixnumのidがrubyを起動時に実行されて既に予約済みだからのようだ
irb/ pry
[28] pry(main)> 1.object_id => 3 [29] pry(main)> 2.object_id => 5 [30] pry(main)> 3.object_id => 7 [35] pry(main)> 1.object_id => 3 [32] pry(main)> 1.0.object_id => 105431370
このようにFixnumのインスタンスはシングルトンで定義されているようだ。