Class: XSpec::Context

Inherits:
Object
  • Object
show all
Extended by:
DSL
Defined in:
lib/xspec/data_structures.rb

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DSL

describe, it, it_behaves_like_a, let, shared_context

Class Attribute Details

.childrenObject (readonly)

Returns the value of attribute children.



23
24
25
# File 'lib/xspec/data_structures.rb', line 23

def children
  @children
end

.evaluatorObject (readonly)

Returns the value of attribute evaluator.



23
24
25
# File 'lib/xspec/data_structures.rb', line 23

def evaluator
  @evaluator
end

.nameObject (readonly)

Returns the value of attribute name.



23
24
25
# File 'lib/xspec/data_structures.rb', line 23

def name
  @name
end

.units_of_workObject (readonly)

Returns the value of attribute units_of_work.



23
24
25
# File 'lib/xspec/data_structures.rb', line 23

def units_of_work
  @units_of_work
end

Class Method Details

.__xspec_contextObject

A context includes the same DSL methods as the root level module, which enables the recursive creation.



27
# File 'lib/xspec/data_structures.rb', line 27

def __xspec_context; self; end

.add_child_context(name = nil, opts = {}, &block) ⇒ Object

Child contexts and units of work are typically added by the ‘describe` and `it` DSL methods respectively.



77
78
79
# File 'lib/xspec/data_structures.rb', line 77

def add_child_context(name = nil, opts = {}, &block)
  self.children << make(name, evaluator, &block)
end

.add_memoized_method(name, &block) ⇒ Object

Values of memoized methods are remembered only for the duration of a single unit of work. These are typically created using the ‘let` DSL method.



135
136
137
138
139
# File 'lib/xspec/data_structures.rb', line 135

def add_memoized_method(name, &block)
  define_method(name) do
    memoized[block] ||= instance_eval(&block)
  end
end

.add_unit_of_work(name = nil, opts = {}, &block) ⇒ Object



81
82
83
# File 'lib/xspec/data_structures.rb', line 81

def add_unit_of_work(name = nil, opts = {}, &block)
  self.units_of_work << UnitOfWork.new(name, block)
end

.apply_evaluator!Object

The assertion context should be applied after the user has had a chance to add their own methods. It needs to be last so that users can’t clobber the assertion methods.



57
58
59
# File 'lib/xspec/data_structures.rb', line 57

def apply_evaluator!
  include(evaluator)
end

.copy_into_tree(source_context) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/xspec/data_structures.rb', line 97

def copy_into_tree(source_context)
  target_context = make(
    source_context.name,
    source_context.evaluator
  )
  source_context.nested_units_of_work.each do |x|
    target_context.units_of_work << x.unit_of_work
  end
  self.children << target_context
  target_context
end

.create_shared_context(&block) ⇒ Object

A shared context is a floating context that isn’t part of any context heirachy, so its units of work will not be visible to the root node. It can be brought into any point in the heirachy using ‘copy_into_tree` (aliased as `it_behaves_like_a` in the DSL), and this can be done multiple times, which allows definitions to be reused.

This is leaky abstraction, since only units of work are copied from shared contexts. Methods and child contexts are ignored.



93
94
95
# File 'lib/xspec/data_structures.rb', line 93

def create_shared_context(&block)
  make(nil, evaluator, &block)
end

.execute(unit_of_work) ⇒ Object

Executing a unit of work creates a new instance and hands it off to the ‘call` method, which is defined by whichever assertion context is being used. By creating a new instance everytime, no state is preserved between executions.



65
66
67
# File 'lib/xspec/data_structures.rb', line 65

def execute(unit_of_work)
  new.call(unit_of_work)
end

.initialize!(name, evaluator) ⇒ Object

A class cannot have an implicit initializer, but some variable inititialization is required so the ‘initialize!` method is called explicitly when ever a dynamic subclass is created.



47
48
49
50
51
52
# File 'lib/xspec/data_structures.rb', line 47

def initialize!(name, evaluator)
  @children          = []
  @units_of_work     = []
  @name              = name
  @evaluator = evaluator
end

.make(name, evaluator, &block) ⇒ Object

Each nested context creates a new class that inherits from the parent. Methods can be added to this class as per normal, and are correctly inherited by children. When it comes time to run tests, the scheduler will create a new instance of the context (a class) for each test, making the defined methods available and also ensuring that there is no state pollution between tests.



36
37
38
39
40
41
42
# File 'lib/xspec/data_structures.rb', line 36

def make(name, evaluator, &block)
  x = Class.new(self)
  x.initialize!(name, evaluator)
  x.class_eval(&block) if block
  x.apply_evaluator!
  x
end

.nested_units_of_work(&block) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/xspec/data_structures.rb', line 112

def nested_units_of_work(&block)
  enum = Enumerator.new do |y|
    children.each do |child|
      child.nested_units_of_work do |x|
        y.yield x.nest_under(self)
      end
    end

    units_of_work.each do |x|
      y.yield NestedUnitOfWork.new([self], x)
    end
  end

  if block
    enum.each(&block)
  else
    enum
  end
end

.root(evaluator) ⇒ Object

The root context is nothing special, and behaves the same as all the others.



71
72
73
# File 'lib/xspec/data_structures.rb', line 71

def root(evaluator)
  make(nil, evaluator)
end

.to_sObject

Dynamically generated classes are hard to identify in object graphs, so it is helpful for debugging to set an explicit name.



143
144
145
# File 'lib/xspec/data_structures.rb', line 143

def to_s
  "Context:'#{name}'"
end

Instance Method Details

#memoizedObject



148
149
150
# File 'lib/xspec/data_structures.rb', line 148

def memoized
  @memoized ||= {}
end