Module: XSpec

Defined in:
lib/xspec.rb,
lib/xspec/dsl.rb,
lib/xspec/defaults.rb,
lib/xspec/notifiers.rb,
lib/xspec/evaluators.rb,
lib/xspec/schedulers.rb,
lib/xspec/data_structures.rb

Overview

XSpec data structures are very dumb. They:

  • Only contain iteration, property, and creation logic.

  • Do not store recursive references (“everything flows downhill”).

Defined Under Namespace

Modules: DSL, Evaluator, Notifier, Scheduler Classes: Context, ExecutedUnitOfWork, Failure, NestedUnitOfWork, UnitOfWork

Constant Summary collapse

CodeException =

An exception is mostly handled the same way as a failure.

Class.new(Failure)

Class Method Summary collapse

Class Method Details

.add_defaults(options = {}) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/xspec/defaults.rb', line 25

def add_defaults(options = {})
  # A notifier makes it possible to observe the state of the system, be that
  # progress or details of failing tests.
  options[:notifier] ||= XSpec::Notifier::DEFAULT

  # A unit of work will run as an instance method on the context it is
  # defined in, but in addition an assertion context will be added as well.
  # This is a module that is included as the final step in constructing a
  # context. Allows for different matchers and expectation frameworks to be
  # used.
  options[:evaluator] ||= Evaluator::DEFAULT

  options[:short_id] ||= XSpec.method(:default_short_id)


  # An scheduler is responsible for scheduling units of work and handing them
  # off to the assertion context. Any logic regarding threads, remote
  # execution or the like belongs in a scheduler.
  options[:scheduler]         ||= Scheduler::DEFAULT
  options
end

.default_short_id(uow) ⇒ Object



13
14
15
16
17
18
19
20
21
22
# File 'lib/xspec/defaults.rb', line 13

def default_short_id(uow)
  length  = 3
  base    = 32
  digest  = Digest::SHA1.hexdigest(uow.full_name).hex
  bottom  = base ** (length-1)
  top     = base ** length
  shifted = digest % (top - bottom) + bottom

  shifted.to_s(base)
end

.dsl(config = {}) ⇒ Object

The DSL is the core of XSpec. It dynamically generates a module that can be mixed into which ever context you choose (using ‘extend`), be that the top-level namespace or a specific class.

This enables different options to be specified per DSL, which is at the heart of XSpec’s modularity. It is easy to change every component to your liking.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/xspec.rb', line 15

def dsl(config = {})
  config = XSpec.add_defaults(config)

  Module.new do
    # Each DSL provides a standard set of methods provided by the [DSL
    # module](dsl.html).
    include DSL

    # In addition, each DSL has its own independent context, which is
    # described in detail in the
    # [`data_structures.rb`](data_structures.html).
    def __xspec_context
      evaluator = __xspec_config.fetch(:evaluator)
      @__xspec_context ||= XSpec::Context.root(evaluator)
    end

    # Some meta-magic is needed to enable the config from local scope above
    # to be available inside the module.
    define_method(:__xspec_config) { config }

    # `run!` is where the magic happens. Typically called at the end of a
    # file (or by `autorun!`), this method takes all the data that was
    # accumulated by the DSL methods above and runs it through the scheduler.
    #
    # It takes an optional block that can be used to override any options
    # set in the initial `XSpec.dsl` call.
    def run!(&overrides)
      overrides ||= -> x { x }
      config = overrides.(__xspec_config)
      scheduler = config.fetch(:scheduler)

      scheduler.run(__xspec_context, config)
    end

    # It is often convenient to trigger a run after all files have been
    # processed, which is what `autorun!` sets up for you. Requiring
    # `xspec/autorun` does this automatically for you.
    def autorun!
      at_exit do
        exit 1 unless run!
      end
    end
  end
end