Upgraded Rails and RSpec
[monkeycharger.git] / vendor / plugins / rspec / rspec / lib / spec / runner / options.rb
blob0beb5c3b5a1d3c5d062a7a5a13d33bdf441c499f
1 module 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       }
8       EXAMPLE_FORMATTERS = {
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,
22       }
24       STORY_FORMATTERS = {
25         'plain' => Formatter::Story::PlainTextFormatter,
26         'html'  => Formatter::Story::HtmlFormatter,
27         'h'     => Formatter::Story::HtmlFormatter
28       }
30       attr_accessor(
31         :backtrace_tweaker,
32         :context_lines,
33         :diff_format,
34         :dry_run,
35         :profile,
36         :examples,
37         :heckle_runner,
38         :line_number,
39         :loadby,
40         :reporter,
41         :reverse,
42         :timeout,
43         :verbose,
44         :user_input_for_runner,
45         :error_stream,
46         :output_stream,
47         # TODO: BT - Figure out a better name
48         :argv
49       )
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
56         @examples = []
57         @colour = false
58         @profile = false
59         @dry_run = false
60         @reporter = Reporter.new(self)
61         @context_lines = 3
62         @diff_format  = :unified
63         @files = []
64         @example_groups = []
65         @user_input_for_runner = nil
66         @examples_run = false
67       end
69       def add_example_group(example_group)
70         @example_groups << example_group
71       end
73       def remove_example_group(example_group)
74         @example_groups.delete(example_group)
75       end
77       def run_examples
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?
83           true
84         else
85           success = runner.run
86           @examples_run = true
87           heckle if heckle_runner
88           success
89         end
90       end
92       def examples_run?
93         @examples_run
94       end
96       def examples_should_not_be_run
97         @examples_should_be_run = false
98       end      
100       def colour=(colour)
101         @colour = colour
102         begin; \
103           require 'Win32/Console/ANSI' if @colour && PLATFORM =~ /win32/; \
104         rescue LoadError ; \
105           raise "You must gem install win32console to use colour on Windows" ; \
106         end
107       end
109       def parse_diff(format)
110         case format
111         when :context, 'context', 'c'
112           @diff_format  = :context
113           default_differ
114         when :unified, 'unified', 'u', '', nil
115           @diff_format  = :unified
116           default_differ
117         else
118           @diff_format  = :custom
119           self.differ_class = load_class(format, 'differ', '--diff')
120         end
121       end
123       def parse_example(example)
124         if(File.file?(example))
125           @examples = File.open(example).read.split("\n")
126         else
127           @examples = [example]
128         end
129       end
131       def parse_format(format_arg)
132         format, where = ClassAndArgumentsParser.parse(format_arg)
133         unless where
134           raise "When using several --format options only one of them can be without a file" if @out_used
135           where = @output_stream
136           @out_used = true
137         end
138         @format_options ||= []
139         @format_options << [format, where]
140       end
141       
142       def formatters
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)
147         end
148       end
150       def story_formatters
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)
155         end
156       end
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)
162       end
164       def number_of_examples
165         @example_groups.inject(0) do |sum, example_group|
166           sum + example_group.number_of_examples
167         end
168       end
170       protected
171       def examples_should_be_run?
172         return @examples_should_be_run unless @examples_should_be_run.nil?
173         @examples_should_be_run = true
174       end
175       
176       def differ_class=(klass)
177         return unless klass
178         @differ_class = klass
179         Spec::Expectations.differ = self.differ_class.new(self)
180       end
182       def load_class(name, kind, option)
183         if name =~ /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/
184           arg = $2 == "" ? nil : $2
185           [$1, arg]
186         else
187           m = "#{name.inspect} is not a valid class name"
188           @error_stream.puts m
189           raise m
190         end
191         begin
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
197         end
198       end
199       
200       def files_to_load
201         result = []
202         sorted_files.each do |file|
203           if test ?d, file
204             result += Dir[File.expand_path("#{file}/**/*.rb")]
205           elsif test ?f, file
206             result << file
207           else
208             raise "File or directory not found: #{file}"
209           end
210         end
211         result
212       end
213       
214       def custom_runner
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)
219       end
221       def custom_runner?
222         return user_input_for_runner ? true : false
223       end
224       
225       def heckle
226         returns = self.heckle_runner.heckle_with
227         self.heckle_runner = nil
228         returns
229       end
230       
231       def sorted_files
232         return sorter ? files.sort(&sorter) : files
233       end
235       def sorter
236         FILE_SORTERS[loadby]
237       end
239       def default_differ
240         require 'spec/expectations/differs/default'
241         self.differ_class = Spec::Expectations::Differs::Default
242       end
243     end
244   end