Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implicit subject should be memoized with let

  • Loading branch information...
commit df58558ecc0984bce91612a9acf3c70baaf0aaa3 1 parent 65700c6
@exviva exviva authored
View
3  lib/rspec/core/example_group.rb
@@ -13,6 +13,8 @@ module Core
# which serves as a wrapper for an instance of the ExampleGroup in which it
# is declared.
class ExampleGroup
+ include Let # Subject::ExampleGroupMethods depends on this module, so include it first
+
extend MetadataHashBuilder::WithDeprecationWarning
extend Extensions::ModuleEvalWithArgs
extend Subject::ExampleGroupMethods
@@ -21,7 +23,6 @@ class ExampleGroup
include Extensions::InstanceEvalWithArgs
include Subject::ExampleMethods
include Pending
- include Let
include SharedExampleGroup
# @private
View
89 lib/rspec/core/subject.rb
@@ -1,53 +1,41 @@
module RSpec
module Core
+ # @note `subject` was contributed by Joe Ferris to support the one-liner
+ # syntax embraced by shoulda matchers:
+ #
+ # describe Widget do
+ # it { should validate_presence_of(:name) }
+ # end
+ #
+ # While the examples below demonstrate how to use `subject`
+ # explicitly in examples, we recommend that you define a method with
+ # an intention revealing name instead.
+ #
+ # @example
+ #
+ # # explicit declaration of subject
+ # describe Person do
+ # subject { Person.new(:birthdate => 19.years.ago) }
+ # it "should be eligible to vote" do
+ # subject.should be_eligible_to_vote
+ # # ^ ^ explicit reference to subject not recommended
+ # end
+ # end
+ #
+ # # implicit subject => { Person.new }
+ # describe Person do
+ # it "should be eligible to vote" do
+ # subject.should be_eligible_to_vote
+ # # ^ ^ explicit reference to subject not recommended
+ # end
+ # end
+ #
+ # # one-liner syntax - should is invoked on subject
+ # describe Person do
+ # it { should be_eligible_to_vote }
+ # end
module Subject
module ExampleMethods
- # Returns the example group's `subject`.
- #
- # @note `subject` was contributed by Joe Ferris to support the one-liner
- # syntax embraced by shoulda matchers:
- #
- # describe Widget do
- # it { should validate_presence_of(:name) }
- # end
- #
- # While the examples below demonstrate how to use `subject`
- # explicitly in examples, we recommend that you define a method with
- # an intention revealing name instead.
- #
- # @example
- #
- # # explicit declaration of subject
- # describe Person do
- # subject { Person.new(:birthdate => 19.years.ago) }
- # it "should be eligible to vote" do
- # subject.should be_eligible_to_vote
- # # ^ ^ explicit reference to subject not recommended
- # end
- # end
- #
- # # implicit subject => { Person.new }
- # describe Person do
- # it "should be eligible to vote" do
- # subject.should be_eligible_to_vote
- # # ^ ^ explicit reference to subject not recommended
- # end
- # end
- #
- # # one-liner syntax - should is invoked on subject
- # describe Person do
- # it { should be_eligible_to_vote }
- # end
- #
- # @see ExampleGroupMethods#subject
- # @see #should
- def subject
- # This logic defines an implicit subject.
- # Explicit `subject` declarations re-define this method.
- described = described_class || self.class.description
- Class === described ? described.new : described
- end
-
# When `should` is called with no explicit receiver, the call is
# delegated to the object returned by `subject`. Combined with an
# implicit subject this supports very concise expressions.
@@ -189,13 +177,20 @@ def its(attribute, &block)
# end
# end
#
- # @see ExampleMethods#subject
# @see ExampleMethods#should
def subject(name=nil, &block)
let(:subject, &block)
alias_method name, :subject if name
end
+ def self.extended(base)
+ # This logic defines an implicit subject.
+ base.subject do
+ described = described_class || self.class.description
+ Class === described ? described.new : described
+ end
+ end
+
# Just like `subject`, except the block is invoked by an implicit `before`
# hook. This serves a dual purpose of setting up state and providing a
# memoized reference to that state.
View
29 spec/rspec/core/subject_spec.rb
@@ -338,4 +338,33 @@ def false_if_first_time
end
end
end
+
+ describe 'using subject in before and let blocks' do
+ shared_examples_for 'a subject' do
+ let(:subject_id_in_let) { subject.object_id }
+ before { @subject_id_in_before = subject.object_id }
+
+ it 'should be memoized' do
+ expect(subject_id_in_let).to eq(@subject_id_in_before)
+ end
+
+ it { should eq(subject) }
+ end
+
+ describe Object do
+ context 'with implicit subject' do
+ it_should_behave_like 'a subject'
+ end
+
+ context 'with explicit subject' do
+ subject { Object.new }
+ it_should_behave_like 'a subject'
+ end
+
+ context 'with a constant subject'do
+ subject { 123 }
+ it_should_behave_like 'a subject'
+ end
+ end
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.