rspec 0.7.5.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (194) hide show
  1. data/CHANGES +60 -1
  2. data/EXAMPLES.rd +38 -19
  3. data/MIT-LICENSE +1 -1
  4. data/README +24 -17
  5. data/RELEASE-PLAN +117 -0
  6. data/Rakefile +24 -18
  7. data/TODO.0.8.0 +5 -0
  8. data/examples/auto_spec_name_generation_example.rb +18 -0
  9. data/examples/custom_expectation_matchers.rb +53 -0
  10. data/examples/dynamic_spec.rb +9 -0
  11. data/examples/io_processor_spec.rb +2 -2
  12. data/examples/mocking_example.rb +4 -4
  13. data/examples/partial_mock_example.rb +2 -2
  14. data/examples/predicate_example.rb +2 -2
  15. data/examples/stack_spec.rb +32 -36
  16. data/examples/stubbing_example.rb +19 -19
  17. data/examples/test_case_spec.rb +6 -6
  18. data/lib/spec.rb +3 -0
  19. data/lib/spec/callback.rb +8 -0
  20. data/lib/spec/callback/extensions/object.rb +4 -0
  21. data/lib/spec/deprecated.rb +3 -0
  22. data/lib/spec/expectations.rb +44 -17
  23. data/lib/spec/expectations/extensions.rb +1 -2
  24. data/lib/spec/expectations/extensions/object.rb +78 -130
  25. data/lib/spec/expectations/extensions/string_and_symbol.rb +17 -0
  26. data/lib/spec/expectations/handler.rb +47 -0
  27. data/lib/spec/expectations/should/base.rb +32 -29
  28. data/lib/spec/expectations/should/change.rb +1 -1
  29. data/lib/spec/expectations/should/have.rb +9 -17
  30. data/lib/spec/expectations/should/not.rb +54 -56
  31. data/lib/spec/expectations/should/should.rb +59 -65
  32. data/lib/spec/expectations/sugar.rb +27 -4
  33. data/lib/spec/matchers.rb +160 -0
  34. data/lib/spec/matchers/be.rb +161 -0
  35. data/lib/spec/matchers/be_close.rb +37 -0
  36. data/lib/spec/matchers/change.rb +120 -0
  37. data/lib/spec/matchers/eql.rb +43 -0
  38. data/lib/spec/matchers/equal.rb +43 -0
  39. data/lib/spec/matchers/has.rb +44 -0
  40. data/lib/spec/matchers/have.rb +140 -0
  41. data/lib/spec/matchers/include.rb +50 -0
  42. data/lib/spec/matchers/match.rb +41 -0
  43. data/lib/spec/matchers/raise_error.rb +100 -0
  44. data/lib/spec/matchers/respond_to.rb +35 -0
  45. data/lib/spec/matchers/satisfy.rb +47 -0
  46. data/lib/spec/matchers/throw_symbol.rb +75 -0
  47. data/lib/spec/mocks.rb +224 -1
  48. data/lib/spec/mocks/argument_expectation.rb +16 -2
  49. data/lib/spec/mocks/error_generator.rb +5 -3
  50. data/lib/spec/mocks/errors.rb +2 -2
  51. data/lib/spec/mocks/extensions/object.rb +1 -1
  52. data/lib/spec/mocks/message_expectation.rb +29 -19
  53. data/lib/spec/mocks/{mock_methods.rb → methods.rb} +5 -5
  54. data/lib/spec/mocks/mock.rb +2 -2
  55. data/lib/spec/mocks/mock_handler.rb +81 -68
  56. data/lib/spec/rake/spectask.rb +7 -12
  57. data/lib/spec/rake/verify_rcov.rb +1 -1
  58. data/lib/spec/runner.rb +117 -0
  59. data/lib/spec/runner/command_line.rb +8 -5
  60. data/lib/spec/runner/context.rb +13 -37
  61. data/lib/spec/runner/context_eval.rb +4 -3
  62. data/lib/spec/runner/context_runner.rb +7 -4
  63. data/lib/spec/runner/drb_command_line.rb +1 -1
  64. data/lib/spec/runner/execution_context.rb +3 -11
  65. data/lib/spec/runner/extensions/kernel.rb +7 -5
  66. data/lib/spec/runner/extensions/object.rb +4 -1
  67. data/lib/spec/runner/formatter/base_text_formatter.rb +11 -3
  68. data/lib/spec/runner/formatter/html_formatter.rb +21 -10
  69. data/lib/spec/runner/heckle_runner.rb +24 -8
  70. data/lib/spec/runner/heckle_runner_win.rb +10 -0
  71. data/lib/spec/runner/option_parser.rb +58 -13
  72. data/lib/spec/runner/spec_matcher.rb +22 -29
  73. data/lib/spec/runner/spec_parser.rb +1 -0
  74. data/lib/spec/runner/specification.rb +36 -22
  75. data/lib/spec/translator.rb +87 -0
  76. data/lib/spec/version.rb +16 -7
  77. data/spec/spec/callback/callback_container_spec.rb +27 -0
  78. data/spec/spec/callback/module_spec.rb +37 -0
  79. data/spec/spec/callback/object_spec.rb +90 -0
  80. data/spec/spec/callback/object_with_class_callback_spec.rb +19 -0
  81. data/spec/spec/expectations/differs/default_spec.rb +107 -0
  82. data/spec/spec/expectations/extensions/object_spec.rb +46 -0
  83. data/spec/spec/expectations/fail_with_spec.rb +71 -0
  84. data/spec/spec/expectations/should/should_==_spec.rb +19 -0
  85. data/spec/spec/expectations/should/should_=~_spec.rb +13 -0
  86. data/spec/spec/expectations/should/should_be_a_kind_of_spec.rb +21 -0
  87. data/spec/spec/expectations/should/should_be_an_instance_of_spec.rb +30 -0
  88. data/spec/spec/expectations/should/should_be_arbitrary_predicate_spec.rb +81 -0
  89. data/spec/spec/expectations/should/should_be_close_spec.rb +18 -0
  90. data/spec/spec/expectations/should/should_be_comparison_operator_spec.rb +44 -0
  91. data/spec/spec/expectations/should/should_be_false_spec.rb +39 -0
  92. data/spec/spec/expectations/should/should_be_spec.rb +11 -0
  93. data/spec/spec/expectations/should/should_be_true_spec.rb +27 -0
  94. data/spec/spec/expectations/should/should_change_spec.rb +184 -0
  95. data/spec/spec/expectations/should/should_eql_spec.rb +11 -0
  96. data/spec/spec/expectations/should/should_equal_spec.rb +11 -0
  97. data/spec/spec/expectations/should/should_have_at_least_spec.rb +53 -0
  98. data/spec/spec/expectations/should/should_have_at_most_spec.rb +45 -0
  99. data/spec/spec/expectations/should/should_have_key_spec.rb +21 -0
  100. data/spec/spec/expectations/should/should_have_spec.rb +64 -0
  101. data/spec/spec/expectations/should/should_include_spec.rb +59 -0
  102. data/spec/spec/expectations/should/should_match_spec.rb +25 -0
  103. data/spec/spec/expectations/should/should_not_==_spec.rb +15 -0
  104. data/spec/spec/expectations/should/should_not_be_a_kind_of_spec.rb +21 -0
  105. data/spec/spec/expectations/should/should_not_be_an_instance_of_spec.rb +11 -0
  106. data/spec/spec/expectations/should/should_not_be_arbitrary_predicate_spec.rb +68 -0
  107. data/spec/spec/expectations/should/should_not_be_spec.rb +11 -0
  108. data/spec/spec/expectations/should/should_not_change_spec.rb +24 -0
  109. data/spec/spec/expectations/should/should_not_eql_spec.rb +11 -0
  110. data/spec/spec/expectations/should/should_not_equal_spec.rb +11 -0
  111. data/spec/spec/expectations/should/should_not_have_key_spec.rb +15 -0
  112. data/spec/spec/expectations/should/should_not_include_spec.rb +58 -0
  113. data/spec/spec/expectations/should/should_not_match_spec.rb +11 -0
  114. data/spec/spec/expectations/should/should_not_raise_spec.rb +75 -0
  115. data/spec/spec/expectations/should/should_not_respond_to_spec.rb +15 -0
  116. data/spec/spec/expectations/should/should_not_throw_spec.rb +35 -0
  117. data/spec/spec/expectations/should/should_raise_spec.rb +66 -0
  118. data/spec/spec/expectations/should/should_respond_to_spec.rb +15 -0
  119. data/spec/spec/expectations/should/should_satisfy_spec.rb +35 -0
  120. data/spec/spec/expectations/should/should_throw_spec.rb +27 -0
  121. data/spec/spec/matchers/be_close_spec.rb +33 -0
  122. data/spec/spec/matchers/be_spec.rb +182 -0
  123. data/spec/spec/matchers/change_spec.rb +232 -0
  124. data/spec/spec/matchers/description_generation_spec.rb +147 -0
  125. data/spec/spec/matchers/eql_spec.rb +41 -0
  126. data/spec/spec/matchers/equal_spec.rb +41 -0
  127. data/spec/spec/matchers/handler_spec.rb +75 -0
  128. data/spec/spec/matchers/has_spec.rb +37 -0
  129. data/spec/spec/matchers/have_spec.rb +259 -0
  130. data/spec/spec/matchers/include_spec.rb +33 -0
  131. data/spec/spec/matchers/match_spec.rb +37 -0
  132. data/spec/spec/matchers/matcher_methods_spec.rb +85 -0
  133. data/spec/spec/matchers/raise_error_spec.rb +147 -0
  134. data/spec/spec/matchers/respond_to_spec.rb +30 -0
  135. data/spec/spec/matchers/satisfy_spec.rb +36 -0
  136. data/spec/spec/matchers/throw_symbol_spec.rb +59 -0
  137. data/spec/spec/mocks/any_number_of_times_spec.rb +34 -0
  138. data/spec/spec/mocks/at_least_spec.rb +97 -0
  139. data/spec/spec/mocks/at_most_spec.rb +97 -0
  140. data/spec/spec/mocks/bug_report_7611_spec.rb +19 -0
  141. data/spec/spec/mocks/bug_report_7805_spec.rb +22 -0
  142. data/spec/spec/mocks/bug_report_8165_spec.rb +31 -0
  143. data/spec/spec/mocks/bug_report_8302_spec.rb +26 -0
  144. data/spec/spec/mocks/failing_mock_argument_constraints_spec.rb +74 -0
  145. data/spec/spec/mocks/mock_ordering_spec.rb +80 -0
  146. data/spec/spec/mocks/mock_spec.rb +407 -0
  147. data/spec/spec/mocks/multiple_return_value_spec.rb +113 -0
  148. data/spec/spec/mocks/null_object_mock_spec.rb +40 -0
  149. data/spec/spec/mocks/once_counts_spec.rb +56 -0
  150. data/spec/spec/mocks/options_hash_spec.rb +31 -0
  151. data/spec/spec/mocks/partial_mock_spec.rb +52 -0
  152. data/spec/spec/mocks/partial_mock_using_mocks_directly_spec.rb +64 -0
  153. data/spec/spec/mocks/passing_mock_argument_constraints_spec.rb +92 -0
  154. data/spec/spec/mocks/precise_counts_spec.rb +56 -0
  155. data/spec/spec/mocks/record_messages_spec.rb +26 -0
  156. data/spec/spec/mocks/stub_spec.rb +159 -0
  157. data/spec/spec/mocks/twice_counts_spec.rb +67 -0
  158. data/spec/spec/runner/command_line_spec.rb +32 -0
  159. data/spec/spec/runner/context_matching_spec.rb +28 -0
  160. data/spec/spec/runner/context_runner_spec.rb +100 -0
  161. data/spec/spec/runner/context_spec.rb +405 -0
  162. data/spec/spec/runner/drb_command_line_spec.rb +74 -0
  163. data/spec/spec/runner/execution_context_spec.rb +52 -0
  164. data/spec/spec/runner/formatter/html_formatter_spec.rb +40 -0
  165. data/spec/spec/runner/formatter/progress_bar_formatter_dry_run_spec.rb +21 -0
  166. data/spec/spec/runner/formatter/progress_bar_formatter_failure_dump_spec.rb +36 -0
  167. data/spec/spec/runner/formatter/progress_bar_formatter_spec.rb +78 -0
  168. data/spec/spec/runner/formatter/rdoc_formatter_dry_run_spec.rb +18 -0
  169. data/spec/spec/runner/formatter/rdoc_formatter_spec.rb +41 -0
  170. data/spec/spec/runner/formatter/specdoc_formatter_dry_run_spec.rb +21 -0
  171. data/spec/spec/runner/formatter/specdoc_formatter_spec.rb +46 -0
  172. data/spec/spec/runner/heckle_runner_spec.rb +63 -0
  173. data/spec/spec/runner/heckler_spec.rb +14 -0
  174. data/spec/spec/runner/kernel_ext_spec.rb +16 -0
  175. data/spec/spec/runner/noisy_backtrace_tweaker_spec.rb +45 -0
  176. data/spec/spec/runner/object_ext_spec.rb +11 -0
  177. data/spec/spec/runner/option_parser_spec.rb +269 -0
  178. data/spec/spec/runner/quiet_backtrace_tweaker_spec.rb +47 -0
  179. data/spec/spec/runner/reporter_spec.rb +126 -0
  180. data/spec/spec/runner/spec_matcher_spec.rb +107 -0
  181. data/spec/spec/runner/spec_name_generation_spec.rb +102 -0
  182. data/spec/spec/runner/spec_parser_spec.rb +37 -0
  183. data/spec/spec/runner/specification_class_spec.rb +72 -0
  184. data/spec/spec/runner/specification_instance_spec.rb +160 -0
  185. data/spec/spec/runner/specification_should_raise_spec.rb +136 -0
  186. data/spec/spec/spec_classes.rb +102 -0
  187. data/spec/spec/translator_spec.rb +79 -0
  188. data/spec/spec_helper.rb +35 -0
  189. metadata +141 -9
  190. data/bin/drbspec +0 -3
  191. data/lib/spec/expectations/diff.rb +0 -28
  192. data/lib/spec/expectations/extensions/numeric.rb +0 -19
  193. data/lib/spec/expectations/extensions/string.rb +0 -22
  194. data/lib/spec/expectations/message_builder.rb +0 -13
@@ -9,8 +9,9 @@ module Spec
9
9
 
10
10
  def include(mod)
11
11
  context_modules << mod
12
+ mod.send :included, self
12
13
  end
13
-
14
+
14
15
  def context_setup(&block)
15
16
  context_setup_parts << block
16
17
  end
@@ -27,7 +28,7 @@ module Spec
27
28
  teardown_parts << block
28
29
  end
29
30
 
30
- def specify(spec_name, opts={}, &block)
31
+ def specify(spec_name=:__generate_description, opts={}, &block)
31
32
  specifications << Specification.new(spec_name, opts, &block)
32
33
  end
33
34
 
@@ -88,7 +89,7 @@ module Spec
88
89
  end
89
90
 
90
91
  def context_modules
91
- @context_modules ||= []
92
+ @context_modules ||= [Spec::Matchers, Spec::Mocks]
92
93
  end
93
94
 
94
95
  def specifications
@@ -1,5 +1,3 @@
1
- require File.dirname(__FILE__) + '/../../spec'
2
-
3
1
  module Spec
4
2
  module Runner
5
3
  class ContextRunner
@@ -10,8 +8,8 @@ module Spec
10
8
  end
11
9
 
12
10
  def add_context(context)
13
- return if !@options.spec_name.nil? unless context.matches?(@options.spec_name)
14
- context.run_single_spec(@options.spec_name) if context.matches?(@options.spec_name)
11
+ return unless spec_description.nil? || context.matches?(spec_description)
12
+ context.run_single_spec(spec_description) if context.matches?(spec_description)
15
13
  @contexts << context
16
14
  end
17
15
 
@@ -47,6 +45,11 @@ module Spec
47
45
  @contexts.inject(0) {|sum, context| sum + context.number_of_specs}
48
46
  end
49
47
 
48
+ private
49
+ def spec_description
50
+ @options.spec_name
51
+ end
52
+
50
53
  end
51
54
  end
52
55
  end
@@ -6,7 +6,7 @@ module Spec
6
6
  class DrbCommandLine
7
7
  # Runs specs on a DRB server. Note that this API is similar to that of
8
8
  # CommandLine - making it possible for clients to use both interchangeably.
9
- def self.run(argv, stderr, stdout, exit=false, warn_if_no_files=true)
9
+ def self.run(argv, stderr, stdout, exit=true, warn_if_no_files=true)
10
10
  begin
11
11
  DRb.start_service
12
12
  rails_spec_server = DRbObject.new_with_uri("druby://localhost:8989")
@@ -2,18 +2,10 @@ module Spec
2
2
  module Runner
3
3
  class ExecutionContext
4
4
  module InstanceMethods
5
- def initialize(spec)
6
- @spec = spec
5
+ def initialize(*args) #:nodoc:
6
+ #necessary for RSpec's own specs
7
7
  end
8
-
9
- def mock(name, options={})
10
- Spec::Mocks::Mock.new(name, options)
11
- end
12
-
13
- def duck_type(*args)
14
- return Spec::Mocks::DuckTypeArgConstraint.new(*args)
15
- end
16
-
8
+
17
9
  def violated(message="")
18
10
  raise Spec::Expectations::ExpectationNotMetError.new(message)
19
11
  end
@@ -1,15 +1,17 @@
1
- require 'spec/runner/extensions/object'
2
-
3
1
  module Kernel
4
2
  def context(name, &block)
5
3
  context = Spec::Runner::Context.new(name, &block)
6
4
  context_runner.add_context(context)
7
5
  end
8
-
6
+
9
7
  private
10
-
8
+
11
9
  def context_runner
12
- if $context_runner.nil?; $context_runner = ::Spec::Runner::OptionParser.new.create_context_runner(ARGV.dup, STDERR, STDOUT, false); at_exit { $context_runner.run(false) }; end
10
+ # TODO: Figure out a better way to get this considered "covered" and keep this statement on multiple lines
11
+ unless $context_runner; \
12
+ $context_runner = ::Spec::Runner::OptionParser.new.create_context_runner(ARGV.dup, STDERR, STDOUT, false); \
13
+ at_exit { $context_runner.run(false) }; \
14
+ end
13
15
  $context_runner
14
16
  end
15
17
  end
@@ -1,3 +1,6 @@
1
+ # The following copyright applies to Object#copy_instance_variables_from,
2
+ # which we borrowed from active_support.
3
+ #
1
4
  # Copyright (c) 2004 David Heinemeier Hansson
2
5
  #
3
6
  # Permission is hereby granted, free of charge, to any person obtaining
@@ -20,7 +23,7 @@
20
23
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
24
  class Object
22
25
  # From active_support
23
- def copy_instance_variables_from(object, exclude = [])
26
+ def copy_instance_variables_from(object, exclude = []) # :nodoc:
24
27
  exclude += object.protected_instance_variables if object.respond_to? :protected_instance_variables
25
28
 
26
29
  instance_variables = object.instance_variables - exclude.map { |name| name.to_s }
@@ -96,10 +96,18 @@ module Spec
96
96
  end
97
97
 
98
98
  def colour(text, colour_code)
99
- return text unless @colour && @output == Kernel
99
+ return text unless @colour && output_to_tty?
100
100
  "#{colour_code}#{text}\e[0m"
101
101
  end
102
-
102
+
103
+ def output_to_tty?
104
+ begin
105
+ @output == Kernel || @output.tty?
106
+ rescue NoMethodError
107
+ false
108
+ end
109
+ end
110
+
103
111
  def red(text); colour(text, "\e[31m"); end
104
112
  def green(text); colour(text, "\e[32m"); end
105
113
  def magenta(text); colour(text, "\e[35m"); end
@@ -107,4 +115,4 @@ module Spec
107
115
  end
108
116
  end
109
117
  end
110
- end
118
+ end
@@ -2,6 +2,8 @@ module Spec
2
2
  module Runner
3
3
  module Formatter
4
4
  class HtmlFormatter < BaseTextFormatter
5
+ attr_reader :current_spec_number, :current_context_number
6
+
5
7
  def initialize(output, dry_run=false, colour=false)
6
8
  super
7
9
  @current_spec_number = 0
@@ -11,7 +13,9 @@ module Spec
11
13
  def start(spec_count)
12
14
  @spec_count = spec_count
13
15
 
14
- @output.puts @@header
16
+ @output.puts HEADER_1
17
+ @output.puts extra_header_content unless extra_header_content.nil?
18
+ @output.puts HEADER_2
15
19
  STDOUT.flush
16
20
  end
17
21
 
@@ -34,14 +38,13 @@ module Spec
34
38
  end
35
39
 
36
40
  def spec_started(name)
37
- @current_spec = name
38
41
  @current_spec_number += 1
39
42
  STDOUT.flush
40
43
  end
41
44
 
42
45
  def spec_passed(name)
43
46
  move_progress
44
- @output.puts " <dd class=\"spec passed\"><span class=\"passed_spec_name\">#{escape(@current_spec)}</span></dd>"
47
+ @output.puts " <dd class=\"spec passed\"><span class=\"passed_spec_name\">#{escape(name)}</span></dd>"
45
48
  STDOUT.flush
46
49
  end
47
50
 
@@ -50,19 +53,23 @@ module Spec
50
53
  @output.puts " <script type=\"text/javascript\">makeRed('context_#{@current_context_number}');</script>"
51
54
  move_progress
52
55
  @output.puts " <dd class=\"spec failed\">"
53
- @output.puts " <span class=\"failed_spec_name\">#{escape(@current_spec)}</span>"
56
+ @output.puts " <span class=\"failed_spec_name\">#{escape(name)}</span>"
54
57
  @output.puts " <div class=\"failure\" id=\"failure_#{counter}\">"
55
58
  @output.puts " <div class=\"message\"><pre>#{escape(failure.exception.message)}</pre></div>" unless failure.exception.nil?
56
59
  @output.puts " <div class=\"backtrace\"><pre>#{format_backtrace(failure.exception.backtrace)}</pre></div>" unless failure.exception.nil?
57
- extra_failure_content
60
+ @output.puts extra_failure_content unless extra_failure_content.nil?
58
61
  @output.puts " </div>"
59
62
  @output.puts " </dd>"
60
63
  STDOUT.flush
61
64
  end
62
65
 
63
- # Override this method if you wish to output extra HTML for a failed spec. For example, you
64
- # could output links to images or other files produced during the specs. Example:
66
+ # Override this method if you wish to output extra HTML in the header
65
67
  #
68
+ def extra_header_content
69
+ end
70
+
71
+ # Override this method if you wish to output extra HTML for a failed spec. For example, you
72
+ # could output links to images or other files produced during the specs.
66
73
  #
67
74
  def extra_failure_content
68
75
  end
@@ -93,7 +100,7 @@ module Spec
93
100
  STDOUT.flush
94
101
  end
95
102
 
96
- @@header = <<-HEADER
103
+ HEADER_1 = <<-EOF
97
104
  <?xml version="1.0" encoding="iso-8859-1"?>
98
105
  <!DOCTYPE html
99
106
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
@@ -103,7 +110,11 @@ module Spec
103
110
  <head>
104
111
  <title>RSpec results</title>
105
112
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
106
- <meta http-equiv="Content-Script-Type" content="text/javascript" />
113
+ <meta http-equiv="Expires" content="-1" />
114
+ <meta http-equiv="Pragma" content="no-cache" />
115
+ EOF
116
+
117
+ HEADER_2 = <<-EOF
107
118
  <script type="text/javascript">
108
119
  function moveProgressBar(percentDone) {
109
120
  document.getElementById("header").style.width = percentDone +"%";
@@ -201,7 +212,7 @@ module Spec
201
212
  </div>
202
213
 
203
214
  <div id="results">
204
- HEADER
215
+ EOF
205
216
  end
206
217
  end
207
218
  end
@@ -17,18 +17,24 @@ module Spec
17
17
  # methods in the matched classes.
18
18
  def heckle_with(context_runner)
19
19
  if @filter =~ /(.*)[#\.](.*)/
20
- heckle = @heckle_class.new($1, $2, context_runner)
21
- heckle.validate
20
+ heckle_method($1, $2)
22
21
  else
23
- heckle_module
22
+ heckle_class_or_module(@filter)
24
23
  end
25
24
  end
26
25
 
27
- def heckle_module
28
- filter = /^#{@filter}/
26
+ def heckle_method(class_name, method_name)
27
+ verify_constant(class_name)
28
+ heckle = @heckle_class.new(class_name, method_name, context_runner)
29
+ heckle.validate
30
+ end
31
+
32
+ def heckle_class_or_module(class_or_module_name)
33
+ verify_constant(class_or_module_name)
34
+ pattern = /^#{class_or_module_name}/
29
35
  classes = []
30
36
  ObjectSpace.each_object(Class) do |klass|
31
- classes << klass if klass.name =~ filter
37
+ classes << klass if klass.name =~ pattern
32
38
  end
33
39
 
34
40
  classes.each do |klass|
@@ -38,9 +44,19 @@ module Spec
38
44
  end
39
45
  end
40
46
  end
47
+
48
+ def verify_constant(name)
49
+ begin
50
+ # This is defined in Heckle
51
+ name.to_class
52
+ rescue
53
+ raise "Heckling failed - \"#{name}\" is not a known class or module"
54
+ end
55
+ end
41
56
  end
42
57
 
43
- class Heckler < Heckle::Base
58
+ #Supports Heckle 1.2 and prior (earlier versions used Heckle::Base)
59
+ class Heckler < (Heckle.const_defined?(:Base) ? Heckle::Base : Heckle)
44
60
  def initialize(klass_name, method_name, context_runner)
45
61
  super(klass_name, method_name)
46
62
  @context_runner = context_runner
@@ -52,4 +68,4 @@ module Spec
52
68
  end
53
69
  end
54
70
  end
55
- end
71
+ end
@@ -0,0 +1,10 @@
1
+ module Spec
2
+ module Runner
3
+ # Dummy implementation for Windows that just fails (Heckle is not supported on Windows)
4
+ class HeckleRunner
5
+ def initialize(filter)
6
+ raise "Heckle not supported on Windows"
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,5 +1,10 @@
1
1
  require 'ostruct'
2
2
  require 'optparse'
3
+ require 'spec/runner/spec_parser'
4
+ require 'spec/runner/formatter'
5
+ require 'spec/runner/backtrace_tweaker'
6
+ require 'spec/runner/reporter'
7
+ require 'spec/runner/context_runner'
3
8
 
4
9
  module Spec
5
10
  module Runner
@@ -11,6 +16,9 @@ module Spec
11
16
 
12
17
  def create_context_runner(args, err, out, warn_if_no_files)
13
18
  options = parse(args, err, out, warn_if_no_files)
19
+ # Some exit points in parse (--generate-options, --drb) don't return the options,
20
+ # but hand over control. In that case we don't want to continue.
21
+ return nil unless options.is_a?(OpenStruct)
14
22
 
15
23
  formatter = options.formatter_type.new(options.out, options.dry_run, options.colour)
16
24
  options.reporter = Reporter.new(formatter, options.backtrace_tweaker)
@@ -18,15 +26,19 @@ module Spec
18
26
  # this doesn't really belong here.
19
27
  # it should, but the way things are coupled, it doesn't
20
28
  if options.differ_class
21
- Spec::Expectations::Should::Base.differ = options.differ_class.new(options.diff_format, options.context_lines, options.colour)
29
+ Spec::Expectations.differ = options.differ_class.new(options.diff_format, options.context_lines, options.colour)
22
30
  end
23
31
 
24
- ContextRunner.new(options)
32
+ unless options.generate
33
+ ContextRunner.new(options)
34
+ end
25
35
  end
26
36
 
27
37
  def parse(args, err, out, warn_if_no_files)
38
+ options_file = nil
39
+ args_copy = args.dup
28
40
  options = OpenStruct.new
29
- options.out = out == STDOUT ? Kernel : out
41
+ options.out = (out == STDOUT ? Kernel : out)
30
42
  options.formatter_type = Formatter::ProgressBarFormatter
31
43
  options.backtrace_tweaker = QuietBacktraceTweaker.new
32
44
  options.spec_name = nil
@@ -39,7 +51,6 @@ module Spec
39
51
  "Builtin formats: unified|u|context|c",
40
52
  "You can also specify a custom differ class",
41
53
  "(in which case you should also specify --require)") do |format|
42
- require 'spec/expectations/diff' # patches in diff extension
43
54
 
44
55
  # TODO make context_lines settable
45
56
  options.context_lines = 3
@@ -104,7 +115,7 @@ module Spec
104
115
  opts.on("-r", "--require FILE", "Require FILE before running specs",
105
116
  "Useful for loading custom formatters or other extensions",
106
117
  "If this option is used it must come before the others") do |req|
107
- require req
118
+ req.split(",").each{|file| require file}
108
119
  end
109
120
 
110
121
  opts.on("-b", "--backtrace", "Output full backtrace") do
@@ -115,7 +126,8 @@ module Spec
115
126
  "the specced code a little each time. The intent is that specs",
116
127
  "*should* fail, and RSpec will tell you if they don't.",
117
128
  "CODE should be either Some::Module, Some::Class or Some::Fabulous#method}") do |heckle|
118
- require 'spec/runner/heckle_runner'
129
+ heckle_runner = PLATFORM == 'i386-mswin32' ? 'spec/runner/heckle_runner_win' : 'spec/runner/heckle_runner'
130
+ require heckle_runner
119
131
  options.heckle_runner = HeckleRunner.new(heckle)
120
132
  end
121
133
 
@@ -123,10 +135,42 @@ module Spec
123
135
  options.dry_run = true
124
136
  end
125
137
 
126
- opts.on("-o", "--out OUTPUT_FILE", "Path to output file (defaults to STDOUT)") do |outfile|
127
- options.out = File.new(outfile, 'w')
138
+ opts.on("-o", "--out OUTPUT_FILE", "Path to output file (defaults to STDOUT)") do |out_file|
139
+ options.out = File.new(out_file, 'w')
128
140
  end
129
141
 
142
+ opts.on("-O", "--options PATH", "Read options from a file") do |options_file|
143
+ # Remove the --options option and the argument before writing to file
144
+ index = args_copy.index("-O") || args_copy.index("--options")
145
+ args_copy.delete_at(index)
146
+ args_copy.delete_at(index)
147
+
148
+ new_args = args_copy + IO.readlines(options_file).each {|s| s.chomp!}
149
+ return CommandLine.run(new_args, err, out, true, warn_if_no_files)
150
+ end
151
+
152
+ opts.on("-G", "--generate-options PATH", "Generate an options file for --options") do |options_file|
153
+ # Remove the --generate-options option and the argument before writing to file
154
+ index = args_copy.index("-G") || args_copy.index("--generate-options")
155
+ args_copy.delete_at(index)
156
+ args_copy.delete_at(index)
157
+
158
+ File.open(options_file, 'w') do |io|
159
+ io.puts args_copy.join("\n")
160
+ end
161
+ out.puts "\nOptions written to #{options_file}. You can now use these options with:"
162
+ out.puts "spec --options #{options_file}"
163
+ options.generate = true
164
+ end
165
+
166
+ opts.on("-X", "--drb", "Run specs via DRb. (For example against script/rails_spec_server)") do |options_file|
167
+ # Remove the --options option and the argument before writing to file
168
+ index = args_copy.index("-X") || args_copy.index("--drb")
169
+ args_copy.delete_at(index)
170
+
171
+ return DrbCommandLine.run(args_copy, err, out, true, warn_if_no_files)
172
+ end
173
+
130
174
  opts.on("-v", "--version", "Show version") do
131
175
  out.puts ::Spec::VERSION::DESCRIPTION
132
176
  exit if out == $stdout
@@ -141,8 +185,9 @@ module Spec
141
185
  opts.parse!(args)
142
186
 
143
187
  if args.empty? && warn_if_no_files
188
+ err.puts "No files specified."
144
189
  err.puts opts
145
- exit(1) if err == $stderr
190
+ exit(6) if err == $stderr
146
191
  end
147
192
 
148
193
  if options.line_number
@@ -163,15 +208,15 @@ module Spec
163
208
  exit(1) if err == $stderr
164
209
  else
165
210
  err.puts "#{args[0]} does not exist"
166
- exit(1) if err == $stderr
211
+ exit(2) if err == $stderr
167
212
  end
168
213
  else
169
- err.puts "Only one file can be specified when using the --line option"
170
- exit(1) if err == $stderr
214
+ err.puts "Only one file can be specified when using the --line option: #{args.inspect}"
215
+ exit(3) if err == $stderr
171
216
  end
172
217
  else
173
218
  err.puts "You cannot use both --line and --spec"
174
- exit(1) if err == $stderr
219
+ exit(4) if err == $stderr
175
220
  end
176
221
  end
177
222
  end