class XSpec::Context
Attributes
Public Class Methods
A context includes the same DSL
methods as the root level module, which enables the recursive creation.
# File lib/xspec/data_structures.rb, line 27 def __xspec_context; self; end
Child contexts and units of work are typically added by the `describe` and `it` DSL
methods respectively.
# File lib/xspec/data_structures.rb, line 77 def add_child_context(name = nil, opts = {}, &block) self.children << make(name, evaluator, &block) end
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.
# 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
# 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
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.
# File lib/xspec/data_structures.rb, line 57 def apply_evaluator! include(evaluator) end
# 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
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.
# File lib/xspec/data_structures.rb, line 65 def execute(unit_of_work) new.call(unit_of_work) end
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.
# File lib/xspec/data_structures.rb, line 47 def initialize!(name, evaluator) @children = [] @units_of_work = [] @name = name @evaluator = evaluator end
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.
# 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
# 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
The root context is nothing special, and behaves the same as all the others.
# File lib/xspec/data_structures.rb, line 71 def root(evaluator) make(nil, evaluator) end
Dynamically generated classes are hard to identify in object graphs, so it is helpful for debugging to set an explicit name.
# File lib/xspec/data_structures.rb, line 143 def to_s "Context:'#{name}'" end
Public Instance Methods
# File lib/xspec/data_structures.rb, line 148 def memoized @memoized ||= {} end