aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/plugins/rspec/lib/spec/runner
diff options
context:
space:
mode:
authorlouise <louise>2007-10-16 19:10:21 +0000
committerlouise <louise>2007-10-16 19:10:21 +0000
commitd350850897a5ee7a994d3c618529cf5beecf71ea (patch)
tree39de7013d0a3377f063fbd53da7c89f207eeedd0 /vendor/plugins/rspec/lib/spec/runner
parent3b1d8bfdeea68da1ad083a305d0df8f458c362a0 (diff)
Adding rspec plugin
Diffstat (limited to 'vendor/plugins/rspec/lib/spec/runner')
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb57
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb123
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/command_line.rb22
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb21
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/extensions/kernel.rb50
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/extensions/object.rb32
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter.rb9
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb76
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb130
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/failing_behaviours_formatter.rb29
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/failing_examples_formatter.rb22
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb323
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb31
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/rdoc_formatter.rb24
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb52
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb29
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb72
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb10
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/option_parser.rb227
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/options.rb175
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/reporter.rb125
-rw-r--r--vendor/plugins/rspec/lib/spec/runner/spec_parser.rb50
22 files changed, 1689 insertions, 0 deletions
diff --git a/vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb b/vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb
new file mode 100644
index 000000000..aacc2c8b8
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/backtrace_tweaker.rb
@@ -0,0 +1,57 @@
+module Spec
+ module Runner
+ class BacktraceTweaker
+ def clean_up_double_slashes(line)
+ line.gsub!('//','/')
+ end
+ end
+
+ class NoisyBacktraceTweaker < BacktraceTweaker
+ def tweak_backtrace(error, spec_name)
+ return if error.backtrace.nil?
+ error.backtrace.each do |line|
+ clean_up_double_slashes(line)
+ end
+ end
+ end
+
+ # Tweaks raised Exceptions to mask noisy (unneeded) parts of the backtrace
+ class QuietBacktraceTweaker < BacktraceTweaker
+ unless defined?(IGNORE_PATTERNS)
+ root_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', '..'))
+ spec_files = Dir["#{root_dir}/lib/spec/*"].map do |path|
+ subpath = path[root_dir.length..-1]
+ /#{subpath}/
+ end
+ IGNORE_PATTERNS = spec_files + [
+ /\/lib\/ruby\//,
+ /bin\/spec:/,
+ /bin\/rcov:/,
+ /lib\/rspec_on_rails/,
+ /vendor\/rails/,
+ # TextMate's Ruby and RSpec plugins
+ /Ruby\.tmbundle\/Support\/tmruby.rb:/,
+ /RSpec\.tmbundle\/Support\/lib/,
+ /temp_textmate\./,
+ /mock_frameworks\/rspec/,
+ /spec_server/
+ ]
+ end
+
+ def tweak_backtrace(error, spec_name)
+ return if error.backtrace.nil?
+ error.backtrace.collect! do |line|
+ clean_up_double_slashes(line)
+ IGNORE_PATTERNS.each do |ignore|
+ if line =~ ignore
+ line = nil
+ break
+ end
+ end
+ line
+ end
+ error.backtrace.compact!
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb b/vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb
new file mode 100644
index 000000000..1ac891f3c
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/behaviour_runner.rb
@@ -0,0 +1,123 @@
+module Spec
+ module Runner
+ class BehaviourRunner
+
+ def initialize(options, arg=nil)
+ @behaviours = []
+ @options = options
+ end
+
+ def add_behaviour(behaviour)
+ if !specified_examples.nil? && !specified_examples.empty?
+ behaviour.retain_examples_matching!(specified_examples)
+ end
+ @behaviours << behaviour if behaviour.number_of_examples != 0 && !behaviour.shared?
+ end
+
+ # Runs all behaviours and returns the number of failures.
+ def run(paths, exit_when_done)
+ prepare!(paths)
+ begin
+ run_behaviours
+ rescue Interrupt
+ ensure
+ report_end
+ end
+ failure_count = report_dump
+
+ heckle if(failure_count == 0 && !@options.heckle_runner.nil?)
+
+ if(exit_when_done)
+ exit_code = (failure_count == 0) ? 0 : 1
+ exit(exit_code)
+ end
+ failure_count
+ end
+
+ def report_end
+ @options.reporter.end
+ end
+
+ def report_dump
+ @options.reporter.dump
+ end
+
+ def prepare!(paths)
+ unless paths.nil? # It's nil when running single specs with ruby
+ paths = find_paths(paths)
+ sorted_paths = sort_paths(paths)
+ load_specs(sorted_paths) # This will populate @behaviours via callbacks to add_behaviour
+ end
+ @options.reporter.start(number_of_examples)
+ @behaviours.reverse! if @options.reverse
+ set_sequence_numbers
+ end
+
+ def run_behaviours
+ @behaviours.each do |behaviour|
+ behaviour.run(@options.reporter, @options.dry_run, @options.reverse, @options.timeout)
+ end
+ end
+
+ def number_of_examples
+ @behaviours.inject(0) {|sum, behaviour| sum + behaviour.number_of_examples}
+ end
+
+ FILE_SORTERS = {
+ 'mtime' => lambda {|file_a, file_b| File.mtime(file_b) <=> File.mtime(file_a)}
+ }
+
+ def sorter(paths)
+ FILE_SORTERS[@options.loadby]
+ end
+
+ def sort_paths(paths)
+ sorter = sorter(paths)
+ paths = paths.sort(&sorter) unless sorter.nil?
+ paths
+ end
+
+ private
+
+ # Sets the #number on each Example
+ def set_sequence_numbers
+ number = 0
+ @behaviours.each do |behaviour|
+ number = behaviour.set_sequence_numbers(number, @options.reverse)
+ end
+ end
+
+ def find_paths(paths)
+ result = []
+ paths.each do |path|
+ if File.directory?(path)
+ result += Dir["#{path}/**/*.rb"]
+ elsif File.file?(path)
+ result << path
+ else
+ raise "File or directory not found: #{path}"
+ end
+ end
+ result
+ end
+
+ def load_specs(paths)
+ paths.each do |path|
+ load path
+ end
+ end
+
+ def specified_examples
+ @options.examples
+ end
+
+ def heckle
+ heckle_runner = @options.heckle_runner
+ @options.heckle_runner = nil
+ behaviour_runner = self.class.new(@options)
+ behaviour_runner.instance_variable_set(:@behaviours, @behaviours)
+ heckle_runner.heckle_with(behaviour_runner)
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/command_line.rb b/vendor/plugins/rspec/lib/spec/runner/command_line.rb
new file mode 100644
index 000000000..0d70337e1
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/command_line.rb
@@ -0,0 +1,22 @@
+require 'spec/runner/option_parser'
+
+module Spec
+ module Runner
+ # Facade to run specs without having to fork a new ruby process (using `spec ...`)
+ class CommandLine
+ # Runs specs. +argv+ is the commandline args as per the spec commandline API, +err+
+ # and +out+ are the streams output will be written to. +exit+ tells whether or
+ # not a system exit should be called after the specs are run and
+ # +warn_if_no_files+ tells whether or not a warning (the help message)
+ # should be printed to +err+ in case no files are specified.
+ def self.run(argv, err, out, exit=true, warn_if_no_files=true)
+ old_behaviour_runner = defined?($behaviour_runner) ? $behaviour_runner : nil
+ $behaviour_runner = OptionParser.new.create_behaviour_runner(argv, err, out, warn_if_no_files)
+ return if $behaviour_runner.nil? # This is the case if we use --drb
+
+ $behaviour_runner.run(argv, exit)
+ $behaviour_runner = old_behaviour_runner
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb b/vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb
new file mode 100644
index 000000000..7e745fb71
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/drb_command_line.rb
@@ -0,0 +1,21 @@
+require "drb/drb"
+
+module Spec
+ module Runner
+ # Facade to run specs by connecting to a DRB server
+ class DrbCommandLine
+ # Runs specs on a DRB server. Note that this API is similar to that of
+ # CommandLine - making it possible for clients to use both interchangeably.
+ def self.run(argv, stderr, stdout, exit=true, warn_if_no_files=true)
+ begin
+ DRb.start_service
+ spec_server = DRbObject.new_with_uri("druby://localhost:8989")
+ spec_server.run(argv, stderr, stdout)
+ rescue DRb::DRbConnError
+ stderr.puts "No server is running"
+ exit 1 if exit
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/extensions/kernel.rb b/vendor/plugins/rspec/lib/spec/runner/extensions/kernel.rb
new file mode 100644
index 000000000..75f2c335e
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/extensions/kernel.rb
@@ -0,0 +1,50 @@
+module Kernel
+ # Creates and registers an instance of a Spec::DSL::Behaviour (or a subclass).
+ # The instantiated behaviour class 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 behaviour class
+ # with an options Hash as the last argument:
+ #
+ # describe "name", :behaviour_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::DSL::BehaviourFactory#add_behaviour_class for details about
+ # how to register special Spec::DSL::Behaviour implementations.
+ #
+ def describe(*args, &block)
+ raise ArgumentError if args.empty?
+ args << {} unless Hash === args.last
+ args.last[:spec_path] = caller(0)[1]
+ register_behaviour(Spec::DSL::BehaviourFactory.create(*args, &block))
+ end
+ alias :context :describe
+
+ def respond_to(*names)
+ Spec::Matchers::RespondTo.new(*names)
+ end
+
+private
+
+ def register_behaviour(behaviour)
+ if behaviour.shared?
+ Spec::DSL::Behaviour.add_shared_behaviour(behaviour)
+ else
+ behaviour_runner.add_behaviour(behaviour)
+ end
+ end
+
+ def behaviour_runner
+ # TODO: Figure out a better way to get this considered "covered" and keep this statement on multiple lines
+ unless $behaviour_runner; \
+ $behaviour_runner = ::Spec::Runner::OptionParser.new.create_behaviour_runner(ARGV.dup, STDERR, STDOUT, false); \
+ at_exit { $behaviour_runner.run(nil, false) }; \
+ end
+ $behaviour_runner
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/extensions/object.rb b/vendor/plugins/rspec/lib/spec/runner/extensions/object.rb
new file mode 100644
index 000000000..49745352f
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/extensions/object.rb
@@ -0,0 +1,32 @@
+# The following copyright applies to Object#copy_instance_variables_from,
+# which we borrowed from active_support.
+#
+# Copyright (c) 2004 David Heinemeier Hansson
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+class Object
+ # From active_support
+ def copy_instance_variables_from(object, exclude = []) # :nodoc:
+ exclude += object.protected_instance_variables if object.respond_to? :protected_instance_variables
+
+ instance_variables = object.instance_variables - exclude.map { |name| name.to_s }
+ instance_variables.each { |name| instance_variable_set(name, object.instance_variable_get(name)) }
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter.rb
new file mode 100644
index 000000000..17512d958
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter.rb
@@ -0,0 +1,9 @@
+require 'spec/runner/formatter/base_formatter'
+require 'spec/runner/formatter/base_text_formatter'
+require 'spec/runner/formatter/progress_bar_formatter'
+require 'spec/runner/formatter/rdoc_formatter'
+require 'spec/runner/formatter/specdoc_formatter'
+require 'spec/runner/formatter/html_formatter'
+require 'spec/runner/formatter/failing_examples_formatter'
+require 'spec/runner/formatter/failing_behaviours_formatter'
+require 'spec/runner/formatter/snippet_extractor'
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb
new file mode 100644
index 000000000..7cc43ef0e
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/base_formatter.rb
@@ -0,0 +1,76 @@
+module Spec
+ module Runner
+ module Formatter
+ # Baseclass for formatters that implements all required methods as no-ops.
+ class BaseFormatter
+ def initialize(where)
+ @where = where
+ end
+
+ # This method is invoked before any examples are run, right after
+ # they have all been collected. This can be useful for special
+ # formatters that need to provide progress on feedback (graphical ones)
+ #
+ # This method will only be invoked once, and the next one to be invoked
+ # is #add_behaviour
+ def start(example_count)
+ end
+
+ # This method is invoked at the beginning of the execution of each behaviour.
+ # +name+ is the name of the behaviour and +first+ is true if it is the
+ # first behaviour - otherwise it's false.
+ #
+ # The next method to be invoked after this is #example_failed or #example_finished
+ def add_behaviour(name)
+ end
+
+ # This method is invoked when an +example+ starts.
+ def example_started(example)
+ end
+
+ # This method is invoked when an +example+ passes.
+ def example_passed(example)
+ end
+
+ # This method is invoked when an +example+ fails, i.e. an exception occurred
+ # inside it (such as a failed should or other exception). +counter+ is the
+ # sequence number of the failure (starting at 1) and +failure+ is the associated
+ # Failure object.
+ def example_failed(example, counter, failure)
+ end
+
+ # This method is invoked when an example is not yet implemented (i.e. has not
+ # been provided a block), or when an ExamplePendingError is raised.
+ # +name+ is the name of the example.
+ # +message+ is the message from the ExamplePendingError, if it exists, or the
+ # default value of "Not Yet Implemented"
+ def example_pending(behaviour_name, example_name, message)
+ end
+
+ # This method is invoked after all of the examples have executed. The next method
+ # to be invoked after this one is #dump_failure (once for each failed example),
+ def start_dump
+ end
+
+ # Dumps detailed information about an example failure.
+ # This method is invoked for each failed example after all examples have run. +counter+ is the sequence number
+ # of the associated example. +failure+ is a Failure object, which contains detailed
+ # information about the failure.
+ def dump_failure(counter, failure)
+ end
+
+ # This method is invoked after the dumping of examples and failures.
+ def dump_summary(duration, example_count, failure_count, pending_count)
+ end
+
+ # This gets invoked after the summary if option is set to do so.
+ def dump_pending
+ end
+
+ # This method is invoked at the very end. Allows the formatter to clean up, like closing open streams.
+ def close
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb
new file mode 100644
index 000000000..c3cf01b76
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/base_text_formatter.rb
@@ -0,0 +1,130 @@
+module Spec
+ module Runner
+ module Formatter
+ # Baseclass for text-based formatters. Can in fact be used for
+ # non-text based ones too - just ignore the +output+ constructor
+ # argument.
+ class BaseTextFormatter < BaseFormatter
+ attr_writer :dry_run
+
+ # Creates a new instance that will write to +where+. If +where+ is a
+ # String, output will be written to the File with that name, otherwise
+ # +where+ is exected to be an IO (or an object that responds to #puts and #write).
+ def initialize(where)
+ super(where)
+ if where.is_a?(String)
+ @output = File.open(where, 'w')
+ elsif where == STDOUT
+ @output = Kernel
+ def @output.flush
+ STDOUT.flush
+ end
+ else
+ @output = where
+ end
+ @colour = false
+ @dry_run = false
+ @snippet_extractor = SnippetExtractor.new
+ @pending_examples = []
+ end
+
+ def example_pending(behaviour_name, example_name, message)
+ @pending_examples << ["#{behaviour_name} #{example_name}", message]
+ end
+
+ def colour=(colour)
+ @colour = colour
+ begin ; require 'Win32/Console/ANSI' if @colour && PLATFORM =~ /win32/ ; rescue LoadError ; raise "You must gem install win32console to use colour on Windows" ; end
+ end
+
+ def dump_failure(counter, failure)
+ @output.puts
+ @output.puts "#{counter.to_s})"
+ @output.puts colourise("#{failure.header}\n#{failure.exception.message}", failure)
+ @output.puts format_backtrace(failure.exception.backtrace)
+ @output.flush
+ end
+
+ def colourise(s, failure)
+ if(failure.expectation_not_met?)
+ red(s)
+ elsif(failure.pending_fixed?)
+ blue(s)
+ else
+ magenta(s)
+ end
+ end
+
+ def dump_summary(duration, example_count, failure_count, pending_count)
+ return if @dry_run
+ @output.puts
+ @output.puts "Finished in #{duration} seconds"
+ @output.puts
+
+ summary = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
+ summary << ", #{pending_count} pending" if pending_count > 0
+
+ if failure_count == 0
+ if pending_count > 0
+ @output.puts yellow(summary)
+ else
+ @output.puts green(summary)
+ end
+ else
+ @output.puts red(summary)
+ end
+ @output.flush
+ dump_pending
+ end
+
+ def dump_pending
+ unless @pending_examples.empty?
+ @output.puts
+ @output.puts "Pending:"
+ @pending_examples.each do |pending_example|
+ @output.puts "#{pending_example[0]} (#{pending_example[1]})"
+ end
+ end
+ @output.flush
+ end
+
+ def close
+ if IO === @output
+ @output.close
+ end
+ end
+
+ def format_backtrace(backtrace)
+ return "" if backtrace.nil?
+ backtrace.map { |line| backtrace_line(line) }.join("\n")
+ end
+
+ protected
+
+ def backtrace_line(line)
+ line.sub(/\A([^:]+:\d+)$/, '\\1:')
+ end
+
+ def colour(text, colour_code)
+ return text unless @colour && output_to_tty?
+ "#{colour_code}#{text}\e[0m"
+ end
+
+ def output_to_tty?
+ begin
+ @output == Kernel || @output.tty?
+ rescue NoMethodError
+ false
+ end
+ end
+
+ def green(text); colour(text, "\e[32m"); end
+ def red(text); colour(text, "\e[31m"); end
+ def magenta(text); colour(text, "\e[35m"); end
+ def yellow(text); colour(text, "\e[33m"); end
+ def blue(text); colour(text, "\e[34m"); end
+
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/failing_behaviours_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/failing_behaviours_formatter.rb
new file mode 100644
index 000000000..2b3940fd3
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/failing_behaviours_formatter.rb
@@ -0,0 +1,29 @@
+module Spec
+ module Runner
+ module Formatter
+ class FailingBehavioursFormatter < BaseTextFormatter
+ def add_behaviour(behaviour_name)
+ if behaviour_name =~ /(.*) \(druby.*\)$/
+ @behaviour_name = $1
+ else
+ @behaviour_name = behaviour_name
+ end
+ end
+
+ def example_failed(example, counter, failure)
+ unless @behaviour_name.nil?
+ @output.puts @behaviour_name
+ @behaviour_name = nil
+ @output.flush
+ 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/failing_examples_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/failing_examples_formatter.rb
new file mode 100644
index 000000000..9728deaf0
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/failing_examples_formatter.rb
@@ -0,0 +1,22 @@
+module Spec
+ module Runner
+ module Formatter
+ class FailingExamplesFormatter < BaseTextFormatter
+ def add_behaviour(behaviour_name)
+ @behaviour_name = behaviour_name
+ end
+
+ def example_failed(example, counter, failure)
+ @output.puts "#{@behaviour_name} #{example.description}"
+ @output.flush
+ 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/html_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb
new file mode 100644
index 000000000..d9c422e55
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/html_formatter.rb
@@ -0,0 +1,323 @@
+require 'erb'
+
+module Spec
+ module Runner
+ module Formatter
+ class HtmlFormatter < BaseTextFormatter
+ include ERB::Util # for the #h method
+
+ def initialize(output)
+ super
+ @current_behaviour_number = 0
+ @current_example_number = 0
+ end
+
+ # The number of the currently running behaviour
+ def current_behaviour_number
+ @current_behaviour_number
+ end
+
+ # The number of the currently running example (a global counter)
+ def current_example_number
+ @current_example_number
+ end
+
+ def start(example_count)
+ @example_count = example_count
+
+ @output.puts html_header
+ @output.puts report_header
+ @output.flush
+ end
+
+ def add_behaviour(name)
+ @behaviour_red = false
+ @behaviour_red = false
+ @current_behaviour_number += 1
+ unless current_behaviour_number == 1
+ @output.puts " </dl>"
+ @output.puts "</div>"
+ end
+ @output.puts "<div class=\"behaviour\">"
+ @output.puts " <dl>"
+ @output.puts " <dt id=\"behaviour_#{current_behaviour_number}\">#{h(name)}</dt>"
+ @output.flush
+ end
+
+ def start_dump
+ @output.puts " </dl>"
+ @output.puts "</div>"
+ @output.flush
+ end
+
+ def example_started(example)
+ @current_example_number = example.number
+ end
+
+ def example_passed(example)
+ move_progress
+ @output.puts " <dd class=\"spec passed\"><span class=\"passed_spec_name\">#{h(example.description)}</span></dd>"
+ @output.flush
+ end
+
+ def example_failed(example, counter, failure)
+ extra = extra_failure_content(failure)
+ failure_style = failure.pending_fixed? ? 'pending_fixed' : 'failed'
+ @output.puts " <script type=\"text/javascript\">makeRed('rspec-header');</script>" unless @header_red
+ @header_red = true
+ @output.puts " <script type=\"text/javascript\">makeRed('behaviour_#{current_behaviour_number}');</script>" unless @behaviour_red
+ @behaviour_red = true
+ move_progress
+ @output.puts " <dd class=\"spec #{failure_style}\">"
+ @output.puts " <span class=\"failed_spec_name\">#{h(example.description)}</span>"
+ @output.puts " <div class=\"failure\" id=\"failure_#{counter}\">"
+ @output.puts " <div class=\"message\"><pre>#{h(failure.exception.message)}</pre></div>" unless failure.exception.nil?
+ @output.puts " <div class=\"backtrace\"><pre>#{format_backtrace(failure.exception.backtrace)}</pre></div>" unless failure.exception.nil?
+ @output.puts extra unless extra == ""
+ @output.puts " </div>"
+ @output.puts " </dd>"
+ @output.flush
+ end
+
+ def example_pending(behaviour_name, example_name, message)
+ @output.puts " <script type=\"text/javascript\">makeYellow('rspec-header');</script>" unless @header_red
+ @output.puts " <script type=\"text/javascript\">makeYellow('behaviour_#{current_behaviour_number}');</script>" unless @behaviour_red
+ move_progress
+ @output.puts " <dd class=\"spec not_implemented\"><span class=\"not_implemented_spec_name\">#{h(example_name)}</span></dd>"
+ @output.flush
+ end
+
+ # Override this method if you wish to output extra HTML for a failed spec. For example, you
+ # could output links to images or other files produced during the specs.
+ #
+ def extra_failure_content(failure)
+ " <pre class=\"ruby\"><code>#{@snippet_extractor.snippet(failure.exception)}</code></pre>"
+ end
+
+ def move_progress
+ percent_done = @example_count == 0 ? 100.0 : ((current_example_number + 1).to_f / @example_count.to_f * 1000).to_i / 10.0
+ @output.puts " <script type=\"text/javascript\">moveProgressBar('#{percent_done}');</script>"
+ @output.flush
+ end
+
+ def dump_failure(counter, failure)
+ end
+
+ def dump_summary(duration, example_count, failure_count, pending_count)
+ if @dry_run
+ totals = "This was a dry-run"
+ else
+ totals = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failure#{'s' unless failure_count == 1}"
+ totals << ", #{pending_count} pending" if pending_count > 0
+ end
+ @output.puts "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{duration} seconds</strong>\";</script>"
+ @output.puts "<script type=\"text/javascript\">document.getElementById('totals').innerHTML = \"#{totals}\";</script>"
+ @output.puts "</div>"
+ @output.puts "</div>"
+ @output.puts "</body>"
+ @output.puts "</html>"
+ @output.flush
+ end
+
+ def html_header
+ <<-EOF
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <title>RSpec results</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
+ <meta http-equiv="Expires" content="-1" />
+ <meta http-equiv="Pragma" content="no-cache" />
+ <style type="text/css">
+ body {
+ margin: 0;
+ padding: 0;
+ background: #fff;
+ font-size: 80%;
+ }
+ </style>
+</head>
+<body>
+EOF
+ end
+
+ def report_header
+ <<-EOF
+<div class="rspec-report">
+ <script type="text/javascript">
+ // <![CDATA[
+#{global_scripts}
+ // ]]>
+ </script>
+ <style type="text/css">
+#{global_styles}
+ </style>
+
+<div id="rspec-header">
+ <h1>RSpec Results</h1>
+
+ <div id="summary">
+ <p id="totals">&nbsp;</p>
+ <p id="duration">&nbsp;</p>
+ </div>
+</div>
+
+<div class="results">
+EOF
+ end
+
+ def global_scripts
+ <<-EOF
+function moveProgressBar(percentDone) {
+ document.getElementById("rspec-header").style.width = percentDone +"%";
+}
+function makeRed(element_id) {
+ document.getElementById(element_id).style.background = '#C40D0D';
+ document.getElementById(element_id).style.color = '#FFFFFF';
+}
+
+function makeYellow(element_id) {
+ if (element_id == "rspec-header" && document.getElementById(element_id).style.background != '#C40D0D')
+ {
+ document.getElementById(element_id).style.background = '#FAF834';
+ document.getElementById(element_id).style.color = '#000000';
+ }
+ else
+ {
+ document.getElementById(element_id).style.background = '#FAF834';
+ document.getElementById(element_id).style.color = '#000000';
+ }
+}
+EOF
+ end
+
+ def global_styles
+ <<-EOF
+#rspec-header {
+ background: #65C400; color: #fff;
+}
+
+.rspec-report h1 {
+ margin: 0px 10px 0px 10px;
+ padding: 10px;
+ font-family: "Lucida Grande", Helvetica, sans-serif;
+ font-size: 1.8em;
+}
+
+#summary {
+ margin: 0; padding: 5px 10px;
+ font-family: "Lucida Grande", Helvetica, sans-serif;
+ text-align: right;
+ position: absolute;
+ top: 0px;
+ right: 0px;
+}
+
+#summary p {
+ margin: 0 0 0 2px;
+}
+
+#summary #totals {
+ font-size: 1.2em;
+}
+
+.behaviour {
+ margin: 0 10px 5px;
+ background: #fff;
+}
+
+dl {
+ margin: 0; padding: 0 0 5px;
+ font: normal 11px "Lucida Grande", Helvetica, sans-serif;
+}
+
+dt {
+ padding: 3px;
+ background: #65C400;
+ color: #fff;
+ font-weight: bold;
+}
+
+dd {
+ margin: 5px 0 5px 5px;
+ padding: 3px 3px 3px 18px;
+}
+
+dd.spec.passed {
+ border-left: 5px solid #65C400;
+ border-bottom: 1px solid #65C400;
+ background: #DBFFB4; color: #3D7700;
+}
+
+dd.spec.failed {
+ border-left: 5px solid #C20000;
+ border-bottom: 1px solid #C20000;
+ color: #C20000; background: #FFFBD3;
+}
+
+dd.spec.not_implemented {
+ border-left: 5px solid #FAF834;
+ border-bottom: 1px solid #FAF834;
+ background: #FCFB98; color: #131313;
+}
+
+dd.spec.pending_fixed {
+ border-left: 5px solid #0000C2;
+ border-bottom: 1px solid #0000C2;
+ color: #0000C2; background: #D3FBFF;
+}
+
+.backtrace {
+ color: #000;
+ font-size: 12px;
+}
+
+a {
+ color: #BE5C00;
+}
+
+/* Ruby code, style similar to vibrant ink */
+.ruby {
+ font-size: 12px;
+ font-family: monospace;
+ color: white;
+ background-color: black;
+ padding: 0.1em 0 0.2em 0;
+}
+
+.ruby .keyword { color: #FF6600; }
+.ruby .constant { color: #339999; }
+.ruby .attribute { color: white; }
+.ruby .global { color: white; }
+.ruby .module { color: white; }
+.ruby .class { color: white; }
+.ruby .string { color: #66FF00; }
+.ruby .ident { color: white; }
+.ruby .method { color: #FFCC00; }
+.ruby .number { color: white; }
+.ruby .char { color: white; }
+.ruby .comment { color: #9933CC; }
+.ruby .symbol { color: white; }
+.ruby .regex { color: #44B4CC; }
+.ruby .punct { color: white; }
+.ruby .escape { color: white; }
+.ruby .interp { color: white; }
+.ruby .expr { color: white; }
+
+.ruby .offending { background-color: gray; }
+.ruby .linenum {
+ width: 75px;
+ padding: 0.1em 1em 0.2em 0;
+ color: #000000;
+ background-color: #FFFBD3;
+}
+EOF
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb
new file mode 100644
index 000000000..624f06e7c
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/progress_bar_formatter.rb
@@ -0,0 +1,31 @@
+module Spec
+ module Runner
+ module Formatter
+ class ProgressBarFormatter < BaseTextFormatter
+ def add_behaviour(name)
+ end
+
+ def example_failed(example, counter, failure)
+ @output.print colourise('F', failure)
+ @output.flush
+ end
+
+ def example_passed(example)
+ @output.print green('.')
+ @output.flush
+ end
+
+ def example_pending(behaviour_name, example_name, message)
+ super
+ @output.print yellow('P')
+ @output.flush
+ end
+
+ def start_dump
+ @output.puts
+ @output.flush
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/rdoc_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/rdoc_formatter.rb
new file mode 100644
index 000000000..0fd22ba6c
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/rdoc_formatter.rb
@@ -0,0 +1,24 @@
+module Spec
+ module Runner
+ module Formatter
+ class RdocFormatter < BaseTextFormatter
+ def add_behaviour(name)
+ @output.puts "# #{name}"
+ end
+
+ def example_passed(example)
+ @output.puts "# * #{example.description}"
+ @output.flush
+ end
+
+ def example_failed(example, counter, failure)
+ @output.puts "# * #{example.description} [#{counter} - FAILED]"
+ end
+
+ def example_pending(behaviour_name, example_name, message)
+ @output.puts "# * #{behaviour_name} #{example_name} [PENDING: #{message}]"
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb
new file mode 100644
index 000000000..41119fe46
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/snippet_extractor.rb
@@ -0,0 +1,52 @@
+module Spec
+ module Runner
+ module Formatter
+ # This class extracts code snippets by looking at the backtrace of the passed error
+ class SnippetExtractor #:nodoc:
+ class NullConverter; def convert(code, pre); code; end; end #:nodoc:
+ begin; require 'rubygems'; require 'syntax/convertors/html'; @@converter = Syntax::Convertors::HTML.for_syntax "ruby"; rescue LoadError => e; @@converter = NullConverter.new; end
+
+ def snippet(error)
+ raw_code, line = snippet_for(error.backtrace[0])
+ highlighted = @@converter.convert(raw_code, false)
+ highlighted << "\n<span class=\"comment\"># gem install syntax to get syntax highlighting</span>" if @@converter.is_a?(NullConverter)
+ post_process(highlighted, line)
+ end
+
+ def snippet_for(error_line)
+ if error_line =~ /(.*):(\d+)/
+ file = $1
+ line = $2.to_i
+ [lines_around(file, line), line]
+ else
+ ["# Couldn't get snippet for #{error_line}", 1]
+ end
+ end
+
+ def lines_around(file, line)
+ if File.file?(file)
+ lines = File.open(file).read.split("\n")
+ min = [0, line-3].max
+ max = [line+1, lines.length-1].min
+ selected_lines = []
+ selected_lines.join("\n")
+ lines[min..max].join("\n")
+ else
+ "# Couldn't get snippet for #{file}"
+ end
+ end
+
+ def post_process(highlighted, offending_line)
+ new_lines = []
+ highlighted.split("\n").each_with_index do |line, i|
+ new_line = "<span class=\"linenum\">#{offending_line+i-2}</span>#{line}"
+ new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
+ new_lines << new_line
+ end
+ new_lines.join("\n")
+ end
+
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb b/vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb
new file mode 100644
index 000000000..ad794b238
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/formatter/specdoc_formatter.rb
@@ -0,0 +1,29 @@
+module Spec
+ module Runner
+ module Formatter
+ class SpecdocFormatter < BaseTextFormatter
+ def add_behaviour(name)
+ @output.puts
+ @output.puts name
+ @output.flush
+ end
+
+ def example_failed(example, counter, failure)
+ @output.puts failure.expectation_not_met? ? red("- #{example.description} (FAILED - #{counter})") : magenta("- #{example.description} (ERROR - #{counter})")
+ @output.flush
+ end
+
+ def example_passed(example)
+ @output.puts green("- #{example.description}")
+ @output.flush
+ end
+
+ def example_pending(behaviour_name, example_name, message)
+ super
+ @output.puts yellow("- #{example_name} (PENDING: #{message})")
+ @output.flush
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb b/vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb
new file mode 100644
index 000000000..b6de4ef73
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/heckle_runner.rb
@@ -0,0 +1,72 @@
+begin
+ require 'rubygems'
+ require 'heckle'
+rescue LoadError ; raise "You must gem install heckle to use --heckle" ; end
+
+module Spec
+ module Runner
+ # Creates a new Heckler configured to heckle all methods in the classes
+ # whose name matches +filter+
+ class HeckleRunner
+ def initialize(filter, heckle_class=Heckler)
+ @filter = filter
+ @heckle_class = heckle_class
+ end
+
+ # Runs all the contexts held by +behaviour_runner+ once for each of the
+ # methods in the matched classes.
+ def heckle_with(behaviour_runner)
+ if @filter =~ /(.*)[#\.](.*)/
+ heckle_method($1, $2)
+ else
+ heckle_class_or_module(@filter)
+ end
+ end
+
+ def heckle_method(class_name, method_name)
+ verify_constant(class_name)
+ heckle = @heckle_class.new(class_name, method_name, behaviour_runner)
+ heckle.validate
+ end
+
+ def heckle_class_or_module(class_or_module_name)
+ verify_constant(class_or_module_name)
+ pattern = /^#{class_or_module_name}/
+ classes = []
+ ObjectSpace.each_object(Class) do |klass|
+ classes << klass if klass.name =~ pattern
+ end
+
+ classes.each do |klass|
+ klass.instance_methods(false).each do |method_name|
+ heckle = @heckle_class.new(klass.name, method_name, behaviour_runner)
+ heckle.validate
+ end
+ end
+ end
+
+ def verify_constant(name)
+ begin
+ # This is defined in Heckle
+ name.to_class
+ rescue
+ raise "Heckling failed - \"#{name}\" is not a known class or module"
+ end
+ end
+ end
+
+ #Supports Heckle 1.2 and prior (earlier versions used Heckle::Base)
+ class Heckler < (Heckle.const_defined?(:Base) ? Heckle::Base : Heckle)
+ def initialize(klass_name, method_name, behaviour_runner)
+ super(klass_name, method_name)
+ @behaviour_runner = behaviour_runner
+ end
+
+ def tests_pass?
+ paths = [] # We can pass an empty array of paths - our specs are already loaded.
+ failure_count = @behaviour_runner.run(paths, false)
+ failure_count == 0
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb b/vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb
new file mode 100644
index 000000000..02aa37953
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/heckle_runner_unsupported.rb
@@ -0,0 +1,10 @@
+module Spec
+ module Runner
+ # Dummy implementation for Windows that just fails (Heckle is not supported on Windows)
+ class HeckleRunner
+ def initialize(filter)
+ raise "Heckle not supported on Windows"
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/option_parser.rb b/vendor/plugins/rspec/lib/spec/runner/option_parser.rb
new file mode 100644
index 000000000..1facb85a8
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/option_parser.rb
@@ -0,0 +1,227 @@
+require 'optparse'
+require 'stringio'
+
+module Spec
+ module Runner
+ class OptionParser
+ BUILT_IN_FORMATTERS = {
+ 'specdoc' => Formatter::SpecdocFormatter,
+ 's' => Formatter::SpecdocFormatter,
+ 'html' => Formatter::HtmlFormatter,
+ 'h' => Formatter::HtmlFormatter,
+ 'rdoc' => Formatter::RdocFormatter,
+ 'r' => Formatter::RdocFormatter,
+ 'progress' => Formatter::ProgressBarFormatter,
+ 'p' => Formatter::ProgressBarFormatter,
+ 'failing_examples' => Formatter::FailingExamplesFormatter,
+ 'e' => Formatter::FailingExamplesFormatter,
+ 'failing_behaviours' => Formatter::FailingBehavioursFormatter,
+ 'b' => Formatter::FailingBehavioursFormatter
+ }
+
+ COMMAND_LINE = {
+ :diff => ["-D", "--diff [FORMAT]", "Show diff of objects that are expected to be equal when they are not",
+ "Builtin formats: unified|u|context|c",
+ "You can also specify a custom differ class",
+ "(in which case you should also specify --require)"],
+ :colour => ["-c", "--colour", "--color", "Show coloured (red/green) output"],
+ :example => ["-e", "--example [NAME|FILE_NAME]", "Execute example(s) with matching name(s). If the argument is",
+ "the path to an existing file (typically generated by a previous",
+ "run using --format failing_examples:file.txt), then the examples",
+ "on each line of thatfile will be executed. If the file is empty,",
+ "all examples will be run (as if --example was not specified).",
+ " ",
+ "If the argument is not an existing file, then it is treated as",
+ "an example name directly, causing RSpec to run just the example",
+ "matching that name"],
+ :specification => ["-s", "--specification [NAME]", "DEPRECATED - use -e instead", "(This will be removed when autotest works with -e)"],
+ :line => ["-l", "--line LINE_NUMBER", Integer, "Execute behaviout or specification at given line.",
+ "(does not work for dynamically generated specs)"],
+ :format => ["-f", "--format FORMAT[:WHERE]", "Specifies what format to use for output. Specify WHERE to tell",
+ "the formatter where to write the output. All built-in formats",
+ "expect WHERE to be a file name, and will write to STDOUT if it's",
+ "not specified. The --format option may be specified several times",
+ "if you want several outputs",
+ " ",
+ "Builtin formats: ",
+ "progress|p : Text progress",
+ "specdoc|s : Behaviour doc as text",
+ "rdoc|r : Behaviour doc as RDoc",
+ "html|h : A nice HTML report",
+ "failing_examples|e : Write all failing examples - input for --example",
+ "failing_behaviours|b : Write all failing behaviours - input for --example",
+ " ",
+ "FORMAT can also be the name of a custom formatter class",
+ "(in which case you should also specify --require to load it)"],
+ :require => ["-r", "--require FILE", "Require FILE before running specs",
+ "Useful for loading custom formatters or other extensions.",
+ "If this option is used it must come before the others"],
+ :backtrace => ["-b", "--backtrace", "Output full backtrace"],
+ :loadby => ["-L", "--loadby STRATEGY", "Specify the strategy by which spec files should be loaded.",
+ "STRATEGY can currently only be 'mtime' (File modification time)",
+ "By default, spec files are loaded in alphabetical order if --loadby",
+ "is not specified."],
+ :reverse => ["-R", "--reverse", "Run examples in reverse order"],
+ :timeout => ["-t", "--timeout FLOAT", "Interrupt and fail each example that doesn't complete in the",
+ "specified time"],
+ :heckle => ["-H", "--heckle CODE", "If all examples pass, this will mutate the classes and methods",
+ "identified by CODE little by little and run all the examples again",
+ "for each mutation. The intent is that for each mutation, at least",
+ "one example *should* fail, and RSpec will tell you if this is not the",
+ "case. CODE should be either Some::Module, Some::Class or",
+ "Some::Fabulous#method}"],
+ :dry_run => ["-d", "--dry-run", "Invokes formatters without executing the examples."],
+ :options_file => ["-O", "--options PATH", "Read options from a file"],
+ :generate_options => ["-G", "--generate-options PATH", "Generate an options file for --options"],
+ :runner => ["-U", "--runner RUNNER", "Use a custom BehaviourRunner."],
+ :drb => ["-X", "--drb", "Run examples via DRb. (For example against script/spec_server)"],
+ :version => ["-v", "--version", "Show version"],
+ :help => ["-h", "--help", "You're looking at it"]
+ }
+
+ def initialize
+ @spec_parser = SpecParser.new
+ @file_factory = File
+ end
+
+ def create_behaviour_runner(args, err, out, warn_if_no_files)
+ options = parse(args, err, out, warn_if_no_files)
+ # Some exit points in parse (--generate-options, --drb) don't return the options,
+ # but hand over control. In that case we don't want to continue.
+ return nil unless options.is_a?(Options)
+ options.configure
+ options.behaviour_runner
+ end
+
+ def parse(args, err, out, warn_if_no_files)
+ options_file = nil
+ args_copy = args.dup
+ options = Options.new(err, out)
+
+ opts = ::OptionParser.new do |opts|
+ opts.banner = "Usage: spec (FILE|DIRECTORY|GLOB)+ [options]"
+ opts.separator ""
+
+ def opts.rspec_on(name, &block)
+ on(*COMMAND_LINE[name], &block)
+ end
+
+ opts.rspec_on(:diff) {|diff| options.parse_diff(diff)}
+
+ opts.rspec_on(:colour) {options.colour = true}
+
+ opts.rspec_on(:example) {|example| options.parse_example(example)}
+
+ opts.rspec_on(:specification) {|example| options.parse_example(example)}
+
+ opts.rspec_on(:line) {|line_number| options.line_number = line_number.to_i}
+
+ opts.rspec_on(:format) {|format| options.parse_format(format)}
+
+ opts.rspec_on(:require) {|req| options.parse_require(req)}
+
+ opts.rspec_on(:backtrace) {options.backtrace_tweaker = NoisyBacktraceTweaker.new}
+
+ opts.rspec_on(:loadby) {|loadby| options.loadby = loadby}
+
+ opts.rspec_on(:reverse) {options.reverse = true}
+
+ opts.rspec_on(:timeout) {|timeout| options.timeout = timeout.to_f}
+
+ opts.rspec_on(:heckle) {|heckle| options.parse_heckle(heckle)}
+
+ opts.rspec_on(:dry_run) {options.dry_run = true}
+
+ opts.rspec_on(:options_file) do |options_file|
+ return parse_options_file(options_file, out, err, args_copy, warn_if_no_files)
+ end
+
+ opts.rspec_on(:generate_options) do |options_file|
+ options.parse_generate_options(options_file, args_copy, out)
+ end
+
+ opts.rspec_on(:runner) do |runner|
+ options.runner_arg = runner
+ end
+
+ opts.rspec_on(:drb) do
+ return parse_drb(args_copy, out, err, warn_if_no_files)
+ end
+
+ opts.rspec_on(:version) {parse_version(out)}
+
+ opts.on_tail(*COMMAND_LINE[:help]) {parse_help(opts, out)}
+ end
+ opts.parse!(args)
+
+ if args.empty? && warn_if_no_files
+ err.puts "No files specified."
+ err.puts opts
+ exit(6) if err == $stderr
+ end
+
+ if options.line_number
+ set_spec_from_line_number(options, args, err)
+ end
+
+ if options.formatters.empty?
+ options.formatters << Formatter::ProgressBarFormatter.new(out)
+ end
+
+ options
+ end
+
+ def parse_options_file(options_file, out_stream, error_stream, args_copy, warn_if_no_files)
+ # Remove the --options option and the argument before writing to file
+ index = args_copy.index("-O") || args_copy.index("--options")
+ args_copy.delete_at(index)
+ args_copy.delete_at(index)
+
+ new_args = args_copy + IO.readlines(options_file).map {|l| l.chomp.split " "}.flatten
+ return CommandLine.run(new_args, error_stream, out_stream, true, warn_if_no_files)
+ end
+
+ def parse_drb(args_copy, out_stream, error_stream, warn_if_no_files)
+ # Remove the --drb option
+ index = args_copy.index("-X") || args_copy.index("--drb")
+ args_copy.delete_at(index)
+
+ return DrbCommandLine.run(args_copy, error_stream, out_stream, true, warn_if_no_files)
+ end
+
+ def parse_version(out_stream)
+ out_stream.puts ::Spec::VERSION::DESCRIPTION
+ exit if out_stream == $stdout
+ end
+
+ def parse_help(opts, out_stream)
+ out_stream.puts opts
+ exit if out_stream == $stdout
+ end
+
+ def set_spec_from_line_number(options, args, err)
+ if options.examples.empty?
+ if args.length == 1
+ if @file_factory.file?(args[0])
+ source = @file_factory.open(args[0])
+ example = @spec_parser.spec_name_for(source, options.line_number)
+ options.parse_example(example)
+ elsif @file_factory.directory?(args[0])
+ err.puts "You must specify one file, not a directory when using the --line option"
+ exit(1) if err == $stderr
+ else
+ err.puts "#{args[0]} does not exist"
+ exit(2) if err == $stderr
+ end
+ else
+ err.puts "Only one file can be specified when using the --line option: #{args.inspect}"
+ exit(3) if err == $stderr
+ end
+ else
+ err.puts "You cannot use both --line and --example"
+ exit(4) if err == $stderr
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/options.rb b/vendor/plugins/rspec/lib/spec/runner/options.rb
new file mode 100644
index 000000000..a940133eb
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/options.rb
@@ -0,0 +1,175 @@
+module Spec
+ module Runner
+ class Options
+ BUILT_IN_FORMATTERS = {
+ 'specdoc' => Formatter::SpecdocFormatter,
+ 's' => Formatter::SpecdocFormatter,
+ 'html' => Formatter::HtmlFormatter,
+ 'h' => Formatter::HtmlFormatter,
+ 'rdoc' => Formatter::RdocFormatter,
+ 'r' => Formatter::RdocFormatter,
+ 'progress' => Formatter::ProgressBarFormatter,
+ 'p' => Formatter::ProgressBarFormatter,
+ 'failing_examples' => Formatter::FailingExamplesFormatter,
+ 'e' => Formatter::FailingExamplesFormatter,
+ 'failing_behaviours' => Formatter::FailingBehavioursFormatter,
+ 'b' => Formatter::FailingBehavioursFormatter
+ }
+
+ attr_accessor(
+ :backtrace_tweaker,
+ :colour,
+ :context_lines,
+ :diff_format,
+ :differ_class,
+ :dry_run,
+ :examples,
+ :failure_file,
+ :formatters,
+ :generate,
+ :heckle_runner,
+ :line_number,
+ :loadby,
+ :reporter,
+ :reverse,
+ :timeout,
+ :verbose,
+ :runner_arg,
+ :behaviour_runner
+ )
+
+ def initialize(err, out)
+ @err, @out = err, out
+ @backtrace_tweaker = QuietBacktraceTweaker.new
+ @examples = []
+ @formatters = []
+ @colour = false
+ @dry_run = false
+ end
+
+ def configure
+ configure_formatters
+ create_reporter
+ configure_differ
+ create_behaviour_runner
+ end
+
+ def create_behaviour_runner
+ return nil if @generate
+ @behaviour_runner = if @runner_arg
+ klass_name, arg = split_at_colon(@runner_arg)
+ runner_type = load_class(klass_name, 'behaviour runner', '--runner')
+ runner_type.new(self, arg)
+ else
+ BehaviourRunner.new(self)
+ end
+ end
+
+ def configure_formatters
+ @formatters.each do |formatter|
+ formatter.colour = @colour if formatter.respond_to?(:colour=)
+ formatter.dry_run = @dry_run if formatter.respond_to?(:dry_run=)
+ end
+ end
+
+ def create_reporter
+ @reporter = Reporter.new(@formatters, @backtrace_tweaker)
+ end
+
+ def configure_differ
+ if @differ_class
+ Spec::Expectations.differ = @differ_class.new(@diff_format, @context_lines, @colour)
+ end
+ end
+
+ def parse_diff(format)
+ @context_lines = 3
+ case format
+ when :context, 'context', 'c'
+ @diff_format = :context
+ when :unified, 'unified', 'u', '', nil
+ @diff_format = :unified
+ end
+
+ if [:context,:unified].include? @diff_format
+ require 'spec/expectations/differs/default'
+ @differ_class = Spec::Expectations::Differs::Default
+ else
+ @diff_format = :custom
+ @differ_class = load_class(format, 'differ', '--diff')
+ end
+ end
+
+ def parse_example(example)
+ if(File.file?(example))
+ @examples = File.open(example).read.split("\n")
+ else
+ @examples = [example]
+ end
+ end
+
+ def parse_format(format_arg)
+ format, where = split_at_colon(format_arg)
+ # This funky regexp checks whether we have a FILE_NAME or not
+ if where.nil?
+ raise "When using several --format options only one of them can be without a file" if @out_used
+ where = @out
+ @out_used = true
+ end
+
+ formatter_type = BUILT_IN_FORMATTERS[format] || load_class(format, 'formatter', '--format')
+ @formatters << formatter_type.new(where)
+ end
+
+ def parse_require(req)
+ req.split(",").each{|file| require file}
+ end
+
+ def parse_heckle(heckle)
+ heckle_require = [/mswin/, /java/].detect{|p| p =~ RUBY_PLATFORM} ? 'spec/runner/heckle_runner_unsupported' : 'spec/runner/heckle_runner'
+ require heckle_require
+ @heckle_runner = HeckleRunner.new(heckle)
+ end
+
+ def parse_generate_options(options_file, args_copy, out_stream)
+ # Remove the --generate-options option and the argument before writing to file
+ index = args_copy.index("-G") || args_copy.index("--generate-options")
+ args_copy.delete_at(index)
+ args_copy.delete_at(index)
+ File.open(options_file, 'w') do |io|
+ io.puts args_copy.join("\n")
+ end
+ out_stream.puts "\nOptions written to #{options_file}. You can now use these options with:"
+ out_stream.puts "spec --options #{options_file}"
+ @generate = true
+ end
+
+ def split_at_colon(s)
+ if s =~ /([a-zA-Z_]+(?:::[a-zA-Z_]+)*):?(.*)/
+ arg = $2 == "" ? nil : $2
+ [$1, arg]
+ else
+ raise "Couldn't parse #{s.inspect}"
+ end
+ end
+
+ def load_class(name, kind, option)
+ if name =~ /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/
+ arg = $2 == "" ? nil : $2
+ [$1, arg]
+ else
+ m = "#{name.inspect} is not a valid class name"
+ @err.puts m
+ raise m
+ end
+ begin
+ eval(name, binding, __FILE__, __LINE__)
+ rescue NameError => e
+ @err.puts "Couldn't find #{kind} class #{name}"
+ @err.puts "Make sure the --require option is specified *before* #{option}"
+ if $_spec_spec ; raise e ; else exit(1) ; end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/reporter.rb b/vendor/plugins/rspec/lib/spec/runner/reporter.rb
new file mode 100644
index 000000000..b1dc2a27a
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/reporter.rb
@@ -0,0 +1,125 @@
+module Spec
+ module Runner
+ class Reporter
+
+ def initialize(formatters, backtrace_tweaker)
+ @formatters = formatters
+ @backtrace_tweaker = backtrace_tweaker
+ clear!
+ end
+
+ def add_behaviour(name)
+ @formatters.each{|f| f.add_behaviour(name)}
+ @behaviour_names << name
+ end
+
+ def example_started(name)
+ @formatters.each{|f| f.example_started(name)}
+ end
+
+ def example_finished(name, error=nil, failure_location=nil, not_implemented = false)
+ @example_names << name
+
+ if not_implemented
+ example_pending(@behaviour_names.last, name)
+ elsif error.nil?
+ example_passed(name)
+ elsif Spec::DSL::ExamplePendingError === error
+ example_pending(@behaviour_names.last, name, error.message)
+ else
+ example_failed(name, error, failure_location)
+ end
+ end
+
+ def start(number_of_examples)
+ clear!
+ @start_time = Time.new
+ @formatters.each{|f| f.start(number_of_examples)}
+ end
+
+ def end
+ @end_time = Time.new
+ end
+
+ # Dumps the summary and returns the total number of failures
+ def dump
+ @formatters.each{|f| f.start_dump}
+ dump_failures
+ @formatters.each do |f|
+ f.dump_summary(duration, @example_names.length, @failures.length, @pending_count)
+ f.close
+ end
+ @failures.length
+ end
+
+ private
+
+ def clear!
+ @behaviour_names = []
+ @failures = []
+ @pending_count = 0
+ @example_names = []
+ @start_time = nil
+ @end_time = nil
+ end
+
+ def dump_failures
+ return if @failures.empty?
+ @failures.inject(1) do |index, failure|
+ @formatters.each{|f| f.dump_failure(index, failure)}
+ index + 1
+ end
+ end
+
+ def duration
+ return @end_time - @start_time unless (@end_time.nil? or @start_time.nil?)
+ return "0.0"
+ end
+
+ def example_passed(name)
+ @formatters.each{|f| f.example_passed(name)}
+ end
+
+ def example_failed(name, error, failure_location)
+ @backtrace_tweaker.tweak_backtrace(error, failure_location)
+ example_name = "#{@behaviour_names.last} #{name}"
+ failure = Failure.new(example_name, error)
+ @failures << failure
+ @formatters.each{|f| f.example_failed(name, @failures.length, failure)}
+ end
+
+ def example_pending(behaviour_name, example_name, message="Not Yet Implemented")
+ @pending_count += 1
+ @formatters.each{|f| f.example_pending(behaviour_name, example_name, message)}
+ end
+
+ class Failure
+ attr_reader :exception
+
+ def initialize(example_name, exception)
+ @example_name = example_name
+ @exception = exception
+ end
+
+ def header
+ if expectation_not_met?
+ "'#{@example_name}' FAILED"
+ elsif pending_fixed?
+ "'#{@example_name}' FIXED"
+ else
+ "#{@exception.class.name} in '#{@example_name}'"
+ end
+ end
+
+ def pending_fixed?
+ @exception.is_a?(Spec::DSL::PendingFixedError)
+ end
+
+ def expectation_not_met?
+ @exception.is_a?(Spec::Expectations::ExpectationNotMetError)
+ end
+
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/rspec/lib/spec/runner/spec_parser.rb b/vendor/plugins/rspec/lib/spec/runner/spec_parser.rb
new file mode 100644
index 000000000..bc9170065
--- /dev/null
+++ b/vendor/plugins/rspec/lib/spec/runner/spec_parser.rb
@@ -0,0 +1,50 @@
+module Spec
+ module Runner
+ # Parses a spec file and finds the nearest example for a given line number.
+ class SpecParser
+ def spec_name_for(io, line_number)
+ source = io.read
+ behaviour, behaviour_line = behaviour_at_line(source, line_number)
+ example, example_line = example_at_line(source, line_number)
+ if behaviour && example && (behaviour_line < example_line)
+ "#{behaviour} #{example}"
+ elsif behaviour
+ behaviour
+ else
+ nil
+ end
+ end
+
+ protected
+
+ def behaviour_at_line(source, line_number)
+ find_above(source, line_number, /^\s*(context|describe)\s+(.*)\s+do/)
+ end
+
+ def example_at_line(source, line_number)
+ find_above(source, line_number, /^\s*(specify|it)\s+(.*)\s+do/)
+ end
+
+ # Returns the context/describe or specify/it name and the line number
+ def find_above(source, line_number, pattern)
+ lines_above_reversed(source, line_number).each_with_index do |line, n|
+ return [parse_description($2), line_number-n] if line =~ pattern
+ end
+ nil
+ end
+
+ def lines_above_reversed(source, line_number)
+ lines = source.split("\n")
+ lines[0...line_number].reverse
+ end
+
+ def parse_description(str)
+ return str[1..-2] if str =~ /^['"].*['"]$/
+ if matches = /^(.*)\s*,\s*['"](.*)['"]$/.match(str)
+ return ::Spec::DSL::Description.generate_description(matches[1], matches[2])
+ end
+ return str
+ end
+ end
+ end
+end