require 'rubygems' 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 ::Spec::Story::Runner.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 ::Spec::Story::Runner.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 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