5 'mtime' => lambda {|file_a, file_b| File.mtime(file_b) <=> File.mtime(file_a)}
9 'specdoc' => Formatter::SpecdocFormatter,
10 's' => Formatter::SpecdocFormatter,
11 'html' => Formatter::HtmlFormatter,
12 'h' => Formatter::HtmlFormatter,
13 'progress' => Formatter::ProgressBarFormatter,
14 'p' => Formatter::ProgressBarFormatter,
15 'failing_examples' => Formatter::FailingExamplesFormatter,
16 'e' => Formatter::FailingExamplesFormatter,
17 'failing_behaviours' => Formatter::FailingBehavioursFormatter,
18 'b' => Formatter::FailingBehavioursFormatter,
19 'profile' => Formatter::ProfileFormatter,
20 'o' => Formatter::ProfileFormatter,
21 'textmate' => Formatter::TextMateFormatter,
25 'plain' => Formatter::Story::PlainTextFormatter,
26 'html' => Formatter::Story::HtmlFormatter,
27 'h' => Formatter::Story::HtmlFormatter
44 :user_input_for_runner,
47 # TODO: BT - Figure out a better name
50 attr_reader :colour, :differ_class, :files, :example_groups
52 def initialize(error_stream, output_stream)
53 @error_stream = error_stream
54 @output_stream = output_stream
55 @backtrace_tweaker = QuietBacktraceTweaker.new
60 @reporter = Reporter.new(self)
62 @diff_format = :unified
65 @user_input_for_runner = nil
69 def add_example_group(example_group)
70 @example_groups << example_group
73 def remove_example_group(example_group)
74 @example_groups.delete(example_group)
78 return true unless examples_should_be_run?
79 runner = custom_runner || ExampleGroupRunner.new(self)
81 runner.load_files(files_to_load)
82 if example_groups.empty?
87 heckle if heckle_runner
96 def examples_should_not_be_run
97 @examples_should_be_run = false
103 require 'Win32/Console/ANSI' if @colour && PLATFORM =~ /win32/; \
105 raise "You must gem install win32console to use colour on Windows" ; \
109 def parse_diff(format)
111 when :context, 'context', 'c'
112 @diff_format = :context
114 when :unified, 'unified', 'u', '', nil
115 @diff_format = :unified
118 @diff_format = :custom
119 self.differ_class = load_class(format, 'differ', '--diff')
123 def parse_example(example)
124 if(File.file?(example))
125 @examples = File.open(example).read.split("\n")
127 @examples = [example]
131 def parse_format(format_arg)
132 format, where = ClassAndArgumentsParser.parse(format_arg)
134 raise "When using several --format options only one of them can be without a file" if @out_used
135 where = @output_stream
138 @format_options ||= []
139 @format_options << [format, where]
143 @format_options ||= [['progress', @output_stream]]
144 @formatters ||= @format_options.map do |format, where|
145 formatter_type = EXAMPLE_FORMATTERS[format] || load_class(format, 'formatter', '--format')
146 formatter_type.new(self, where)
151 @format_options ||= [['plain', @output_stream]]
152 @story_formatters ||= @format_options.map do |format, where|
153 formatter_type = STORY_FORMATTERS[format] || load_class(format, 'formatter', '--format')
154 formatter_type.new(self, where)
158 def load_heckle_runner(heckle)
159 suffix = [/mswin/, /java/].detect{|p| p =~ RUBY_PLATFORM} ? '_unsupported' : ''
160 require "spec/runner/heckle_runner#{suffix}"
161 @heckle_runner = HeckleRunner.new(heckle)
164 def number_of_examples
165 @example_groups.inject(0) do |sum, example_group|
166 sum + example_group.number_of_examples
171 def examples_should_be_run?
172 return @examples_should_be_run unless @examples_should_be_run.nil?
173 @examples_should_be_run = true
176 def differ_class=(klass)
178 @differ_class = klass
179 Spec::Expectations.differ = self.differ_class.new(self)
182 def load_class(name, kind, option)
183 if name =~ /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/
184 arg = $2 == "" ? nil : $2
187 m = "#{name.inspect} is not a valid class name"
192 eval(name, binding, __FILE__, __LINE__)
193 rescue NameError => e
194 @error_stream.puts "Couldn't find #{kind} class #{name}"
195 @error_stream.puts "Make sure the --require option is specified *before* #{option}"
196 if $_spec_spec ; raise e ; else exit(1) ; end
202 sorted_files.each do |file|
204 result += Dir[File.expand_path("#{file}/**/*.rb")]
208 raise "File or directory not found: #{file}"
215 return nil unless custom_runner?
216 klass_name, arg = ClassAndArgumentsParser.parse(user_input_for_runner)
217 runner_type = load_class(klass_name, 'behaviour runner', '--runner')
218 return runner_type.new(self, arg)
222 return user_input_for_runner ? true : false
226 returns = self.heckle_runner.heckle_with
227 self.heckle_runner = nil
232 return sorter ? files.sort(&sorter) : files
240 require 'spec/expectations/differs/default'
241 self.differ_class = Spec::Expectations::Differs::Default