Skip to content

Commit

Permalink
ExampleGroup .its() creates new Example with a subject modifier
Browse files Browse the repository at this point in the history
  • Loading branch information
gsterndale committed Apr 17, 2010
1 parent a275d81 commit d4b365e
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 6 deletions.
45 changes: 45 additions & 0 deletions example_specs/passing/subject_example.rb
@@ -0,0 +1,45 @@
require File.dirname(__FILE__) + '/spec_helper'

module SubjectExample
class OneThing
attr_accessor :what_things_do
def initialize
self.what_things_do = "stuff"
end
end

# implicit subject
describe OneThing do
it "should do what things do" do
subject.what_things_do.should == "stuff"
end
it "should be a OneThing" do
should == subject
end
its(:what_things_do) { should == "stuff" }
end

# explicit subject
describe SubjectExample::OneThing do
subject { SubjectExample::OneThing.new }
it "should do what things do" do
subject.what_things_do.should == "stuff"
end
it "should be a OneThing" do
should == subject
end
its(:what_things_do) { should == "stuff" }
end

# modified subject
describe OneThing do
subject { SubjectExample::OneThing.new }
before { subject.what_things_do = "more stuff" }
it "should do what things do" do
subject.what_things_do.should == "more stuff"
end
its(:what_things_do) { should == "more stuff" }
end

end

4 changes: 4 additions & 0 deletions lib/rspec/core/example.rb
Expand Up @@ -35,6 +35,10 @@ def inspect
@metadata[:full_description]
end

def subject_modifier
@metadata[:subject_modifier]
end

def to_s
inspect
end
Expand Down
7 changes: 7 additions & 0 deletions lib/rspec/core/example_group.rb
Expand Up @@ -28,6 +28,13 @@ def self.#{name}(desc=nil, options={}, &block)
END_RUBY
end

def self.its(modifier, desc=nil, options={}, &block)
options.update(:pending => true) unless block
options.update(:caller => caller)
options.update(:subject_modifier => modifier)
examples << Rspec::Core::Example.new(self, desc, options, block)
end

define_example_method :example

class << self
Expand Down
29 changes: 23 additions & 6 deletions lib/rspec/core/subject.rb
@@ -1,17 +1,17 @@
module Rspec
module Core
module Subject

def self.included(kls)
kls.extend ClassMethods
kls.__send__ :alias_method, :__should_for_example_group__, :should
kls.__send__ :alias_method, :__should_not_for_example_group__, :should_not
end

def subject
@subject ||= instance_eval(&self.class.subject)
modify_subject? ? modified_subject : unmodified_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
Expand All @@ -37,7 +37,7 @@ def should(matcher=nil, message=nil)
def should_not(matcher=nil, message=nil)
self == subject ? self.__should_not_for_example_group__(matcher) : subject.should_not(matcher,message)
end

module ClassMethods
# Defines an explicit subject for an example group which can then be the
# implicit receiver (through delegation) of calls to +should+.
Expand All @@ -54,7 +54,7 @@ module ClassMethods
def subject(&block)
block ? @explicit_subject_block = block : explicit_subject || implicit_subject
end

attr_reader :explicit_subject_block # :nodoc:

private
Expand All @@ -72,6 +72,23 @@ def implicit_subject
Class === described ? lambda { described.new } : lambda { described }
end
end

private

def modify_subject?
!running_example.nil? &&
!running_example.subject_modifier.nil? &&
running_example.state == :block
end

def unmodified_subject
@unmodified_subject ||= instance_eval(&self.class.subject)
end

def modified_subject
unmodified_subject.send(running_example.subject_modifier)
end

end
end
end
26 changes: 26 additions & 0 deletions spec/rspec/core/example_group_spec.rb
Expand Up @@ -168,6 +168,12 @@ module Rspec::Core
group.examples.size.should == 1
end

it "should allow adding an example using 'its'" do
group = ExampleGroup.create
group.its(:some_method) { }
group.examples.size.should == 1
end

it "should expose all examples at examples" do
group = ExampleGroup.create
group.it("should do something 1") { }
Expand Down Expand Up @@ -374,6 +380,26 @@ def self.count
SelfObserver.cache.length.should == 1
end
end

describe "example added with its" do
it "should have a subject_modifier" do
group = ExampleGroup.create
examples = group.its(:some_method) { }
example = examples.last
example.subject_modifier.should === :some_method
end
end

describe "#its" do
its(:class, "should be ExampleGroup") { should == Rspec::Core::ExampleGroup }
it "does not interfere between tests" do
subject.class.should == Rspec::Core::ExampleGroup
end
context "subject modified in before block" do
before { subject.class.should == Rspec::Core::ExampleGroup }
its(:class, "should be ExampleGroup") { should == Rspec::Core::ExampleGroup }
end
end
end

end
4 changes: 4 additions & 0 deletions spec/rspec/core/example_spec.rb
Expand Up @@ -29,6 +29,10 @@
@example.should respond_to(:example_block)
end

it "should have one for its subject modifier" do
@example.should respond_to(:subject_modifier)
end

it "should have one for its state" do
@example.should respond_to(:state)
end
Expand Down

0 comments on commit d4b365e

Please sign in to comment.