aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/plugins/rspec/lib
diff options
context:
space:
mode:
authorfrancis <francis>2008-01-23 01:57:59 +0000
committerfrancis <francis>2008-01-23 01:57:59 +0000
commit6d1733e8a0b5f404326cfbd78b7139c87ecbffa3 (patch)
treec86561445b9ec5179020f8f56afb7b9174b390c5 /vendor/plugins/rspec/lib
parent8bd6667c7885870af45522315f501a2b87340b1a (diff)
Add files new to new rspec
Diffstat (limited to 'vendor/plugins/rspec/lib')
-rw-r--r--vendor/plugins/rspec/lib/spec/example.rb12
-rw-r--r--vendor/plugins/rspec/lib/spec/example/configuration.rb144
-rw-r--r--vendor/plugins/rspec/lib/spec/example/errors.rb9
-rw-r--r--vendor/plugins/rspec/lib/spec/example/example_group.rb16
-rw-r--r--vendor/plugins/rspec/lib/spec/example/example_group_factory.rb62
-rw-r--r--vendor/plugins/rspec/lib/spec/example/example_group_methods.rb418
-rw-r--r--vendor/plugins/rspec/lib/spec/example/example_matcher.rb42
-rw-r--r--vendor/plugins/rspec/lib/spec/example/example_methods.rb102
-rw-r--r--vendor/plugins/rspec/lib/spec/example/module_reopening_fix.rb21
-rw-r--r--vendor/plugins/rspec/lib/spec/example/pending.rb18
-rw-r--r--vendor/plugins/rspec/lib/spec/example/shared_example_group.rb58
-rw-r--r--vendor/plugins/rspec/lib/spec/extensions/class.rb24
-rw-r--r--vendor/plugins/rspec/lib/spec/extensions/main.rb102
-rw-r--r--vendor/plugins/rspec/lib/spec/interop/test.rb10
-rw-r--r--vendor/plugins/rspec/lib/spec/interop/test/unit/autorunner.rb6
-rw-r--r--vendor/plugins/rspec/lib/spec/interop/test/unit/testcase.rb61
-rw-r--r--vendor/plugins/rspec/lib/spec/interop/test/unit/testresult.rb6
-rw-r--r--vendor/plugins/rspec/lib/spec/interop/test/unit/testsuite_adapter.rb34
-rw-r--r--vendor/plugins/rspec/lib/spec/interop/test/unit/ui/console/testrunner.rb60
-rw-r--r--vendor/plugins/rspec/lib/spec/matchers/exist.rb17
-rw-r--r--vendor/plugins/rspec/lib/spec/matchers/simple_matcher.rb29
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb16
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb59
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb31
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb47
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb125
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb128
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/text_mate_formatter.rb16
-rw-r--r--vendor/plugins/rspec/lib/spec/story.rb10
-rw-r--r--vendor/plugins/rspec/lib/spec/story/extensions.rb3
-rw-r--r--vendor/plugins/rspec/lib/spec/story/extensions/main.rb86
-rw-r--r--vendor/plugins/rspec/lib/spec/story/extensions/regexp.rb9
-rw-r--r--vendor/plugins/rspec/lib/spec/story/extensions/string.rb9
-rw-r--r--vendor/plugins/rspec/lib/spec/story/given_scenario.rb14
-rw-r--r--vendor/plugins/rspec/lib/spec/story/runner.rb58
-rw-r--r--vendor/plugins/rspec/lib/spec/story/runner/plain_text_story_runner.rb48
-rw-r--r--vendor/plugins/rspec/lib/spec/story/runner/scenario_collector.rb18
-rw-r--r--vendor/plugins/rspec/lib/spec/story/runner/scenario_runner.rb46
-rw-r--r--vendor/plugins/rspec/lib/spec/story/runner/story_mediator.rb123
-rw-r--r--vendor/plugins/rspec/lib/spec/story/runner/story_parser.rb227
-rw-r--r--vendor/plugins/rspec/lib/spec/story/runner/story_runner.rb68
-rw-r--r--vendor/plugins/rspec/lib/spec/story/scenario.rb14
-rw-r--r--vendor/plugins/rspec/lib/spec/story/step.rb56
-rw-r--r--vendor/plugins/rspec/lib/spec/story/step_group.rb89
-rw-r--r--vendor/plugins/rspec/lib/spec/story/step_mother.rb37
-rw-r--r--vendor/plugins/rspec/lib/spec/story/story.rb42
-rw-r--r--vendor/plugins/rspec/lib/spec/story/world.rb124
47 files changed, 2754 insertions, 0 deletions
diff --git a/vendor/plugins/rspec/lib/spec/example.rb b/vendor/plugins/rspec/lib/spec/example.rb
new file mode 100644
index 000000000..39ff76b99
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example.rb
@@ -0,0 +1,12 @@
+require 'timeout'
+require 'forwardable'
+require 'spec/example/pending'
+require 'spec/example/module_reopening_fix'
+require 'spec/example/example_group_methods'
+require 'spec/example/example_methods'
+require 'spec/example/example_group'
+require 'spec/example/shared_example_group'
+require 'spec/example/example_group_factory'
+require 'spec/example/errors'
+require 'spec/example/configuration'
+require 'spec/example/example_matcher'
diff --git a/vendor/plugins/rspec/lib/spec/example/configuration.rb b/vendor/plugins/rspec/lib/spec/example/configuration.rb
new file mode 100644
index 000000000..674184727
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/configuration.rb
@@ -0,0 +1,144 @@
+module Spec
+ module Example
+ class Configuration
+ # Chooses what mock framework to use. Example:
+ #
+ # Spec::Runner.configure do |config|
+ # config.mock_with :rspec, :mocha, :flexmock, or :rr
+ # end
+ #
+ # To use any other mock framework, you'll have to provide
+ # your own adapter. This is simply a module that responds to
+ # setup_mocks_for_rspec, verify_mocks_for_rspec and teardown_mocks_for_rspec.
+ # These are your hooks into the lifecycle of a given example. RSpec will
+ # call setup_mocks_for_rspec before running anything else in each Example.
+ # After executing the #after methods, RSpec will then call verify_mocks_for_rspec
+ # and teardown_mocks_for_rspec (this is guaranteed to run even if there are
+ # failures in verify_mocks_for_rspec).
+ #
+ # Once you've defined this module, you can pass that to mock_with:
+ #
+ # Spec::Runner.configure do |config|
+ # config.mock_with MyMockFrameworkAdapter
+ # end
+ #
+ def mock_with(mock_framework)
+ @mock_framework = case mock_framework
+ when Symbol
+ mock_framework_path(mock_framework.to_s)
+ else
+ mock_framework
+ end
+ end
+
+ def mock_framework # :nodoc:
+ @mock_framework ||= mock_framework_path("rspec")
+ end
+
+ # Declares modules to be included in all example groups (<tt>describe</tt> blocks).
+ #
+ # config.include(My::Bottle, My::Cup)
+ #
+ # If you want to restrict the inclusion to a subset of all the example groups then
+ # specify this in a Hash as the last argument:
+ #
+ # config.include(My::Pony, My::Horse, :type => :farm)
+ #
+ # Only example groups that have that type will get the modules included:
+ #
+ # describe "Downtown", :type => :city do
+ # # Will *not* get My::Pony and My::Horse included
+ # end
+ #
+ # describe "Old Mac Donald", :type => :farm do
+ # # *Will* get My::Pony and My::Horse included
+ # end
+ #
+ def include(*args)
+ args << {} unless Hash === args.last
+ modules, options = args_and_options(*args)
+ required_example_group = get_type_from_options(options)
+ required_example_group = required_example_group.to_sym if required_example_group
+ modules.each do |mod|
+ ExampleGroupFactory.get(required_example_group).send(:include, mod)
+ end
+ end
+
+ # Defines global predicate matchers. Example:
+ #
+ # config.predicate_matchers[:swim] = :can_swim?
+ #
+ # This makes it possible to say:
+ #
+ # person.should swim # passes if person.should_swim? returns true
+ #
+ def predicate_matchers
+ @predicate_matchers ||= {}
+ end
+
+ # Prepends a global <tt>before</tt> block to all example groups.
+ # See #append_before for filtering semantics.
+ def prepend_before(*args, &proc)
+ scope, options = scope_and_options(*args)
+ example_group = ExampleGroupFactory.get(
+ get_type_from_options(options)
+ )
+ example_group.prepend_before(scope, &proc)
+ end
+ # Appends a global <tt>before</tt> block to all example groups.
+ #
+ # If you want to restrict the block to a subset of all the example groups then
+ # specify this in a Hash as the last argument:
+ #
+ # config.prepend_before(:all, :type => :farm)
+ #
+ # or
+ #
+ # config.prepend_before(:type => :farm)
+ #
+ def append_before(*args, &proc)
+ scope, options = scope_and_options(*args)
+ example_group = ExampleGroupFactory.get(
+ get_type_from_options(options)
+ )
+ example_group.append_before(scope, &proc)
+ end
+ alias_method :before, :append_before
+
+ # Prepends a global <tt>after</tt> block to all example groups.
+ # See #append_before for filtering semantics.
+ def prepend_after(*args, &proc)
+ scope, options = scope_and_options(*args)
+ example_group = ExampleGroupFactory.get(
+ get_type_from_options(options)
+ )
+ example_group.prepend_after(scope, &proc)
+ end
+ alias_method :after, :prepend_after
+ # Appends a global <tt>after</tt> block to all example groups.
+ # See #append_before for filtering semantics.
+ def append_after(*args, &proc)
+ scope, options = scope_and_options(*args)
+ example_group = ExampleGroupFactory.get(
+ get_type_from_options(options)
+ )
+ example_group.append_after(scope, &proc)
+ end
+
+ private
+
+ def scope_and_options(*args)
+ args, options = args_and_options(*args)
+ scope = (args[0] || :each), options
+ end
+
+ def get_type_from_options(options)
+ options[:type] || options[:behaviour_type]
+ end
+
+ def mock_framework_path(framework_name)
+ File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "plugins", "mock_frameworks", framework_name))
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/example/errors.rb b/vendor/plugins/rspec/lib/spec/example/errors.rb
new file mode 100644
index 000000000..c6cb22453
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/errors.rb
@@ -0,0 +1,9 @@
+module Spec
+ module Example
+ class ExamplePendingError < StandardError
+ end
+
+ class PendingExampleFixedError < StandardError
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/example/example_group.rb b/vendor/plugins/rspec/lib/spec/example/example_group.rb
new file mode 100644
index 000000000..d6e156f93
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/example_group.rb
@@ -0,0 +1,16 @@
+module Spec
+ module Example
+ # The superclass for all regular RSpec examples.
+ class ExampleGroup
+ extend Spec::Example::ExampleGroupMethods
+ include Spec::Example::ExampleMethods
+
+ def initialize(defined_description, &implementation)
+ @_defined_description = defined_description
+ @_implementation = implementation
+ end
+ end
+ end
+end
+
+Spec::ExampleGroup = Spec::Example::ExampleGroup
diff --git a/vendor/plugins/rspec/lib/spec/example/example_group_factory.rb b/vendor/plugins/rspec/lib/spec/example/example_group_factory.rb
new file mode 100644
index 000000000..0414a3b96
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/example_group_factory.rb
@@ -0,0 +1,62 @@
+module Spec
+ module Example
+ class ExampleGroupFactory
+ class << self
+ def reset
+ @example_group_types = nil
+ default(ExampleGroup)
+ end
+
+ # Registers an example group class +klass+ with the symbol
+ # +type+. For example:
+ #
+ # Spec::Example::ExampleGroupFactory.register(:farm, Spec::Farm::Example::FarmExampleGroup)
+ #
+ # This will cause Main#describe from a file living in
+ # <tt>spec/farm</tt> to create example group instances of type
+ # Spec::Farm::Example::FarmExampleGroup.
+ def register(id, example_group_class)
+ @example_group_types[id] = example_group_class
+ end
+
+ # Sets the default ExampleGroup class
+ def default(example_group_class)
+ old = @example_group_types
+ @example_group_types = Hash.new(example_group_class)
+ @example_group_types.merge(old) if old
+ end
+
+ def get(id=nil)
+ if @example_group_types.values.include?(id)
+ id
+ else
+ @example_group_types[id]
+ end
+ end
+
+ def create_example_group(*args, &block)
+ opts = Hash === args.last ? args.last : {}
+ if opts[:shared]
+ SharedExampleGroup.new(*args, &block)
+ else
+ superclass = determine_superclass(opts)
+ superclass.describe(*args, &block)
+ end
+ end
+
+ protected
+
+ def determine_superclass(opts)
+ id = if opts[:type]
+ opts[:type]
+ elsif opts[:spec_path] =~ /spec(\\|\/)(#{@example_group_types.keys.join('|')})/
+ $2 == '' ? nil : $2.to_sym
+ end
+ get(id)
+ end
+
+ end
+ self.reset
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb b/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb
new file mode 100644
index 000000000..8f73a9853
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb
@@ -0,0 +1,418 @@
+module Spec
+ module Example
+
+ module ExampleGroupMethods
+ class << self
+ def description_text(*args)
+ args.inject("") do |result, arg|
+ result << " " unless (result == "" || arg.to_s =~ /^(\s|\.|#)/)
+ result << arg.to_s
+ end
+ end
+ end
+
+ attr_reader :description_text, :description_args, :description_options, :spec_path
+
+ def inherited(klass)
+ super
+ klass.register
+ end
+
+ # Makes the describe/it syntax available from a class. For example:
+ #
+ # class StackSpec < Spec::ExampleGroup
+ # describe Stack, "with no elements"
+ #
+ # before
+ # @stack = Stack.new
+ # end
+ #
+ # it "should raise on pop" do
+ # lambda{ @stack.pop }.should raise_error
+ # end
+ # end
+ #
+ def describe(*args, &example_group_block)
+ if example_group_block
+ self.subclass("Subclass") do
+ describe(*args)
+ module_eval(&example_group_block)
+ end
+ else
+ set_description(*args)
+ before_eval
+ self
+ end
+ end
+
+ # Use this to pull in examples from shared example groups.
+ # See Spec::Runner for information about shared example groups.
+ def it_should_behave_like(shared_example_group)
+ case shared_example_group
+ when SharedExampleGroup
+ include shared_example_group
+ else
+ example_group = SharedExampleGroup.find_shared_example_group(shared_example_group)
+ unless example_group
+ raise RuntimeError.new("Shared Example Group '#{shared_example_group}' can not be found")
+ end
+ include(example_group)
+ end
+ end
+
+ # :call-seq:
+ # predicate_matchers[matcher_name] = method_on_object
+ # predicate_matchers[matcher_name] = [method1_on_object, method2_on_object]
+ #
+ # Dynamically generates a custom matcher that will match
+ # a predicate on your class. RSpec provides a couple of these
+ # out of the box:
+ #
+ # exist (or state expectations)
+ # File.should exist("path/to/file")
+ #
+ # an_instance_of (for mock argument constraints)
+ # mock.should_receive(:message).with(an_instance_of(String))
+ #
+ # == Examples
+ #
+ # class Fish
+ # def can_swim?
+ # true
+ # end
+ # end
+ #
+ # describe Fish do
+ # predicate_matchers[:swim] = :can_swim?
+ # it "should swim" do
+ # Fish.new.should swim
+ # end
+ # end
+ def predicate_matchers
+ @predicate_matchers ||= {:an_instance_of => :is_a?}
+ end
+
+ # Creates an instance of Spec::Example::Example and adds
+ # it to a collection of examples of the current example group.
+ def it(description=nil, &implementation)
+ e = new(description, &implementation)
+ example_objects << e
+ e
+ end
+
+ alias_method :specify, :it
+
+ # Use this to temporarily disable an example.
+ def xit(description=nil, opts={}, &block)
+ Kernel.warn("Example disabled: #{description}")
+ end
+
+ def run
+ examples = examples_to_run
+ return true if examples.empty?
+ reporter.add_example_group(self)
+ return dry_run(examples) if dry_run?
+
+ plugin_mock_framework
+ define_methods_from_predicate_matchers
+
+ success, before_all_instance_variables = run_before_all
+ success, after_all_instance_variables = execute_examples(success, before_all_instance_variables, examples)
+ success = run_after_all(success, after_all_instance_variables)
+ end
+
+ def description
+ result = ExampleGroupMethods.description_text(*description_parts)
+ if result.nil? || result == ""
+ return to_s
+ else
+ result
+ end
+ end
+
+ def described_type
+ description_parts.find {|part| part.is_a?(Module)}
+ end
+
+ def description_parts #:nodoc:
+ parts = []
+ execute_in_class_hierarchy do |example_group|
+ parts << example_group.description_args
+ end
+ parts.flatten.compact
+ end
+
+ def set_description(*args)
+ args, options = args_and_options(*args)
+ @description_args = args
+ @description_options = options
+ @description_text = ExampleGroupMethods.description_text(*args)
+ @spec_path = File.expand_path(options[:spec_path]) if options[:spec_path]
+ if described_type.class == Module
+ include described_type
+ end
+ self
+ end
+
+ def examples #:nodoc:
+ examples = example_objects.dup
+ add_method_examples(examples)
+ rspec_options.reverse ? examples.reverse : examples
+ end
+
+ def number_of_examples #:nodoc:
+ examples.length
+ end
+
+ # Registers a block to be executed before each example.
+ # This method prepends +block+ to existing before blocks.
+ def prepend_before(*args, &block)
+ scope, options = scope_and_options(*args)
+ parts = before_parts_from_scope(scope)
+ parts.unshift(block)
+ end
+
+ # Registers a block to be executed before each example.
+ # This method appends +block+ to existing before blocks.
+ def append_before(*args, &block)
+ scope, options = scope_and_options(*args)
+ parts = before_parts_from_scope(scope)
+ parts << block
+ end
+ alias_method :before, :append_before
+
+ # Registers a block to be executed after each example.
+ # This method prepends +block+ to existing after blocks.
+ def prepend_after(*args, &block)
+ scope, options = scope_and_options(*args)
+ parts = after_parts_from_scope(scope)
+ parts.unshift(block)
+ end
+ alias_method :after, :prepend_after
+
+ # Registers a block to be executed after each example.
+ # This method appends +block+ to existing after blocks.
+ def append_after(*args, &block)
+ scope, options = scope_and_options(*args)
+ parts = after_parts_from_scope(scope)
+ parts << block
+ end
+
+ def remove_after(scope, &block)
+ after_each_parts.delete(block)
+ end
+
+ # Deprecated. Use before(:each)
+ def setup(&block)
+ before(:each, &block)
+ end
+
+ # Deprecated. Use after(:each)
+ def teardown(&block)
+ after(:each, &block)
+ end
+
+ def before_all_parts # :nodoc:
+ @before_all_parts ||= []
+ end
+
+ def after_all_parts # :nodoc:
+ @after_all_parts ||= []
+ end
+
+ def before_each_parts # :nodoc:
+ @before_each_parts ||= []
+ end
+
+ def after_each_parts # :nodoc:
+ @after_each_parts ||= []
+ end
+
+ # Only used from RSpec's own examples
+ def reset # :nodoc:
+ @before_all_parts = nil
+ @after_all_parts = nil
+ @before_each_parts = nil
+ @after_each_parts = nil
+ end
+
+ def register
+ rspec_options.add_example_group self
+ end
+
+ def unregister #:nodoc:
+ rspec_options.remove_example_group self
+ end
+
+ def run_before_each(example)
+ execute_in_class_hierarchy do |example_group|
+ example.eval_each_fail_fast(example_group.before_each_parts)
+ end
+ end
+
+ def run_after_each(example)
+ execute_in_class_hierarchy(:superclass_first) do |example_group|
+ example.eval_each_fail_slow(example_group.after_each_parts)
+ end
+ end
+
+ private
+ def dry_run(examples)
+ examples.each do |example|
+ rspec_options.reporter.example_started(example)
+ rspec_options.reporter.example_finished(example)
+ end
+ return true
+ end
+
+ def run_before_all
+ before_all = new("before(:all)")
+ begin
+ execute_in_class_hierarchy do |example_group|
+ before_all.eval_each_fail_fast(example_group.before_all_parts)
+ end
+ return [true, before_all.instance_variable_hash]
+ rescue Exception => e
+ reporter.failure(before_all, e)
+ return [false, before_all.instance_variable_hash]
+ end
+ end
+
+ def execute_examples(success, instance_variables, examples)
+ return [success, instance_variables] unless success
+
+ after_all_instance_variables = instance_variables
+ examples.each do |example_group_instance|
+ success &= example_group_instance.execute(rspec_options, instance_variables)
+ after_all_instance_variables = example_group_instance.instance_variable_hash
+ end
+ return [success, after_all_instance_variables]
+ end
+
+ def run_after_all(success, instance_variables)
+ after_all = new("after(:all)")
+ after_all.set_instance_variables_from_hash(instance_variables)
+ execute_in_class_hierarchy(:superclass_first) do |example_group|
+ after_all.eval_each_fail_slow(example_group.after_all_parts)
+ end
+ return success
+ rescue Exception => e
+ reporter.failure(after_all, e)
+ return false
+ end
+
+ def examples_to_run
+ all_examples = examples
+ return all_examples unless specified_examples?
+ all_examples.reject do |example|
+ matcher = ExampleMatcher.new(description.to_s, example.description)
+ !matcher.matches?(specified_examples)
+ end
+ end
+
+ def specified_examples?
+ specified_examples && !specified_examples.empty?
+ end
+
+ def specified_examples
+ rspec_options.examples
+ end
+
+ def reporter
+ rspec_options.reporter
+ end
+
+ def dry_run?
+ rspec_options.dry_run
+ end
+
+ def example_objects
+ @example_objects ||= []
+ end
+
+ def execute_in_class_hierarchy(superclass_last=false)
+ classes = []
+ current_class = self
+ while is_example_group?(current_class)
+ superclass_last ? classes << current_class : classes.unshift(current_class)
+ current_class = current_class.superclass
+ end
+ superclass_last ? classes << ExampleMethods : classes.unshift(ExampleMethods)
+
+ classes.each do |example_group|
+ yield example_group
+ end
+ end
+
+ def is_example_group?(klass)
+ Module === klass && klass.kind_of?(ExampleGroupMethods)
+ end
+
+ def plugin_mock_framework
+ case mock_framework = Spec::Runner.configuration.mock_framework
+ when Module
+ include mock_framework
+ else
+ require Spec::Runner.configuration.mock_framework
+ include Spec::Plugins::MockFramework
+ end
+ end
+
+ def define_methods_from_predicate_matchers # :nodoc:
+ all_predicate_matchers = predicate_matchers.merge(
+ Spec::Runner.configuration.predicate_matchers
+ )
+ all_predicate_matchers.each_pair do |matcher_method, method_on_object|
+ define_method matcher_method do |*args|
+ eval("be_#{method_on_object.to_s.gsub('?','')}(*args)")
+ end
+ end
+ end
+
+ def scope_and_options(*args)
+ args, options = args_and_options(*args)
+ scope = (args[0] || :each), options
+ end
+
+ def before_parts_from_scope(scope)
+ case scope
+ when :each; before_each_parts
+ when :all; before_all_parts
+ end
+ end
+
+ def after_parts_from_scope(scope)
+ case scope
+ when :each; after_each_parts
+ when :all; after_all_parts
+ end
+ end
+
+ def before_eval
+ end
+
+ def add_method_examples(examples)
+ instance_methods.sort.each do |method_name|
+ if example_method?(method_name)
+ examples << new(method_name) do
+ __send__(method_name)
+ end
+ end
+ end
+ end
+
+ def example_method?(method_name)
+ should_method?(method_name)
+ end
+
+ def should_method?(method_name)
+ !(method_name =~ /^should(_not)?$/) &&
+ method_name =~ /^should/ && (
+ instance_method(method_name).arity == 0 ||
+ instance_method(method_name).arity == -1
+ )
+ end
+ end
+
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/example/example_matcher.rb b/vendor/plugins/rspec/lib/spec/example/example_matcher.rb
new file mode 100644
index 000000000..435eabf52
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/example_matcher.rb
@@ -0,0 +1,42 @@
+module Spec
+ module Example
+ class ExampleMatcher
+ def initialize(example_group_description, example_name)
+ @example_group_description = example_group_description
+ @example_name = example_name
+ end
+
+ def matches?(specified_examples)
+ specified_examples.each do |specified_example|
+ return true if matches_literal_example?(specified_example) || matches_example_not_considering_modules?(specified_example)
+ end
+ false
+ end
+
+ protected
+ def matches_literal_example?(specified_example)
+ specified_example =~ /(^#{example_group_regex} #{example_regexp}$|^#{example_group_regex}$|^#{example_group_with_before_all_regexp}$|^#{example_regexp}$)/
+ end
+
+ def matches_example_not_considering_modules?(specified_example)
+ specified_example =~ /(^#{example_group_regex_not_considering_modules} #{example_regexp}$|^#{example_group_regex_not_considering_modules}$|^#{example_regexp}$)/
+ end
+
+ def example_group_regex
+ Regexp.escape(@example_group_description)
+ end
+
+ def example_group_with_before_all_regexp
+ Regexp.escape("#{@example_group_description} before(:all)")
+ end
+
+ def example_group_regex_not_considering_modules
+ Regexp.escape(@example_group_description.split('::').last)
+ end
+
+ def example_regexp
+ Regexp.escape(@example_name)
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/example/example_methods.rb b/vendor/plugins/rspec/lib/spec/example/example_methods.rb
new file mode 100644
index 000000000..6dd4c9c72
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/example_methods.rb
@@ -0,0 +1,102 @@
+module Spec
+ module Example
+ module ExampleMethods
+ extend ExampleGroupMethods
+ extend ModuleReopeningFix
+
+ PENDING_EXAMPLE_BLOCK = lambda {
+ raise Spec::Example::ExamplePendingError.new("Not Yet Implemented")
+ }
+
+ def execute(options, instance_variables)
+ options.reporter.example_started(self)
+ set_instance_variables_from_hash(instance_variables)
+
+ execution_error = nil
+ Timeout.timeout(options.timeout) do
+ begin
+ before_example
+ run_with_description_capturing
+ rescue Exception => e
+ execution_error ||= e
+ end
+ begin
+ after_example
+ rescue Exception => e
+ execution_error ||= e
+ end
+ end
+
+ options.reporter.example_finished(self, execution_error)
+ success = execution_error.nil? || ExamplePendingError === execution_error
+ end
+
+ def instance_variable_hash
+ instance_variables.inject({}) do |variable_hash, variable_name|
+ variable_hash[variable_name] = instance_variable_get(variable_name)
+ variable_hash
+ end
+ end
+
+ def violated(message="")
+ raise Spec::Expectations::ExpectationNotMetError.new(message)
+ end
+
+ def eval_each_fail_fast(procs) #:nodoc:
+ procs.each do |proc|
+ instance_eval(&proc)
+ end
+ end
+
+ def eval_each_fail_slow(procs) #:nodoc:
+ first_exception = nil
+ procs.each do |proc|
+ begin
+ instance_eval(&proc)
+ rescue Exception => e
+ first_exception ||= e
+ end
+ end
+ raise first_exception if first_exception
+ end
+
+ def description
+ @_defined_description || @_matcher_description || "NO NAME"
+ end
+
+ def set_instance_variables_from_hash(ivars)
+ ivars.each do |variable_name, value|
+ # Ruby 1.9 requires variable.to_s on the next line
+ unless ['@_implementation', '@_defined_description', '@_matcher_description', '@method_name'].include?(variable_name.to_s)
+ instance_variable_set variable_name, value
+ end
+ end
+ end
+
+ def run_with_description_capturing
+ begin
+ return instance_eval(&(@_implementation || PENDING_EXAMPLE_BLOCK))
+ ensure
+ @_matcher_description = Spec::Matchers.generated_description
+ Spec::Matchers.clear_generated_description
+ end
+ end
+
+ protected
+ include Matchers
+ include Pending
+
+ def before_example
+ setup_mocks_for_rspec
+ self.class.run_before_each(self)
+ end
+
+ def after_example
+ self.class.run_after_each(self)
+ verify_mocks_for_rspec
+ ensure
+ teardown_mocks_for_rspec
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/example/module_reopening_fix.rb b/vendor/plugins/rspec/lib/spec/example/module_reopening_fix.rb
new file mode 100644
index 000000000..dc01dd666
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/module_reopening_fix.rb
@@ -0,0 +1,21 @@
+module Spec
+ module Example
+ # This is a fix for ...Something in Ruby 1.8.6??... (Someone fill in here please - Aslak)
+ module ModuleReopeningFix
+ def child_modules
+ @child_modules ||= []
+ end
+
+ def included(mod)
+ child_modules << mod
+ end
+
+ def include(mod)
+ super
+ child_modules.each do |child_module|
+ child_module.__send__(:include, mod)
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/example/pending.rb b/vendor/plugins/rspec/lib/spec/example/pending.rb
new file mode 100644
index 000000000..b1f27c866
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/pending.rb
@@ -0,0 +1,18 @@
+module Spec
+ module Example
+ module Pending
+ def pending(message = "TODO")
+ if block_given?
+ begin
+ yield
+ rescue Exception => e
+ raise Spec::Example::ExamplePendingError.new(message)
+ end
+ raise Spec::Example::PendingExampleFixedError.new("Expected pending '#{message}' to fail. No Error was raised.")
+ else
+ raise Spec::Example::ExamplePendingError.new(message)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/example/shared_example_group.rb b/vendor/plugins/rspec/lib/spec/example/shared_example_group.rb
new file mode 100644
index 000000000..a6fd6211c
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/example/shared_example_group.rb
@@ -0,0 +1,58 @@
+module Spec
+ module Example
+ class SharedExampleGroup < Module
+ class << self
+ def add_shared_example_group(new_example_group)
+ guard_against_redefining_existing_example_group(new_example_group)
+ shared_example_groups << new_example_group
+ end
+
+ def find_shared_example_group(example_group_description)
+ shared_example_groups.find do |b|
+ b.description == example_group_description
+ end
+ end
+
+ def shared_example_groups
+ # TODO - this needs to be global, or at least accessible from
+ # from subclasses of Example in a centralized place. I'm not loving
+ # this as a solution, but it works for now.
+ $shared_example_groups ||= []
+ end
+
+ private
+ def guard_against_redefining_existing_example_group(new_example_group)
+ existing_example_group = find_shared_example_group(new_example_group.description)
+ return unless existing_example_group
+ return if new_example_group.equal?(existing_example_group)
+ return if spec_path(new_example_group) == spec_path(existing_example_group)
+ raise ArgumentError.new("Shared Example '#{existing_example_group.description}' already exists")
+ end
+
+ def spec_path(example_group)
+ File.expand_path(example_group.spec_path)
+ end
+ end
+ include ExampleGroupMethods
+ public :include
+
+ def initialize(*args, &example_group_block)
+ describe(*args)
+ @example_group_block = example_group_block
+ self.class.add_shared_example_group(self)
+ end
+
+ def included(mod) # :nodoc:
+ mod.module_eval(&@example_group_block)
+ end
+
+ def execute_in_class_hierarchy(superclass_last=false)
+ classes = [self]
+ superclass_last ? classes << ExampleMethods : classes.unshift(ExampleMethods)
+ classes.each do |example_group|
+ yield example_group
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/extensions/class.rb b/vendor/plugins/rspec/lib/spec/extensions/class.rb
new file mode 100644
index 000000000..30730f87e
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/extensions/class.rb
@@ -0,0 +1,24 @@
+class Class
+ # Creates a new subclass of self, with a name "under" our own name.
+ # Example:
+ #
+ # x = Foo::Bar.subclass('Zap'){}
+ # x.name # => Foo::Bar::Zap_1
+ # x.superclass.name # => Foo::Bar
+ def subclass(base_name, &body)
+ klass = Class.new(self)
+ class_name = "#{base_name}_#{class_count!}"
+ instance_eval do
+ const_set(class_name, klass)
+ end
+ klass.instance_eval(&body)
+ klass
+ end
+
+ private
+ def class_count!
+ @class_count ||= 0
+ @class_count += 1
+ @class_count
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/extensions/main.rb b/vendor/plugins/rspec/lib/spec/extensions/main.rb
new file mode 100644
index 000000000..281cbf879
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/extensions/main.rb
@@ -0,0 +1,102 @@
+module Spec
+ module Extensions
+ module Main
+ # Creates and returns a class that includes the ExampleGroupMethods
+ # module. Which ExampleGroup type is created depends on the directory of the file
+ # calling this method. For example, Spec::Rails will use different
+ # classes for specs living in <tt>spec/models</tt>,
+ # <tt>spec/helpers</tt>, <tt>spec/views</tt> and
+ # <tt>spec/controllers</tt>.
+ #
+ # It is also possible to override autodiscovery of the example group
+ # type with an options Hash as the last argument:
+ #
+ # describe "name", :type => :something_special do ...
+ #
+ # The reason for using different behaviour classes is to have different
+ # matcher methods available from within the <tt>describe</tt> block.
+ #
+ # See Spec::Example::ExampleFactory#register for details about how to
+ # register special implementations.
+ #
+ def describe(*args, &block)
+ raise ArgumentError if args.empty?
+ raise ArgumentError unless block
+ args << {} unless Hash === args.last
+ args.last[:spec_path] = caller(0)[1]
+ Spec::Example::ExampleGroupFactory.create_example_group(*args, &block)
+ end
+ alias :context :describe
+
+ # Creates an example group that can be shared by other example groups
+ #
+ # == Examples
+ #
+ # share_examples_for "All Editions" do
+ # it "all editions behaviour" ...
+ # end
+ #
+ # describe SmallEdition do
+ # it_should_behave_like "All Editions"
+ #
+ # it "should do small edition stuff" do
+ # ...
+ # end
+ # end
+ def share_examples_for(name, &block)
+ describe(name, :shared => true, &block)
+ end
+
+ alias :shared_examples_for :share_examples_for
+
+ # Creates a Shared Example Group and assigns it to a constant
+ #
+ # share_as :AllEditions do
+ # it "should do all editions stuff" ...
+ # end
+ #
+ # describe SmallEdition do
+ # it_should_behave_like AllEditions
+ #
+ # it "should do small edition stuff" do
+ # ...
+ # end
+ # end
+ #
+ # And, for those of you who prefer to use something more like Ruby, you
+ # can just include the module directly
+ #
+ # describe SmallEdition do
+ # include AllEditions
+ #
+ # it "should do small edition stuff" do
+ # ...
+ # end
+ # end
+ def share_as(name, &block)
+ begin
+ Object.const_set(name, share_examples_for(name, &block))
+ rescue NameError => e
+ raise NameError.new(e.message + "\nThe first argument to share_as must be a legal name for a constant\n")
+ end
+ end
+
+ private
+
+ def rspec_options
+ $rspec_options ||= begin; \
+ parser = ::Spec::Runner::OptionParser.new(STDERR, STDOUT); \
+ parser.order!(ARGV); \
+ $rspec_options = parser.options; \
+ end
+ $rspec_options
+ end
+
+ def init_rspec_options(options)
+ $rspec_options = options if $rspec_options.nil?
+ end
+ end
+ end
+end
+
+include Spec::Extensions::Main \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/interop/test.rb b/vendor/plugins/rspec/lib/spec/interop/test.rb
new file mode 100644
index 000000000..5c9543398
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/interop/test.rb
@@ -0,0 +1,10 @@
+require 'test/unit'
+require 'test/unit/testresult'
+
+require 'spec/interop/test/unit/testcase'
+require 'spec/interop/test/unit/testsuite_adapter'
+require 'spec/interop/test/unit/autorunner'
+require 'spec/interop/test/unit/testresult'
+require 'spec/interop/test/unit/ui/console/testrunner'
+
+Spec::Example::ExampleGroupFactory.default(Test::Unit::TestCase) \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/interop/test/unit/autorunner.rb b/vendor/plugins/rspec/lib/spec/interop/test/unit/autorunner.rb
new file mode 100644
index 000000000..3944e6995
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/interop/test/unit/autorunner.rb
@@ -0,0 +1,6 @@
+class Test::Unit::AutoRunner
+ remove_method :process_args
+ def process_args(argv)
+ true
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/interop/test/unit/testcase.rb b/vendor/plugins/rspec/lib/spec/interop/test/unit/testcase.rb
new file mode 100644
index 000000000..b32a820c1
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/interop/test/unit/testcase.rb
@@ -0,0 +1,61 @@
+require 'test/unit/testcase'
+
+module Test
+ module Unit
+ # This extension of the standard Test::Unit::TestCase makes RSpec
+ # available from within, so that you can do things like:
+ #
+ # require 'test/unit'
+ # require 'spec'
+ #
+ # class MyTest < Test::Unit::TestCase
+ # it "should work with Test::Unit assertions" do
+ # assert_equal 4, 2+1
+ # end
+ #
+ # def test_should_work_with_rspec_expectations
+ # (3+1).should == 5
+ # end
+ # end
+ #
+ # See also Spec::Example::ExampleGroup
+ class TestCase
+ extend Spec::Example::ExampleGroupMethods
+ include Spec::Example::ExampleMethods
+
+ before(:each) {setup}
+ after(:each) {teardown}
+
+ class << self
+ def suite
+ Test::Unit::TestSuiteAdapter.new(self)
+ end
+
+ def example_method?(method_name)
+ should_method?(method_name) || test_method?(method_name)
+ end
+
+ def test_method?(method_name)
+ method_name =~ /^test[_A-Z]./ && (
+ instance_method(method_name).arity == 0 ||
+ instance_method(method_name).arity == -1
+ )
+ end
+ end
+
+ def initialize(defined_description, &implementation)
+ @_defined_description = defined_description
+ @_implementation = implementation
+
+ @_result = ::Test::Unit::TestResult.new
+ # @method_name is important to set here because it "complies" with Test::Unit's interface.
+ # Some Test::Unit extensions depend on @method_name being present.
+ @method_name = @_defined_description
+ end
+
+ def run(ignore_this_argument=nil)
+ super()
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/interop/test/unit/testresult.rb b/vendor/plugins/rspec/lib/spec/interop/test/unit/testresult.rb
new file mode 100644
index 000000000..1386dc728
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/interop/test/unit/testresult.rb
@@ -0,0 +1,6 @@
+class Test::Unit::TestResult
+ alias_method :tu_passed?, :passed?
+ def passed?
+ return tu_passed? & ::Spec.run
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/interop/test/unit/testsuite_adapter.rb b/vendor/plugins/rspec/lib/spec/interop/test/unit/testsuite_adapter.rb
new file mode 100644
index 000000000..7c0ed092d
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/interop/test/unit/testsuite_adapter.rb
@@ -0,0 +1,34 @@
+module Test
+ module Unit
+ class TestSuiteAdapter < TestSuite
+ attr_reader :example_group, :examples
+ alias_method :tests, :examples
+ def initialize(example_group)
+ @example_group = example_group
+ @examples = example_group.examples
+ end
+
+ def name
+ example_group.description
+ end
+
+ def run(*args)
+ return true unless args.empty?
+ example_group.run
+ end
+
+ def size
+ example_group.number_of_examples
+ end
+
+ def delete(example)
+ examples.delete example
+ end
+
+ def empty?
+ examples.empty?
+ end
+ end
+ end
+end
+
diff --git a/vendor/plugins/rspec/lib/spec/interop/test/unit/ui/console/testrunner.rb b/vendor/plugins/rspec/lib/spec/interop/test/unit/ui/console/testrunner.rb
new file mode 100644
index 000000000..663dd4722
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/interop/test/unit/ui/console/testrunner.rb
@@ -0,0 +1,60 @@
+require 'test/unit/ui/console/testrunner'
+
+module Test
+ module Unit
+ module UI
+ module Console
+ class TestRunner
+
+ alias_method :started_without_rspec, :started
+ def started_with_rspec(result)
+ @result = result
+ @need_to_output_started = true
+ end
+ alias_method :started, :started_with_rspec
+
+ alias_method :test_started_without_rspec, :test_started
+ def test_started_with_rspec(name)
+ if @need_to_output_started
+ if @rspec_io
+ @rspec_io.rewind
+ output(@rspec_io.read)
+ end
+ output("Started")
+ @need_to_output_started = false
+ end
+ test_started_without_rspec(name)
+ end
+ alias_method :test_started, :test_started_with_rspec
+
+ alias_method :test_finished_without_rspec, :test_finished
+ def test_finished_with_rspec(name)
+ test_finished_without_rspec(name)
+ @ran_test = true
+ end
+ alias_method :test_finished, :test_finished_with_rspec
+
+ alias_method :finished_without_rspec, :finished
+ def finished_with_rspec(elapsed_time)
+ if @ran_test
+ finished_without_rspec(elapsed_time)
+ end
+ end
+ alias_method :finished, :finished_with_rspec
+
+ alias_method :setup_mediator_without_rspec, :setup_mediator
+ def setup_mediator_with_rspec
+ orig_io = @io
+ @io = StringIO.new
+ setup_mediator_without_rspec
+ ensure
+ @rspec_io = @io
+ @io = orig_io
+ end
+ alias_method :setup_mediator, :setup_mediator_with_rspec
+
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/matchers/exist.rb b/vendor/plugins/rspec/lib/spec/matchers/exist.rb
new file mode 100644
index 000000000..a5a911132
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/matchers/exist.rb
@@ -0,0 +1,17 @@
+module Spec
+ module Matchers
+ class Exist
+ def matches? actual
+ @actual = actual
+ @actual.exist?
+ end
+ def failure_message
+ "expected #{@actual.inspect} to exist, but it doesn't."
+ end
+ def negative_failure_message
+ "expected #{@actual.inspect} to not exist, but it does."
+ end
+ end
+ def exist; Exist.new; end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/matchers/simple_matcher.rb b/vendor/plugins/rspec/lib/spec/matchers/simple_matcher.rb
new file mode 100644
index 000000000..ac547d06a
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/matchers/simple_matcher.rb
@@ -0,0 +1,29 @@
+module Spec
+ module Matchers
+ class SimpleMatcher
+ attr_reader :description
+
+ def initialize(description, &match_block)
+ @description = description
+ @match_block = match_block
+ end
+
+ def matches?(actual)
+ @actual = actual
+ return @match_block.call(@actual)
+ end
+
+ def failure_message()
+ return %[expected #{@description.inspect} but got #{@actual.inspect}]
+ end
+
+ def negative_failure_message()
+ return %[expected not to get #{@description.inspect}, but got #{@actual.inspect}]
+ end
+ end
+
+ def simple_matcher(message, &match_block)
+ SimpleMatcher.new(message, &match_block)
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb b/vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb
new file mode 100644
index 000000000..65dc4519c
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/class_and_arguments_parser.rb
@@ -0,0 +1,16 @@
+module Spec
+ module Runner
+ class ClassAndArgumentsParser
+ class << self
+ def parse(s)
+ if s =~ /([a-zA-Z_]+(?:::[a-zA-Z_]+)*):?(.*)/
+ arg = $2 == "" ? nil : $2
+ [$1, arg]
+ else
+ raise "Couldn't parse #{s.inspect}"
+ end
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb b/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb
new file mode 100644
index 000000000..7275c6a88
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb
@@ -0,0 +1,59 @@
+module Spec
+ module Runner
+ class ExampleGroupRunner
+ def initialize(options)
+ @options = options
+ end
+
+ def load_files(files)
+ # It's important that loading files (or choosing not to) stays the
+ # responsibility of the ExampleGroupRunner. Some implementations (like)
+ # the one using DRb may choose *not* to load files, but instead tell
+ # someone else to do it over the wire.
+ files.each do |file|
+ load file
+ end
+ end
+
+ def run
+ prepare
+ success = true
+ example_groups.each do |example_group|
+ success = success & example_group.run
+ end
+ return success
+ ensure
+ finish
+ end
+
+ protected
+ def prepare
+ reporter.start(number_of_examples)
+ example_groups.reverse! if reverse
+ end
+
+ def finish
+ reporter.end
+ reporter.dump
+ end
+
+ def reporter
+ @options.reporter
+ end
+
+ def reverse
+ @options.reverse
+ end
+
+ def example_groups
+ @options.example_groups
+ end
+
+ def number_of_examples
+ @options.number_of_examples
+ end
+ end
+ # TODO: BT - Deprecate BehaviourRunner?
+ BehaviourRunner = ExampleGroupRunner
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb
new file mode 100644
index 000000000..5a4607983
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/failing_example_groups_formatter.rb
@@ -0,0 +1,31 @@
+require 'spec/runner/formatter/base_text_formatter'
+
+module Spec
+ module Runner
+ module Formatter
+ class FailingExampleGroupsFormatter < BaseTextFormatter
+ def add_example_group(example_group)
+ super
+ @example_group_description_parts = example_group.description_parts
+ end
+
+ def example_failed(example, counter, failure)
+ if @example_group_description_parts
+ description_parts = @example_group_description_parts.collect do |description|
+ description =~ /(.*) \(druby.*\)$/ ? $1 : description
+ end
+ @output.puts ::Spec::Example::ExampleGroupMethods.description_text(*description_parts)
+ @output.flush
+ @example_group_description_parts = nil
+ end
+ end
+
+ def dump_failure(counter, failure)
+ end
+
+ def dump_summary(duration, example_count, failure_count, pending_count)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb
new file mode 100644
index 000000000..3784f3ac7
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/profile_formatter.rb
@@ -0,0 +1,47 @@
+require 'spec/runner/formatter/progress_bar_formatter'
+
+module Spec
+ module Runner
+ module Formatter
+ class ProfileFormatter < ProgressBarFormatter
+
+ def initialize(options, where)
+ super
+ @example_times = []
+ end
+
+ def start(count)
+ @output.puts "Profiling enabled."
+ end
+
+ def example_started(example)
+ @time = Time.now
+ end
+
+ def example_passed(example)
+ super
+ @example_times << [
+ example_group.description,
+ example.description,
+ Time.now - @time
+ ]
+ end
+
+ def start_dump
+ super
+ @output.puts "\n\nTop 10 slowest examples:\n"
+
+ @example_times = @example_times.sort_by do |description, example, time|
+ time
+ end.reverse
+
+ @example_times[0..9].each do |description, example, time|
+ @output.print red(sprintf("%.7f", time))
+ @output.puts " #{description} #{example}"
+ end
+ @output.flush
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb
new file mode 100644
index 000000000..b70ac153a
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/story/html_formatter.rb
@@ -0,0 +1,125 @@
+require 'erb'
+require 'spec/runner/formatter/base_text_formatter'
+
+module Spec
+ module Runner
+ module Formatter
+ module Story
+ class HtmlFormatter < BaseTextFormatter
+ include ERB::Util
+
+ def run_started(count)
+ @output.puts <<-EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <title>Stories</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta http-equiv="Expires" content="-1" />
+ <meta http-equiv="Pragma" content="no-cache" />
+ <script src="javascripts/prototype.js" type="text/javascript"></script>
+ <script src="javascripts/scriptaculous.js" type="text/javascript"></script>
+ <script src="javascripts/rspec.js" type="text/javascript"></script>
+ <link href="stylesheets/rspec.css" rel="stylesheet" type="text/css" />
+ </head>
+ <body>
+ <div id="container">
+EOF
+ end
+
+ def collected_steps(steps)
+ unless steps.empty?
+ @output.puts " <ul id=\"stock_steps\" style=\"display: none;\">"
+ steps.each do |step|
+ @output.puts " <li>#{step}</li>"
+ end
+ @output.puts " </ul>"
+ end
+ end
+
+ def run_ended
+ @output.puts <<-EOF
+ </div>
+ </body>
+</head>
+EOF
+ end
+
+ def story_started(title, narrative)
+ @output.puts <<-EOF
+ <dl class="story passed">
+ <dt>Story: #{h title}</dt>
+ <dd>
+ <p>
+ #{h(narrative).split("\n").join("<br />")}
+ </p>
+EOF
+ end
+
+ def story_ended(title, narrative)
+ @output.puts <<-EOF
+ </dd>
+ </dl>
+EOF
+ end
+
+ def scenario_started(story_title, scenario_name)
+ @output.puts <<-EOF
+ <dl class="passed">
+ <dt>Scenario: #{h scenario_name}</dt>
+ <dd>
+ <ul class="steps">
+EOF
+ end
+
+ def scenario_ended
+ @output.puts <<-EOF
+ </ul>
+ </dd>
+ </dl>
+EOF
+ end
+
+ def found_scenario(type, description)
+ end
+
+ def scenario_succeeded(story_title, scenario_name)
+ scenario_ended
+ end
+
+ def scenario_pending(story_title, scenario_name, reason)
+ scenario_ended
+ end
+
+ def scenario_failed(story_title, scenario_name, err)
+ scenario_ended
+ end
+
+ def step_succeeded(type, description, *args)
+ print_step('passed', type, description, *args) # TODO: uses succeeded CSS class
+ end
+
+ def step_pending(type, description, *args)
+ print_step('pending', type, description, *args)
+ end
+
+ def step_failed(type, description, *args)
+ print_step('failed', type, description, *args)
+ end
+
+ def print_step(klass, type, description, *args)
+ spans = args.map { |arg| "<span class=\"param\">#{arg}</span>" }
+ desc_string = description.step_name
+ arg_regexp = description.arg_regexp
+ i = -1
+ inner = type.to_s.capitalize + ' ' + desc_string.gsub(arg_regexp) { |param| spans[i+=1] }
+ @output.puts " <li class=\"#{klass}\">#{inner}</li>"
+ end
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb
new file mode 100644
index 000000000..424e27cc6
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/story/plain_text_formatter.rb
@@ -0,0 +1,128 @@
+require 'spec/runner/formatter/base_text_formatter'
+
+module Spec
+ module Runner
+ module Formatter
+ module Story
+ class PlainTextFormatter < BaseTextFormatter
+ def initialize(options, where)
+ super
+ @successful_scenario_count = 0
+ @pending_scenario_count = 0
+ @failed_scenarios = []
+ @pending_steps = []
+ @previous_type = nil
+ end
+
+ def run_started(count)
+ @count = count
+ @output.puts "Running #@count scenarios\n\n"
+ end
+
+ def story_started(title, narrative)
+ @current_story_title = title
+ @output.puts "Story: #{title}\n\n"
+ narrative.each_line do |line|
+ @output.print " "
+ @output.print line
+ end
+ end
+
+ def story_ended(title, narrative)
+ @output.puts
+ @output.puts
+ end
+
+ def scenario_started(story_title, scenario_name)
+ @current_scenario_name = scenario_name
+ @scenario_already_failed = false
+ @output.print "\n\n Scenario: #{scenario_name}"
+ @scenario_ok = true
+ end
+
+ def scenario_succeeded(story_title, scenario_name)
+ @successful_scenario_count += 1
+ end
+
+ def scenario_failed(story_title, scenario_name, err)
+ @options.backtrace_tweaker.tweak_backtrace(err)
+ @failed_scenarios << [story_title, scenario_name, err] unless @scenario_already_failed
+ @scenario_already_failed = true
+ end
+
+ def scenario_pending(story_title, scenario_name, msg)
+ @pending_scenario_count += 1 unless @scenario_already_failed
+ @scenario_already_failed = true
+ end
+
+ def run_ended
+ @output.puts "#@count scenarios: #@successful_scenario_count succeeded, #{@failed_scenarios.size} failed, #@pending_scenario_count pending"
+ unless @pending_steps.empty?
+ @output.puts "\nPending Steps:"
+ @pending_steps.each_with_index do |pending, i|
+ story_name, scenario_name, msg = pending
+ @output.puts "#{i+1}) #{story_name} (#{scenario_name}): #{msg}"
+ end
+ end
+ unless @failed_scenarios.empty?
+ @output.print "\nFAILURES:"
+ @failed_scenarios.each_with_index do |failure, i|
+ title, scenario_name, err = failure
+ @output.print %[
+ #{i+1}) #{title} (#{scenario_name}) FAILED
+ #{err.class}: #{err.message}
+ #{err.backtrace.join("\n")}
+]
+ end
+ end
+ end
+
+ def step_succeeded(type, description, *args)
+ found_step(type, description, false, *args)
+ end
+
+ def step_pending(type, description, *args)
+ found_step(type, description, false, *args)
+ @pending_steps << [@current_story_title, @current_scenario_name, description]
+ @output.print " (PENDING)"
+ @scenario_ok = false
+ end
+
+ def step_failed(type, description, *args)
+ found_step(type, description, true, *args)
+ @output.print red(@scenario_ok ? " (FAILED)" : " (SKIPPED)")
+ @scenario_ok = false
+ end
+
+ def collected_steps(steps)
+ end
+
+ def method_missing(sym, *args, &block) #:nodoc:
+ # noop - ignore unknown messages
+ end
+
+ private
+
+ def found_step(type, description, failed, *args)
+ desc_string = description.step_name
+ arg_regexp = description.arg_regexp
+ text = if(type == @previous_type)
+ "\n And "
+ else
+ "\n\n #{type.to_s.capitalize} "
+ end
+ i = -1
+ text << desc_string.gsub(arg_regexp) { |param| args[i+=1] }
+ @output.print(failed ? red(text) : green(text))
+
+ if type == :'given scenario'
+ @previous_type = :given
+ else
+ @previous_type = type
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/text_mate_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/text_mate_formatter.rb
new file mode 100644
index 000000000..4c0a9c7de
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/text_mate_formatter.rb
@@ -0,0 +1,16 @@
+require 'spec/runner/formatter/html_formatter'
+
+module Spec
+ module Runner
+ module Formatter
+ # Formats backtraces so they're clickable by TextMate
+ class TextMateFormatter < HtmlFormatter
+ def backtrace_line(line)
+ line.gsub(/([^:]*\.rb):(\d*)/) do
+ "<a href=\"txmt://open?url=file://#{File.expand_path($1)}&line=#{$2}\">#{$1}:#{$2}</a> "
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story.rb b/vendor/plugins/rspec/lib/spec/story.rb
new file mode 100644
index 000000000..bc6960a28
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story.rb
@@ -0,0 +1,10 @@
+require 'spec'
+require 'spec/story/extensions'
+require 'spec/story/given_scenario'
+require 'spec/story/runner'
+require 'spec/story/scenario'
+require 'spec/story/step'
+require 'spec/story/step_group'
+require 'spec/story/step_mother'
+require 'spec/story/story'
+require 'spec/story/world'
diff --git a/vendor/plugins/rspec/lib/spec/story/extensions.rb b/vendor/plugins/rspec/lib/spec/story/extensions.rb
new file mode 100644
index 000000000..dc7dd1140
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/extensions.rb
@@ -0,0 +1,3 @@
+require 'spec/story/extensions/main'
+require 'spec/story/extensions/string'
+require 'spec/story/extensions/regexp'
diff --git a/vendor/plugins/rspec/lib/spec/story/extensions/main.rb b/vendor/plugins/rspec/lib/spec/story/extensions/main.rb
new file mode 100644
index 000000000..6336b630c
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/extensions/main.rb
@@ -0,0 +1,86 @@
+module Spec
+ module Story
+ module Extensions
+ module Main
+ def Story(title, narrative, params = {}, &body)
+ ::Spec::Story::Runner.story_runner.Story(title, narrative, params, &body)
+ end
+
+ # Calling this deprecated is silly, since it hasn't been released yet. But, for
+ # those who are reading this - this will be deleted before the 1.1 release.
+ def run_story(*args, &block)
+ runner = Spec::Story::Runner::PlainTextStoryRunner.new(*args)
+ runner.instance_eval(&block) if block
+ runner.run
+ end
+
+ # Creates (or appends to an existing) a namespaced group of steps for use in Stories
+ #
+ # == Examples
+ #
+ # # Creating a new group
+ # steps_for :forms do
+ # When("user enters $value in the $field field") do ... end
+ # When("user submits the $form form") do ... end
+ # end
+ def steps_for(tag, &block)
+ steps = rspec_story_steps[tag]
+ steps.instance_eval(&block) if block
+ steps
+ end
+
+ # Creates a context for running a Plain Text Story with specific groups of Steps.
+ # Also supports adding arbitrary steps that will only be accessible to
+ # the Story being run.
+ #
+ # == Examples
+ #
+ # # Run a Story with one group of steps
+ # with_steps_for :checking_accounts do
+ # run File.dirname(__FILE__) + "/withdraw_cash"
+ # end
+ #
+ # # Run a Story, adding steps that are only available for this Story
+ # with_steps_for :accounts do
+ # Given "user is logged in as account administrator"
+ # run File.dirname(__FILE__) + "/reconcile_accounts"
+ # end
+ #
+ # # Run a Story with steps from two groups
+ # with_steps_for :checking_accounts, :savings_accounts do
+ # run File.dirname(__FILE__) + "/transfer_money"
+ # end
+ #
+ # # Run a Story with a specific Story extension
+ # with_steps_for :login, :navigation do
+ # run File.dirname(__FILE__) + "/user_changes_password", :type => RailsStory
+ # end
+ def with_steps_for(*tags, &block)
+ steps = Spec::Story::StepGroup.new do
+ extend StoryRunnerStepGroupAdapter
+ end
+ tags.each {|tag| steps << rspec_story_steps[tag]}
+ steps.instance_eval(&block) if block
+ steps
+ end
+
+ private
+
+ module StoryRunnerStepGroupAdapter
+ def run(path, options={})
+ runner = Spec::Story::Runner::PlainTextStoryRunner.new(path, options)
+ runner.steps << self
+ runner.run
+ end
+ end
+
+ def rspec_story_steps # :nodoc:
+ $rspec_story_steps ||= Spec::Story::StepGroupHash.new
+ end
+
+ end
+ end
+ end
+end
+
+include Spec::Story::Extensions::Main \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/story/extensions/regexp.rb b/vendor/plugins/rspec/lib/spec/story/extensions/regexp.rb
new file mode 100644
index 000000000..7955b4c33
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/extensions/regexp.rb
@@ -0,0 +1,9 @@
+class Regexp
+ def step_name
+ self.source
+ end
+
+ def arg_regexp
+ ::Spec::Story::Step::PARAM_OR_GROUP_PATTERN
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/story/extensions/string.rb b/vendor/plugins/rspec/lib/spec/story/extensions/string.rb
new file mode 100644
index 000000000..896578def
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/extensions/string.rb
@@ -0,0 +1,9 @@
+class String
+ def step_name
+ self
+ end
+
+ def arg_regexp
+ ::Spec::Story::Step::PARAM_PATTERN
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/story/given_scenario.rb b/vendor/plugins/rspec/lib/spec/story/given_scenario.rb
new file mode 100644
index 000000000..88c51f981
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/given_scenario.rb
@@ -0,0 +1,14 @@
+module Spec
+ module Story
+ class GivenScenario
+ def initialize(name)
+ @name = name
+ end
+
+ def perform(instance, ignore_name)
+ scenario = Runner::StoryRunner.scenario_from_current_story(@name)
+ Runner::ScenarioRunner.new.run(scenario, instance)
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/runner.rb b/vendor/plugins/rspec/lib/spec/story/runner.rb
new file mode 100644
index 000000000..2dd36fbc6
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/runner.rb
@@ -0,0 +1,58 @@
+require 'spec/story/runner/scenario_collector.rb'
+require 'spec/story/runner/scenario_runner.rb'
+require 'spec/story/runner/story_runner.rb'
+require 'spec/story/runner/story_parser.rb'
+require 'spec/story/runner/story_mediator.rb'
+require 'spec/story/runner/plain_text_story_runner.rb'
+
+module Spec
+ module Story
+ module Runner
+ class << self
+ def run_options # :nodoc:
+ @run_options ||= ::Spec::Runner::OptionParser.parse(ARGV, $stderr, $stdout)
+ end
+
+ def story_runner # :nodoc:
+ unless @story_runner
+ @story_runner = StoryRunner.new(scenario_runner, world_creator)
+ run_options.story_formatters.each do |formatter|
+ register_listener(formatter)
+ end
+ Runner.register_exit_hook
+ end
+ @story_runner
+ end
+
+ def scenario_runner # :nodoc:
+ @scenario_runner ||= ScenarioRunner.new
+ end
+
+ def world_creator # :nodoc:
+ @world_creator ||= World
+ end
+
+ # Use this to register a customer output formatter.
+ def register_listener(listener)
+ story_runner.add_listener(listener) # run_started, story_started, story_ended, #run_ended
+ world_creator.add_listener(listener) # found_scenario, step_succeeded, step_failed, step_failed
+ scenario_runner.add_listener(listener) # scenario_started, scenario_succeeded, scenario_pending, scenario_failed
+ end
+
+ def register_exit_hook # :nodoc:
+ # TODO - when story runner uses test/unit runners like example runner does we can kill
+ # this and also the assorted Kernel.stub!(:at_exit) in examples
+ at_exit do
+ Runner.story_runner.run_stories unless $!
+ end
+ # TODO exit with non-zero status if run fails
+ end
+
+ def dry_run
+ run_options.dry_run
+ end
+
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/runner/plain_text_story_runner.rb b/vendor/plugins/rspec/lib/spec/story/runner/plain_text_story_runner.rb
new file mode 100644
index 000000000..8d34ea2d2
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/runner/plain_text_story_runner.rb
@@ -0,0 +1,48 @@
+module Spec
+ module Story
+ module Runner
+ class PlainTextStoryRunner
+ # You can initialize a PlainTextStoryRunner with the path to the
+ # story file or a block, in which you can define the path using load.
+ #
+ # == Examples
+ #
+ # PlainTextStoryRunner.new('path/to/file')
+ #
+ # PlainTextStoryRunner.new do |runner|
+ # runner.load 'path/to/file'
+ # end
+ def initialize(*args)
+ @options = Hash === args.last ? args.pop : {}
+ @story_file = args.empty? ? nil : args.shift
+ yield self if block_given?
+ end
+
+ def []=(key, value)
+ @options[key] = value
+ end
+
+ def load(path)
+ @story_file = path
+ end
+
+ def run
+ raise "You must set a path to the file with the story. See the RDoc." if @story_file.nil?
+ mediator = Spec::Story::Runner::StoryMediator.new(steps, Spec::Story::Runner.story_runner, @options)
+ parser = Spec::Story::Runner::StoryParser.new(mediator)
+
+ story_text = File.read(@story_file)
+ parser.parse(story_text.split("\n"))
+
+ mediator.run_stories
+ end
+
+ def steps
+ @step_group ||= Spec::Story::StepGroup.new
+ yield @step_group if block_given?
+ @step_group
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/runner/scenario_collector.rb b/vendor/plugins/rspec/lib/spec/story/runner/scenario_collector.rb
new file mode 100644
index 000000000..78339fd22
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/runner/scenario_collector.rb
@@ -0,0 +1,18 @@
+module Spec
+ module Story
+ module Runner
+ class ScenarioCollector
+ attr_accessor :scenarios
+
+ def initialize(story)
+ @story = story
+ @scenarios = []
+ end
+
+ def Scenario(name, &body)
+ @scenarios << Scenario.new(@story, name, &body)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/runner/scenario_runner.rb b/vendor/plugins/rspec/lib/spec/story/runner/scenario_runner.rb
new file mode 100644
index 000000000..aee52e412
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/runner/scenario_runner.rb
@@ -0,0 +1,46 @@
+module Spec
+ module Story
+ module Runner
+ class ScenarioRunner
+ def initialize
+ @listeners = []
+ end
+
+ def run(scenario, world)
+ @listeners.each { |l| l.scenario_started(scenario.story.title, scenario.name) }
+ run_story_ignoring_scenarios(scenario.story, world)
+
+ world.start_collecting_errors
+ world.instance_eval(&scenario.body)
+ if world.errors.empty?
+ @listeners.each { |l| l.scenario_succeeded(scenario.story.title, scenario.name) }
+ else
+ if Spec::Example::ExamplePendingError === (e = world.errors.first)
+ @listeners.each { |l| l.scenario_pending(scenario.story.title, scenario.name, e.message) }
+ else
+ @listeners.each { |l| l.scenario_failed(scenario.story.title, scenario.name, e) }
+ end
+ end
+ end
+
+ def add_listener(listener)
+ @listeners << listener
+ end
+
+ private
+
+ def run_story_ignoring_scenarios(story, world)
+ class << world
+ def Scenario(name, &block)
+ # do nothing
+ end
+ end
+ story.run_in(world)
+ class << world
+ remove_method(:Scenario)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/runner/story_mediator.rb b/vendor/plugins/rspec/lib/spec/story/runner/story_mediator.rb
new file mode 100644
index 000000000..1f4744b9f
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/runner/story_mediator.rb
@@ -0,0 +1,123 @@
+ module Spec
+ module Story
+ module Runner
+
+ class StoryMediator
+ def initialize(step_group, runner, options={})
+ @step_group = step_group
+ @stories = []
+ @runner = runner
+ @options = options
+ end
+
+ def stories
+ @stories.collect { |p| p.to_proc }
+ end
+
+ def create_story(title, narrative)
+ @stories << Story.new(title, narrative, @step_group, @options)
+ end
+
+ def create_scenario(title)
+ current_story.add_scenario Scenario.new(title)
+ end
+
+ def create_given(name)
+ current_scenario.add_step Step.new('Given', name)
+ end
+
+ def create_given_scenario(name)
+ current_scenario.add_step Step.new('GivenScenario', name)
+ end
+
+ def create_when(name)
+ current_scenario.add_step Step.new('When', name)
+ end
+
+ def create_then(name)
+ current_scenario.add_step Step.new('Then', name)
+ end
+
+ def run_stories
+ stories.each { |story| @runner.instance_eval(&story) }
+ end
+
+ private
+ def current_story
+ @stories.last
+ end
+
+ def current_scenario
+ current_story.current_scenario
+ end
+
+ class Story
+ def initialize(title, narrative, step_group, options)
+ @title = title
+ @narrative = narrative
+ @scenarios = []
+ @step_group = step_group
+ @options = options
+ end
+
+ def to_proc
+ title = @title
+ narrative = @narrative
+ scenarios = @scenarios.collect { |scenario| scenario.to_proc }
+ options = @options.merge(:steps => @step_group)
+ lambda do
+ Story title, narrative, options do
+ scenarios.each { |scenario| instance_eval(&scenario) }
+ end
+ end
+ end
+
+ def add_scenario(scenario)
+ @scenarios << scenario
+ end
+
+ def current_scenario
+ @scenarios.last
+ end
+ end
+
+ class Scenario
+ def initialize(name)
+ @name = name
+ @steps = []
+ end
+
+ def to_proc
+ name = @name
+ steps = @steps.collect { |step| step.to_proc }
+ lambda do
+ Scenario name do
+ steps.each { |step| instance_eval(&step) }
+ end
+ end
+ end
+
+ def add_step(step)
+ @steps << step
+ end
+ end
+
+ class Step
+ def initialize(type, name)
+ @type = type
+ @name = name
+ end
+
+ def to_proc
+ type = @type
+ name = @name
+ lambda do
+ send(type, name)
+ end
+ end
+ end
+ end
+
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/runner/story_parser.rb b/vendor/plugins/rspec/lib/spec/story/runner/story_parser.rb
new file mode 100644
index 000000000..d454df8cb
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/runner/story_parser.rb
@@ -0,0 +1,227 @@
+module Spec
+ module Story
+ module Runner
+
+ class IllegalStepError < StandardError
+ def initialize(state, event)
+ super("Illegal attempt to create a #{event} after a #{state}")
+ end
+ end
+
+ class StoryParser
+ def initialize(story_mediator)
+ @story_mediator = story_mediator
+ @current_story_lines = []
+ transition_to(:starting_state)
+ end
+
+ def parse(lines)
+ lines.reject! {|line| line == ""}
+ until lines.empty?
+ process_line(lines.shift)
+ end
+ @state.eof
+ end
+
+ def process_line(line)
+ line.strip!
+ case line
+ when /^Story: / then @state.story(line)
+ when /^Scenario: / then @state.scenario(line)
+ when /^Given:? / then @state.given(line)
+ when /^GivenScenario:? / then @state.given_scenario(line)
+ when /^When:? / then @state.event(line)
+ when /^Then:? / then @state.outcome(line)
+ when /^And:? / then @state.one_more_of_the_same(line)
+ else @state.other(line)
+ end
+ end
+
+ def init_story(title)
+ @current_story_lines.clear
+ add_story_line(title)
+ end
+
+ def add_story_line(line)
+ @current_story_lines << line
+ end
+
+ def create_story()
+ unless @current_story_lines.empty?
+ @story_mediator.create_story(@current_story_lines[0].gsub("Story: ",""), @current_story_lines[1..-1].join("\n"))
+ @current_story_lines.clear
+ end
+ end
+
+ def create_scenario(title)
+ @story_mediator.create_scenario(title.gsub("Scenario: ",""))
+ end
+
+ def create_given(name)
+ @story_mediator.create_given(name)
+ end
+
+ def create_given_scenario(name)
+ @story_mediator.create_given_scenario(name)
+ end
+
+ def create_when(name)
+ @story_mediator.create_when(name)
+ end
+
+ def create_then(name)
+ @story_mediator.create_then(name)
+ end
+
+ def transition_to(key)
+ @state = states[key]
+ end
+
+ def states
+ @states ||= {
+ :starting_state => StartingState.new(self),
+ :story_state => StoryState.new(self),
+ :scenario_state => ScenarioState.new(self),
+ :given_state => GivenState.new(self),
+ :when_state => WhenState.new(self),
+ :then_state => ThenState.new(self)
+ }
+ end
+
+ class State
+ def initialize(parser)
+ @parser = parser
+ end
+
+ def story(line)
+ @parser.init_story(line)
+ @parser.transition_to(:story_state)
+ end
+
+ def scenario(line)
+ @parser.create_scenario(line)
+ @parser.transition_to(:scenario_state)
+ end
+
+ def given(line)
+ @parser.create_given(remove_tag_from(:given, line))
+ @parser.transition_to(:given_state)
+ end
+
+ def given_scenario(line)
+ @parser.create_given_scenario(remove_tag_from(:givenscenario, line))
+ @parser.transition_to(:given_state)
+ end
+
+ def event(line)
+ @parser.create_when(remove_tag_from(:when, line))
+ @parser.transition_to(:when_state)
+ end
+
+ def outcome(line)
+ @parser.create_then(remove_tag_from(:then, line))
+ @parser.transition_to(:then_state)
+ end
+
+ def remove_tag_from(tag, line)
+ tokens = line.split
+ # validation of tag can go here
+ tokens[0].downcase.match(/#{tag.to_s}:?/) ?
+ (tokens[1..-1].join(' ')) : line
+ end
+
+ def eof
+ end
+
+ def other(line)
+ # no-op - supports header text before the first story in a file
+ end
+ end
+
+ class StartingState < State
+ def initialize(parser)
+ @parser = parser
+ end
+ end
+
+ class StoryState < State
+ def one_more_of_the_same(line)
+ other(line)
+ end
+
+ def story(line)
+ @parser.create_story
+ @parser.add_story_line(line)
+ end
+
+ def scenario(line)
+ @parser.create_story
+ @parser.create_scenario(line)
+ @parser.transition_to(:scenario_state)
+ end
+
+ def given(line)
+ other(line)
+ end
+
+ def event(line)
+ other(line)
+ end
+
+ def outcome(line)
+ other(line)
+ end
+
+ def other(line)
+ @parser.add_story_line(line)
+ end
+
+ def eof
+ @parser.create_story
+ end
+ end
+
+ class ScenarioState < State
+ def one_more_of_the_same(line)
+ raise IllegalStepError.new("Scenario", "And")
+ end
+
+ def scenario(line)
+ @parser.create_scenario(line)
+ end
+ end
+
+ class GivenState < State
+ def one_more_of_the_same(line)
+ @parser.create_given(remove_tag_from(:and, line))
+ end
+
+ def given(line)
+ @parser.create_given(remove_tag_from(:given, line))
+ end
+ end
+
+ class WhenState < State
+ def one_more_of_the_same(line)
+ @parser.create_when(remove_tag_from(:and ,line))
+ end
+
+ def event(line)
+ @parser.create_when(remove_tag_from(:when ,line))
+ end
+ end
+
+ class ThenState < State
+ def one_more_of_the_same(line)
+ @parser.create_then(remove_tag_from(:and ,line))
+ end
+
+ def outcome(line)
+ @parser.create_then(remove_tag_from(:then ,line))
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/runner/story_runner.rb b/vendor/plugins/rspec/lib/spec/story/runner/story_runner.rb
new file mode 100644
index 000000000..f9eeb9ac1
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/runner/story_runner.rb
@@ -0,0 +1,68 @@
+module Spec
+ module Story
+ module Runner
+ class StoryRunner
+ class << self
+ attr_accessor :current_story_runner
+
+ def scenario_from_current_story(scenario_name)
+ current_story_runner.scenario_from_current_story(scenario_name)
+ end
+ end
+
+ attr_accessor :stories, :scenarios, :current_story
+
+ def initialize(scenario_runner, world_creator = World)
+ StoryRunner.current_story_runner = self
+ @scenario_runner = scenario_runner
+ @world_creator = world_creator
+ @stories = []
+ @scenarios_by_story = {}
+ @scenarios = []
+ @listeners = []
+ end
+
+ def Story(title, narrative, params = {}, &body)
+ story = Story.new(title, narrative, params, &body)
+ @stories << story
+
+ # collect scenarios
+ collector = ScenarioCollector.new(story)
+ story.run_in(collector)
+ @scenarios += collector.scenarios
+ @scenarios_by_story[story.title] = collector.scenarios
+ end
+
+ def run_stories
+ return if @stories.empty?
+ @listeners.each { |l| l.run_started(scenarios.size) }
+ @stories.each do |story|
+ story.assign_steps_to(World)
+ @current_story = story
+ @listeners.each { |l| l.story_started(story.title, story.narrative) }
+ scenarios = @scenarios_by_story[story.title]
+ scenarios.each do |scenario|
+ type = story[:type] || Object
+ args = story[:args] || []
+ world = @world_creator.create(type, *args)
+ @scenario_runner.run(scenario, world)
+ end
+ @listeners.each { |l| l.story_ended(story.title, story.narrative) }
+ World.step_mother.clear
+ end
+ unique_steps = (World.step_names.collect {|n| Regexp === n ? n.source : n.to_s}).uniq.sort
+ @listeners.each { |l| l.collected_steps(unique_steps) }
+ @listeners.each { |l| l.run_ended }
+ end
+
+ def add_listener(listener)
+ @listeners << listener
+ end
+
+ def scenario_from_current_story(scenario_name)
+ @scenarios_by_story[@current_story.title].find {|s| s.name == scenario_name }
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/scenario.rb b/vendor/plugins/rspec/lib/spec/story/scenario.rb
new file mode 100644
index 000000000..d83b3eeb8
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/scenario.rb
@@ -0,0 +1,14 @@
+
+module Spec
+ module Story
+ class Scenario
+ attr_accessor :name, :body, :story
+
+ def initialize(story, name, &body)
+ @story = story
+ @name = name
+ @body = body
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/step.rb b/vendor/plugins/rspec/lib/spec/story/step.rb
new file mode 100644
index 000000000..1d596e92c
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/step.rb
@@ -0,0 +1,56 @@
+module Spec
+ module Story
+ class Step
+ PARAM_PATTERN = /(\$\w*)/
+ PARAM_OR_GROUP_PATTERN = /(\$\w*)|\(.*?\)/
+
+ attr_reader :name
+ def initialize(name, &block)
+ @name = name
+ assign_expression(name)
+ init_module(name, &block)
+ end
+
+ def perform(instance, *args)
+ instance.extend(@mod)
+ instance.__send__(sanitize(@name), *args)
+ end
+
+ def init_module(name, &block)
+ sanitized_name = sanitize(name)
+ @mod = Module.new do
+ define_method(sanitized_name, &block)
+ end
+ end
+
+ def sanitize(a_string_or_regexp)
+ return a_string_or_regexp.source if Regexp == a_string_or_regexp
+ a_string_or_regexp.to_s
+ end
+
+
+ def matches?(name)
+ !(matches = name.match(@expression)).nil?
+ end
+
+ def parse_args(name)
+ name.match(@expression)[1..-1]
+ end
+
+ private
+
+ def assign_expression(name)
+ expression = name.dup
+ if String === expression
+ expression.gsub! '(', '\('
+ expression.gsub! ')', '\)'
+ while expression =~ PARAM_PATTERN
+ expression.gsub!($1, "(.*?)")
+ end
+ end
+ @expression = Regexp.new("^#{expression}$")
+ end
+
+ end
+ end
+end \ No newline at end of file
diff --git a/vendor/plugins/rspec/lib/spec/story/step_group.rb b/vendor/plugins/rspec/lib/spec/story/step_group.rb
new file mode 100644
index 000000000..cae558c40
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/step_group.rb
@@ -0,0 +1,89 @@
+module Spec
+ module Story
+
+ class StepGroupHash < Hash
+ def initialize
+ super do |h,k|
+ h[k] = Spec::Story::StepGroup.new
+ end
+ end
+ end
+
+ class StepGroup
+ def self.steps(&block)
+ @step_group ||= StepGroup.new(false)
+ @step_group.instance_eval(&block) if block
+ @step_group
+ end
+
+ def initialize(init_defaults=true, &block)
+ @hash_of_lists_of_steps = Hash.new {|h, k| h[k] = []}
+ if init_defaults
+ self.class.steps.add_to(self)
+ end
+ instance_eval(&block) if block
+ end
+
+ def find(type, name)
+ @hash_of_lists_of_steps[type].each do |step|
+ return step if step.matches?(name)
+ end
+ return nil
+ end
+
+ def GivenScenario(name, &block)
+ create_matcher(:given_scenario, name, &block)
+ end
+
+ def Given(name, &block)
+ create_matcher(:given, name, &block)
+ end
+
+ def When(name, &block)
+ create_matcher(:when, name, &block)
+ end
+
+ def Then(name, &block)
+ create_matcher(:then, name, &block)
+ end
+
+ alias :given_scenario :GivenScenario
+ alias :given :Given
+ alias :when :When
+ alias :then :Then
+
+ def add(type, steps)
+ (@hash_of_lists_of_steps[type] << steps).flatten!
+ end
+
+ def clear
+ @hash_of_lists_of_steps.clear
+ end
+
+ def empty?
+ [:given_scenario, :given, :when, :then].each do |type|
+ return false unless @hash_of_lists_of_steps[type].empty?
+ end
+ return true
+ end
+
+ def add_to(other_step_matchers)
+ [:given_scenario, :given, :when, :then].each do |type|
+ other_step_matchers.add(type, @hash_of_lists_of_steps[type])
+ end
+ end
+
+ def <<(other_step_matchers)
+ other_step_matchers.add_to(self) if other_step_matchers.respond_to?(:add_to)
+ end
+
+ # TODO - make me private
+ def create_matcher(type, name, &block)
+ matcher = Step.new(name, &block)
+ @hash_of_lists_of_steps[type] << matcher
+ matcher
+ end
+
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/step_mother.rb b/vendor/plugins/rspec/lib/spec/story/step_mother.rb
new file mode 100644
index 000000000..a2e84e310
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/step_mother.rb
@@ -0,0 +1,37 @@
+module Spec
+ module Story
+ class StepMother
+ def initialize
+ @steps = StepGroup.new
+ end
+
+ def use(new_step_group)
+ @steps << new_step_group
+ end
+
+ def store(type, step)
+ @steps.add(type, step)
+ end
+
+ def find(type, name)
+ if @steps.find(type, name).nil?
+ @steps.add(type,
+ Step.new(name) do
+ raise Spec::Example::ExamplePendingError.new("Unimplemented step: #{name}")
+ end
+ )
+ end
+ @steps.find(type, name)
+ end
+
+ def clear
+ @steps.clear
+ end
+
+ def empty?
+ @steps.empty?
+ end
+
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/story.rb b/vendor/plugins/rspec/lib/spec/story/story.rb
new file mode 100644
index 000000000..112e9414b
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/story.rb
@@ -0,0 +1,42 @@
+module Spec
+ module Story
+ class Story
+ attr_reader :title, :narrative
+
+ def initialize(title, narrative, params = {}, &body)
+ @body = body
+ @title = title
+ @narrative = narrative
+ @params = params
+ end
+
+ def [](key)
+ @params[key]
+ end
+
+ def run_in(obj)
+ obj.instance_eval(&@body)
+ end
+
+ def assign_steps_to(assignee)
+ if @params[:steps]
+ assignee.use(@params[:steps])
+ else
+ case keys = @params[:steps_for]
+ when Symbol
+ keys = [keys]
+ when nil
+ keys = []
+ end
+ keys.each do |key|
+ assignee.use(steps_for(key))
+ end
+ end
+ end
+
+ def steps_for(key)
+ $rspec_story_steps[key]
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/story/world.rb b/vendor/plugins/rspec/lib/spec/story/world.rb
new file mode 100644
index 000000000..6296537b8
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/story/world.rb
@@ -0,0 +1,124 @@
+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
+ 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