まずshouldが全てのinstaceで実効可能なのはKernel classに対して定義されているからです。
shouldの居場所
# spec/expectations/extensions/kernel.rb def should(matcher=nil, message=nil, &block) Spec::Expectations::PositiveExpectationHandler.handle_matcher(self, matcher, message, &block) end
PositiveExpectationHandler#handle_matcherの居場所
# spec/expectations/handler.rb match = matcher.matches?(actual, &block)
RSpecの構造
/lib
└── spec
├── expectations
│ └── extensions
└── matchers
└── extensions
expectations/extensionsはその名のとおり拡張を行う。spec/expectations/extensions/にはkernel.rbのみがある。
RSpecの構造
spec/matchersには見慣れた名前が。。
ずっとshouldはきっと variable.be_a Stringてかくと variable.is_a? Stringって変えてくれると想像して信じていたけど、実際の条件は逐一Matcherに書いてあるらしい。例えばbe_kind_of matcher
def be_a_kind_of(expected)
Matcher.new :be_a_kind_of, expected do |_expected_|
match do |actual|
actual.kind_of?(_expected_)
end
end
end
be Matcherには僕が想像していたような機能がある
§
Matcherを自作したい時は Object.should be_fine => Object.fine?の法則に当てはまるfine? methodを持つObject定義してあげるか、matches?にrespondするMatcherを書いてmatcher.rbみたいに requireしてあげればいいはず。
§
蛇足だけど
上記 kernel.rbのとおり引数にmessageを渡してfailure時に何が失敗したのかわかりやすくすることもできる別のshould、Subject#shouldの居場所
これは以下の用に書いたときのshouldにちがいない(と信じてる)
let(:int) { 16 }
subject { int }
it "should be even" do
should be_even
end
Change
例えばこんな感じに書いたときはexpect{ array << 42 }.to change{ array.size }.from(0).to(1)
initializeで @value_proc に{ array << 42 }が代入されて、from methodで@fromに0が、to methodで@to に1が代入される。比較は他のmatchers同様matches?で @beforeと@afterを比較して行われる。event_procには array.sizeが代入される。
@before = evaluate_value_proc event_proc.call @after = evaluate_value_procスライドすばらしいので全部読むべし