Class: ContextState

Inherits:
Object show all
Defined in:
lib/mspec/runner/context.rb

Overview

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.

– A note on naming: this is named ContextState rather than DescribeState because describe is the keyword in the DSL for refering to the context in which an example is evaluated, just as it refers to the example itself. ++

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mod, options = nil) ⇒ ContextState

Returns a new instance of ContextState.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 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

Instance Attribute Details

#childrenObject (readonly)

Returns the value of attribute children.



13
14
15
# File 'lib/mspec/runner/context.rb', line 13

def children
  @children
end

#examplesObject (readonly)

Returns the value of attribute examples.



13
14
15
# File 'lib/mspec/runner/context.rb', line 13

def examples
  @examples
end

#parentObject

Returns the value of attribute parent.



13
14
15
# File 'lib/mspec/runner/context.rb', line 13

def parent
  @parent
end

#parentsObject (readonly)

Returns the value of attribute parents.



13
14
15
# File 'lib/mspec/runner/context.rb', line 13

def parents
  @parents
end

#stateObject (readonly)

Returns the value of attribute state.



13
14
15
# File 'lib/mspec/runner/context.rb', line 13

def state
  @state
end

#to_sObject (readonly)

Returns the value of attribute to_s.



13
14
15
# File 'lib/mspec/runner/context.rb', line 13

def to_s
  @to_s
end

Instance Method Details

#after(what, &block) ⇒ Object

Records after(:each) and after(:all) blocks.



93
94
95
96
# File 'lib/mspec/runner/context.rb', line 93

def after(what, &block)
  return if MSpec.guarded?
  block ? @after[what].unshift(block) : @after[what]
end

#before(what, &block) ⇒ Object

Records before(:each) and before(:all) blocks.



87
88
89
90
# File 'lib/mspec/runner/context.rb', line 87

def before(what, &block)
  return if MSpec.guarded?
  block ? @before[what].push(block) : @before[what]
end

#child(child) ⇒ Object

Add the ContextState instance child to the list of nested describe blocks.



68
69
70
# File 'lib/mspec/runner/context.rb', line 68

def child(child)
  @children << child
end

#describe(&block) ⇒ Object

Evaluates the block and resets the toplevel ContextState to #parent.



108
109
110
111
112
# File 'lib/mspec/runner/context.rb', line 108

def describe(&block)
  @parsed = protect @to_s, block, false
  MSpec.register_current parent
  MSpec.register_shared self if shared?
end

#descriptionObject

Returns a description string generated from self and all parents



115
116
117
# File 'lib/mspec/runner/context.rb', line 115

def description
  @description ||= parents.map { |p| p.to_s }.join(" ")
end

#filter_examplesObject

Removes filtered examples. Returns true if there are examples left to evaluate.



154
155
156
157
# File 'lib/mspec/runner/context.rb', line 154

def filter_examples
  @examples.reject! { |ex| ex.filtered? }
  not @examples.empty?
end

#it(desc, &block) ⇒ Object

Creates an ExampleState instance for the block and stores it in a list of examples to evaluate unless the example is filtered.



100
101
102
103
104
105
# File 'lib/mspec/runner/context.rb', line 100

def it(desc, &block)
  example = ExampleState.new(self, desc, block)
  MSpec.actions :add, example
  return if MSpec.guarded?
  @examples << example
end

#it_should_behave_like(desc) ⇒ Object

Injects the before/after blocks and examples from the shared describe block into this ContextState instance.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/mspec/runner/context.rb', line 121

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.examples.each { |ex| ex.context = self; @examples << ex }
  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 }

  # There is a potential race here if mspec ever implements concurrency
  # in process. Right now, the only way to run specs concurrently is
  # with multiple processes, so we ignore this for the sake of simplicity.
  state.children.each do |child|
    child.replace_parent self
    @children << child
  end
end

#post(what) ⇒ Object

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.



82
83
84
# File 'lib/mspec/runner/context.rb', line 82

def post(what)
  @post[what] ||= parents.inject([]) { |l, s| l.unshift(*s.after(what)) }
end

#pre(what) ⇒ Object

Returns a list of all before(what) blocks from self and any parents.



73
74
75
# File 'lib/mspec/runner/context.rb', line 73

def pre(what)
  @pre[what] ||= parents.inject([]) { |l, s| l.push(*s.before(what)) }
end

#processObject

Evaluates the examples in a ContextState. Invokes the MSpec events for :enter, :before, :after, :leave.



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/mspec/runner/context.rb', line 161

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|
        @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
      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

#protect(what, blocks, check = true) ⇒ Object

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.



147
148
149
150
# File 'lib/mspec/runner/context.rb', line 147

def protect(what, blocks, check=true)
  return true if check and MSpec.mode? :pretend
  Array(blocks).all? { |block| MSpec.protect what, &block }
end

#replace_parent(parent) ⇒ Object



60
61
62
63
64
# File 'lib/mspec/runner/context.rb', line 60

def replace_parent(parent)
  @parents[0] = parent

  children.each { |child| child.replace_parent parent }
end

#shared?Boolean

Returns true if this is a shared ContextState. Essentially, when created with: describe “Something”, :shared => true { … }

Returns:

  • (Boolean)


42
43
44
# File 'lib/mspec/runner/context.rb', line 42

def shared?
  return @options[:shared]
end