require 'spec/expectations'
require 'spec/matchers'
require 'spec/example/pending'
module Spec
module Story
=begin
A World represents the actual instance a scenario will run in.
The runner ensures any instance variables and methods defined anywhere
in a story block are available to all the scenarios. This includes
variables that are created or referenced inside Given, When and Then
blocks.
=end
module World
include ::Spec::Example::Pending
include ::Spec::Matchers
# store steps and listeners in the singleton metaclass.
# This serves both to keep them out of the way of runtime Worlds
# and to make them available to all instances.
class << self
def create(cls = Object, *args)
cls.new(*args).extend(World)
end
def listeners
@listeners ||= []
end
def add_listener(listener)
listeners() << listener
end
def step_mother
@step_mother ||= StepMother.new
end
def use(steps)
step_mother.use(steps)
end
def step_names
@step_names ||= []
end
def run_given_scenario_with_suspended_listeners(world, type, name, scenario)
current_listeners = Array.new(listeners)
begin
listeners.each { |l| l.found_scenario(type, name) }
@listeners.clear
scenario.perform(world, name) unless dry_run
ensure
@listeners.replace(current_listeners)
end
end
def store_and_call(world, type, name, *args, &block)
if block_given?
step_mother.store(type, Step.new(name, &block))
end
step = step_mother.find(type, name)
step_name = step.name
step_names << step_name
# It's important to have access to the parsed args here, so
# we can give them to the listeners. The HTML reporter needs
# the args so it can style them. See the generated output in
# story_server/prototype/rspec_stories.html (generated by rake stories)
args = step.parse_args(name) if args.empty?
begin
listeners.each { |l| l.step_upcoming(type, step_name, *args) }
step.perform(world, *args) unless dry_run
listeners.each { |l| l.step_succeeded(type, step_name, *args) }
rescue Exception => e
case e
when Spec::Example::ExamplePendingError
@listeners.each { |l| l.step_pending(type, step_name, *args) }
else
@listeners.each { |l| l.step_failed(type, step_name, *args) }
end
errors << e
end
end
def errors
@errors ||= []
end
def dry_run
::Spec::Story::Runner.dry_run
end
end # end of class << self
def start_collecting_errors
errors.clear
end
def errors
World.errors
end
def GivenScenario(name)
World.run_given_scenario_with_suspended_listeners(self, :'given scenario', name, GivenScenario.new(name))
@__previous_step = :given
end
def Given(name, *args, &block)
World.store_and_call self, :given, name, *args, &block
@__previous_step = :given
end
def When(name, *args, &block)
World.store_and_call self, :when, name, *args, &block
@__previous_step = :when
end
def Then(name, *args, &block)
World.store_and_call self, :then, name, *args, &block
@__previous_step = :then
end
def And(name, *args, &block)
World.store_and_call self, @__previous_step, name, *args, &block
end
end
end
end