module Spec module Example module Subject module ExampleGroupMethods # Defines an explicit subject for an example group which can then be the # implicit receiver (through delegation) of calls to +should+. # # == Examples # # describe CheckingAccount, "with $50" do # subject { CheckingAccount.new(:amount => 50, :currency => :USD) } # it { should have_a_balance_of(50, :USD) } # it { should_not be_overdrawn } # its(:currency) { should == :USD } # end # # See +ExampleMethods#should+ for more information about this approach. def subject(&block) block.nil? ? explicit_subject || implicit_subject : @explicit_subject_block = block end def its(attribute, &block) describe(attribute) do example do self.class.class_eval do define_method(:subject) do super().send(attribute) end end instance_eval(&block) end end end attr_reader :explicit_subject_block # :nodoc: private def explicit_subject group = self while group.respond_to?(:explicit_subject_block) return group.explicit_subject_block if group.explicit_subject_block group = group.superclass end end def implicit_subject (described_class ? proc {described_class.new} : proc {description_args.first}) end end module ExampleMethods alias_method :__should_for_example_group__, :should alias_method :__should_not_for_example_group__, :should_not # Returns the subject defined in ExampleGroupMethods#subject. The # subject block is only executed once per example, the result of which # is cached and returned by any subsequent calls to +subject+. # # If a class is passed to +describe+ and no subject is explicitly # declared in the example group, then +subject+ will return a new # instance of that class. # # == Examples # # # explicit subject defined by the subject method # describe Person do # subject { Person.new(:birthdate => 19.years.ago) } # it "should be eligible to vote" do # subject.should be_eligible_to_vote # end # end # # # implicit subject => { Person.new } # describe Person do # it "should be eligible to vote" do # subject.should be_eligible_to_vote # end # end def subject @subject ||= instance_eval(&self.class.subject) end # When +should+ is called with no explicit receiver, the call is # delegated to the object returned by +subject+. Combined with # an implicit subject (see +subject+), this supports very concise # expressions. # # == Examples # # describe Person do # it { should be_eligible_to_vote } # end def should(matcher=nil, message=nil) self == subject ? self.__should_for_example_group__(matcher) : subject.should(matcher,message) end # Just like +should+, +should_not+ delegates to the subject (implicit or # explicit) of the example group. # # == Examples # # describe Person do # it { should_not be_eligible_to_vote } # end def should_not(matcher=nil, message=nil) self == subject ? self.__should_not_for_example_group__(matcher) : subject.should_not(matcher,message) end end end end end