changelog shortlog tags changeset manifest revisions annotate raw

vendor/plugins/rspec/lib/spec/runner/options.rb

changeset 15: 64acf98d15f4
author: moriq@moriq.com
date: Mon Mar 10 10:12:58 2008 +0900 (16 years ago)
permissions: -rw-r--r--
description: add plugins rspec
1module Spec
2 module Runner
3 class Options
4 FILE_SORTERS = {
5 'mtime' => lambda {|file_a, file_b| File.mtime(file_b) <=> File.mtime(file_a)}
6 }
7
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']
22 }
23
24 STORY_FORMATTERS = {
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']
29 }
30
31 attr_accessor(
32 :filename_pattern,
33 :backtrace_tweaker,
34 :context_lines,
35 :diff_format,
36 :dry_run,
37 :profile,
38 :examples,
39 :heckle_runner,
40 :line_number,
41 :loadby,
42 :reporter,
43 :reverse,
44 :timeout,
45 :verbose,
46 :user_input_for_runner,
47 :error_stream,
48 :output_stream,
49 # TODO: BT - Figure out a better name
50 :argv
51 )
52 attr_reader :colour, :differ_class, :files, :example_groups
53
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
59 @examples = []
60 @colour = false
61 @profile = false
62 @dry_run = false
63 @reporter = Reporter.new(self)
64 @context_lines = 3
65 @diff_format = :unified
66 @files = []
67 @example_groups = []
68 @examples_run = false
69 @examples_should_be_run = nil
70 @user_input_for_runner = nil
71 end
72
73 def add_example_group(example_group)
74 @example_groups << example_group
75 end
76
77 def remove_example_group(example_group)
78 @example_groups.delete(example_group)
79 end
80
81 def run_examples
82 return true unless examples_should_be_run?
83 runner = custom_runner || ExampleGroupRunner.new(self)
84
85 runner.load_files(files_to_load)
86 if example_groups.empty?
87 true
88 else
89 set_spec_from_line_number if line_number
90 success = runner.run
91 @examples_run = true
92 heckle if heckle_runner
93 success
94 end
95 end
96
97 def examples_run?
98 @examples_run
99 end
100
101 def examples_should_not_be_run
102 @examples_should_be_run = false
103 end
104
105 def colour=(colour)
106 @colour = colour
107 if @colour && RUBY_PLATFORM =~ /win32/ ;\
108 begin ;\
109 require 'rubygems' ;\
110 require 'Win32/Console/ANSI' ;\
111 rescue LoadError ;\
112 warn "You must 'gem install win32console' to use colour on Windows" ;\
113 @colour = false ;\
114 end
115 end
116 end
117
118 def parse_diff(format)
119 case format
120 when :context, 'context', 'c'
121 @diff_format = :context
122 default_differ
123 when :unified, 'unified', 'u', '', nil
124 @diff_format = :unified
125 default_differ
126 else
127 @diff_format = :custom
128 self.differ_class = load_class(format, 'differ', '--diff')
129 end
130 end
131
132 def parse_example(example)
133 if(File.file?(example))
134 @examples = File.open(example).read.split("\n")
135 else
136 @examples = [example]
137 end
138 end
139
140 def parse_format(format_arg)
141 format, where = ClassAndArgumentsParser.parse(format_arg)
142 unless where
143 raise "When using several --format options only one of them can be without a file" if @out_used
144 where = @output_stream
145 @out_used = true
146 end
147 @format_options ||= []
148 @format_options << [format, where]
149 end
150
151 def formatters
152 @format_options ||= [['progress', @output_stream]]
153 @formatters ||= load_formatters(@format_options, EXAMPLE_FORMATTERS)
154 end
155
156 def story_formatters
157 @format_options ||= [['plain', @output_stream]]
158 @formatters ||= load_formatters(@format_options, STORY_FORMATTERS)
159 end
160
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__)
166 else
167 load_class(format, 'formatter', '--format')
168 end
169 formatter_type.new(self, where)
170 end
171 end
172
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)
177 end
178
179 def number_of_examples
180 @example_groups.inject(0) do |sum, example_group|
181 sum + example_group.number_of_examples
182 end
183 end
184
185 def files_to_load
186 result = []
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}")]
191 end
192 elsif File.file?(file)
193 result << file
194 else
195 raise "File or directory not found: #{file}"
196 end
197 end
198 result
199 end
200
201 protected
202 def examples_should_be_run?
203 return @examples_should_be_run unless @examples_should_be_run.nil?
204 @examples_should_be_run = true
205 end
206
207 def differ_class=(klass)
208 return unless klass
209 @differ_class = klass
210 Spec::Expectations.differ = self.differ_class.new(self)
211 end
212
213 def load_class(name, kind, option)
214 if name =~ /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/
215 arg = $2 == "" ? nil : $2
216 [$1, arg]
217 else
218 m = "#{name.inspect} is not a valid class name"
219 @error_stream.puts m
220 raise m
221 end
222 begin
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
228 end
229 end
230
231 def custom_runner
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)
236 end
237
238 def custom_runner?
239 return user_input_for_runner ? true : false
240 end
241
242 def heckle
243 returns = self.heckle_runner.heckle_with
244 self.heckle_runner = nil
245 returns
246 end
247
248 def sorted_files
249 return sorter ? files.sort(&sorter) : files
250 end
251
252 def sorter
253 FILE_SORTERS[loadby]
254 end
255
256 def default_differ
257 require 'spec/expectations/differs/default'
258 self.differ_class = Spec::Expectations::Differs::Default
259 end
260
261 def set_spec_from_line_number
262 if examples.empty?
263 if files.length == 1
264 if File.directory?(files[0])
265 error_stream.puts "You must specify one file, not a directory when using the --line option"
266 exit(1) if stderr?
267 else
268 example = SpecParser.new.spec_name_for(files[0], line_number)
269 @examples = [example]
270 end
271 else
272 error_stream.puts "Only one file can be specified when using the --line option: #{files.inspect}"
273 exit(3) if stderr?
274 end
275 else
276 error_stream.puts "You cannot use both --line and --example"
277 exit(4) if stderr?
278 end
279 end
280
281 def stderr?
282 @error_stream == $stderr
283 end
284 end
285 end
286end