まず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スライドすばらしいので全部読むべし