5
'mtime' => lambda {|file_a, file_b| File.mtime(file_b) <=> File.mtime(file_a)}
8
EXAMPLE_FORMATTERS = { # Load these lazily for better speed
9
'specdoc' => ['spec/runner/formatter/specdoc_formatter', 'Formatter::SpecdocFormatter'],
10
's' => ['spec/runner/formatter/specdoc_formatter', 'Formatter::SpecdocFormatter'],
11
'html' => ['spec/runner/formatter/html_formatter', 'Formatter::HtmlFormatter'],
12
'h' => ['spec/runner/formatter/html_formatter', 'Formatter::HtmlFormatter'],
13
'progress' => ['spec/runner/formatter/progress_bar_formatter', 'Formatter::ProgressBarFormatter'],
14
'p' => ['spec/runner/formatter/progress_bar_formatter', 'Formatter::ProgressBarFormatter'],
15
'failing_examples' => ['spec/runner/formatter/failing_examples_formatter', 'Formatter::FailingExamplesFormatter'],
16
'e' => ['spec/runner/formatter/failing_examples_formatter', 'Formatter::FailingExamplesFormatter'],
17
'failing_example_groups' => ['spec/runner/formatter/failing_example_groups_formatter', 'Formatter::FailingExampleGroupsFormatter'],
18
'g' => ['spec/runner/formatter/failing_example_groups_formatter', 'Formatter::FailingExampleGroupsFormatter'],
19
'profile' => ['spec/runner/formatter/profile_formatter', 'Formatter::ProfileFormatter'],
20
'o' => ['spec/runner/formatter/profile_formatter', 'Formatter::ProfileFormatter'],
21
'textmate' => ['spec/runner/formatter/text_mate_formatter', 'Formatter::TextMateFormatter']
25
'plain' => ['spec/runner/formatter/story/plain_text_formatter', 'Formatter::Story::PlainTextFormatter'],
26
'p' => ['spec/runner/formatter/story/plain_text_formatter', 'Formatter::Story::PlainTextFormatter'],
27
'html' => ['spec/runner/formatter/story/html_formatter', 'Formatter::Story::HtmlFormatter'],
28
'h' => ['spec/runner/formatter/story/html_formatter', 'Formatter::Story::HtmlFormatter']
46
:user_input_for_runner,
49
# TODO: BT - Figure out a better name
52
attr_reader :colour, :differ_class, :files, :example_groups
54
def initialize(error_stream, output_stream)
55
@error_stream = error_stream
56
@output_stream = output_stream
57
@filename_pattern = "**/*_spec.rb"
58
@backtrace_tweaker = QuietBacktraceTweaker.new
63
@reporter = Reporter.new(self)
65
@diff_format = :unified
69
@examples_should_be_run = nil
70
@user_input_for_runner = nil
73
def add_example_group(example_group)
74
@example_groups << example_group
77
def remove_example_group(example_group)
78
@example_groups.delete(example_group)
82
return true unless examples_should_be_run?
83
runner = custom_runner || ExampleGroupRunner.new(self)
85
runner.load_files(files_to_load)
86
if example_groups.empty?
89
set_spec_from_line_number if line_number
92
heckle if heckle_runner
101
def examples_should_not_be_run
102
@examples_should_be_run = false
107
if @colour && RUBY_PLATFORM =~ /win32/ ;\
109
require 'rubygems' ;\
110
require 'Win32/Console/ANSI' ;\
112
warn "You must 'gem install win32console' to use colour on Windows" ;\
118
def parse_diff(format)
120
when :context, 'context', 'c'
121
@diff_format = :context
123
when :unified, 'unified', 'u', '', nil
124
@diff_format = :unified
127
@diff_format = :custom
128
self.differ_class = load_class(format, 'differ', '--diff')
132
def parse_example(example)
133
if(File.file?(example))
134
@examples = File.open(example).read.split("\n")
136
@examples = [example]
140
def parse_format(format_arg)
141
format, where = ClassAndArgumentsParser.parse(format_arg)
143
raise "When using several --format options only one of them can be without a file" if @out_used
144
where = @output_stream
147
@format_options ||= []
148
@format_options << [format, where]
152
@format_options ||= [['progress', @output_stream]]
153
@formatters ||= load_formatters(@format_options, EXAMPLE_FORMATTERS)
157
@format_options ||= [['plain', @output_stream]]
158
@formatters ||= load_formatters(@format_options, STORY_FORMATTERS)
161
def load_formatters(format_options, formatters)
162
format_options.map do |format, where|
163
formatter_type = if formatters[format]
164
require formatters[format][0]
165
eval(formatters[format][1], binding, __FILE__, __LINE__)
167
load_class(format, 'formatter', '--format')
169
formatter_type.new(self, where)
173
def load_heckle_runner(heckle)
174
suffix = [/mswin/, /java/].detect{|p| p =~ RUBY_PLATFORM} ? '_unsupported' : ''
175
require "spec/runner/heckle_runner#{suffix}"
176
@heckle_runner = HeckleRunner.new(heckle)
179
def number_of_examples
180
@example_groups.inject(0) do |sum, example_group|
181
sum + example_group.number_of_examples
187
sorted_files.each do |file|
188
if File.directory?(file)
189
filename_pattern.split(",").each do |pattern|
190
result += Dir[File.expand_path("#{file}/#{pattern.strip}")]
192
elsif File.file?(file)
195
raise "File or directory not found: #{file}"
202
def examples_should_be_run?
203
return @examples_should_be_run unless @examples_should_be_run.nil?
204
@examples_should_be_run = true
207
def differ_class=(klass)
209
@differ_class = klass
210
Spec::Expectations.differ = self.differ_class.new(self)
213
def load_class(name, kind, option)
214
if name =~ /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/
215
arg = $2 == "" ? nil : $2
218
m = "#{name.inspect} is not a valid class name"
223
eval(name, binding, __FILE__, __LINE__)
224
rescue NameError => e
225
@error_stream.puts "Couldn't find #{kind} class #{name}"
226
@error_stream.puts "Make sure the --require option is specified *before* #{option}"
227
if $_spec_spec ; raise e ; else exit(1) ; end
232
return nil unless custom_runner?
233
klass_name, arg = ClassAndArgumentsParser.parse(user_input_for_runner)
234
runner_type = load_class(klass_name, 'behaviour runner', '--runner')
235
return runner_type.new(self, arg)
239
return user_input_for_runner ? true : false
243
returns = self.heckle_runner.heckle_with
244
self.heckle_runner = nil
249
return sorter ? files.sort(&sorter) : files
257
require 'spec/expectations/differs/default'
258
self.differ_class = Spec::Expectations::Differs::Default
261
def set_spec_from_line_number
264
if File.directory?(files[0])
265
error_stream.puts "You must specify one file, not a directory when using the --line option"
268
example = SpecParser.new.spec_name_for(files[0], line_number)
269
@examples = [example]
272
error_stream.puts "Only one file can be specified when using the --line option: #{files.inspect}"
276
error_stream.puts "You cannot use both --line and --example"
282
@error_stream == $stderr