class ContextState
Holds the state of the describe
block that is being evaluated.
Every example (i.e. it
block) is evaluated in a context, which
may include state set up in before :each
or before
:all
blocks.
Attributes
Public Class Methods
# File lib/mspec/runner/context.rb, line 15 def initialize(mod, options=nil) @to_s = mod.to_s if options.is_a? Hash @options = options else @to_s += "#{".:#".include?(options[0,1]) ? "" : " "}#{options}" if options @options = { } end @options[:shared] ||= false @parsed = false @before = { :all => [], :each => [] } @after = { :all => [], :each => [] } @pre = {} @post = {} @examples = [] @parent = nil @parents = [self] @children = [] @mock_verify = Proc.new { Mock.verify_count } @mock_cleanup = Proc.new { Mock.cleanup } @expectation_missing = Proc.new { raise SpecExpectationNotFoundError } end
Public Instance Methods
Adds a nested ContextState in a shared ContextState to a containing ContextState.
Normal adoption is from the parent's perspective. But adopt is a good verb and it's reasonable for the child to adopt the parent as well. In this case, manipulating state from inside the child avoids needlessly exposing the state to manipulate it externally in the dup. (See it_should_behave_like)
# File lib/mspec/runner/context.rb, line 86 def adopt(parent) self.parent = parent @examples = @examples.map do |example| example = example.dup example.context = self example end children = @children @children = [] children.each { |child| child.dup.adopt self } end
Records after(:each) and after(:all) blocks.
# File lib/mspec/runner/context.rb, line 122 def after(what, &block) return if MSpec.guarded? block ? @after[what].unshift(block) : @after[what] end
Records before(:each) and before(:all) blocks.
# File lib/mspec/runner/context.rb, line 116 def before(what, &block) return if MSpec.guarded? block ? @before[what].push(block) : @before[what] end
Add the ContextState instance
child
to the list of nested describe blocks.
# File lib/mspec/runner/context.rb, line 74 def child(child) @children << child end
Evaluates the block and resets the toplevel ContextState
to parent.
# File lib/mspec/runner/context.rb, line 137 def describe(&block) @parsed = protect @to_s, block, false MSpec.register_current parent MSpec.register_shared self if shared? end
Returns a description string generated from self and all parents
# File lib/mspec/runner/context.rb, line 144 def description @description ||= parents.map { |p| p.to_s }.compact.join(" ") end
Removes filtered examples. Returns true if there are examples left to evaluate.
# File lib/mspec/runner/context.rb, line 184 def filter_examples @examples.reject! { |ex| ex.filtered? } not @examples.empty? end
Remove caching when a ContextState is dup'd for shared specs.
# File lib/mspec/runner/context.rb, line 41 def initialize_copy(other) @pre = {} @post = {} end
Creates an ExampleState instance for the block and stores it in a list of examples to evaluate unless the example is filtered.
# File lib/mspec/runner/context.rb, line 129 def it(desc, &block) example = ExampleState.new(self, desc, block) MSpec.actions :add, example return if MSpec.guarded? @examples << example end
Injects the before/after blocks and examples from the shared describe block
into this ContextState
instance.
# File lib/mspec/runner/context.rb, line 150 def it_should_behave_like(desc) return if MSpec.guarded? unless state = MSpec.retrieve_shared(desc) raise Exception, "Unable to find shared 'describe' for #{desc}" end state.before(:all).each { |b| before :all, &b } state.before(:each).each { |b| before :each, &b } state.after(:each).each { |b| after :each, &b } state.after(:all).each { |b| after :all, &b } state.examples.each do |example| example = example.dup example.context = self @examples << example end state.children.each do |child| child.dup.adopt self end end
Set the parent (enclosing) ContextState
for this state.
Creates the parents
list.
# File lib/mspec/runner/context.rb, line 54 def parent=(parent) @description = nil if shared? @parent = nil else @parent = parent parent.child self if parent @parents = [self] state = parent while state @parents.unshift state state = state.parent end end end
Returns a list of all after(what
) blocks from self and any
parents. The list is in reverse order. In other words, the blocks defined
in inner describes are in the list before those defined in outer describes,
and in a particular describe block those defined later are in the list
before those defined earlier.
# File lib/mspec/runner/context.rb, line 111 def post(what) @post[what] ||= parents.inject([]) { |l, s| l.unshift(*s.after(what)) } end
Returns a list of all before(what
) blocks from self and any
parents.
# File lib/mspec/runner/context.rb, line 102 def pre(what) @pre[what] ||= parents.inject([]) { |l, s| l.push(*s.before(what)) } end
Evaluates the examples in a ContextState
. Invokes the MSpec events for :enter, :before, :after, :leave.
# File lib/mspec/runner/context.rb, line 191 def process MSpec.register_current self if @parsed and filter_examples MSpec.shuffle @examples if MSpec.randomize? MSpec.actions :enter, description if protect "before :all", pre(:all) @examples.each do |state| MSpec.repeat do @state = state example = state.example MSpec.actions :before, state if protect "before :each", pre(:each) MSpec.clear_expectations if example passed = protect nil, example MSpec.actions :example, state, example protect nil, @expectation_missing unless MSpec.expectation? or not passed end protect "after :each", post(:each) protect "Mock.verify_count", @mock_verify end protect "Mock.cleanup", @mock_cleanup MSpec.actions :after, state @state = nil end end protect "after :all", post(:all) else protect "Mock.cleanup", @mock_cleanup end MSpec.actions :leave end MSpec.register_current nil children.each { |child| child.process } end
Evaluates each block in blocks
using the
MSpec.protect
method so that exceptions are handled and
tallied. Returns true and does NOT evaluate any blocks if
check
is true and MSpec.mode?(:pretend)
is true.
# File lib/mspec/runner/context.rb, line 177 def protect(what, blocks, check=true) return true if check and MSpec.mode? :pretend Array(blocks).all? { |block| MSpec.protect what, &block } end