rspec-core 2.14.8 → 2.99.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +8 -8
  2. data/Changelog.md +54 -8
  3. data/features/command_line/order.feature +5 -8
  4. data/features/configuration/custom_settings.feature +10 -10
  5. data/features/configuration/deprecation_stream.feature +3 -3
  6. data/features/configuration/read_options_from_file.feature +1 -1
  7. data/features/example_groups/shared_examples.feature +2 -2
  8. data/features/hooks/around_hooks.feature +1 -1
  9. data/features/metadata/current_example.feature +43 -4
  10. data/features/metadata/user_defined.feature +12 -12
  11. data/lib/autotest/rspec2.rb +60 -56
  12. data/lib/rspec/core.rb +40 -2
  13. data/lib/rspec/core/caller_filter.rb +55 -0
  14. data/lib/rspec/core/command_line.rb +2 -2
  15. data/lib/rspec/core/configuration.rb +201 -13
  16. data/lib/rspec/core/deprecation.rb +2 -7
  17. data/lib/rspec/core/example.rb +5 -8
  18. data/lib/rspec/core/example_group.rb +101 -17
  19. data/lib/rspec/core/filter_manager.rb +2 -2
  20. data/lib/rspec/core/formatters/deprecation_formatter.rb +173 -15
  21. data/lib/rspec/core/formatters/text_mate_formatter.rb +0 -12
  22. data/lib/rspec/core/hooks.rb +1 -1
  23. data/lib/rspec/core/memoized_helpers.rb +49 -17
  24. data/lib/rspec/core/metadata.rb +1 -1
  25. data/lib/rspec/core/option_parser.rb +8 -3
  26. data/lib/rspec/core/pending.rb +14 -10
  27. data/lib/rspec/core/rake_task.rb +30 -6
  28. data/lib/rspec/core/runner.rb +9 -0
  29. data/lib/rspec/core/shared_example_group.rb +11 -9
  30. data/lib/rspec/core/shared_example_group/collection.rb +3 -1
  31. data/lib/rspec/core/version.rb +1 -2
  32. data/spec/command_line/order_spec.rb +4 -4
  33. data/spec/rspec/core/backtrace_cleaner_spec.rb +10 -10
  34. data/spec/rspec/core/caller_filter_spec.rb +58 -0
  35. data/spec/rspec/core/command_line_spec.rb +1 -0
  36. data/spec/rspec/core/configuration_options_spec.rb +6 -6
  37. data/spec/rspec/core/configuration_spec.rb +285 -52
  38. data/spec/rspec/core/deprecation_spec.rb +10 -29
  39. data/spec/rspec/core/deprecations_spec.rb +0 -14
  40. data/spec/rspec/core/example_group_spec.rb +74 -56
  41. data/spec/rspec/core/example_spec.rb +54 -17
  42. data/spec/rspec/core/filter_manager_spec.rb +2 -2
  43. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +156 -52
  44. data/spec/rspec/core/formatters/html_formatter_spec.rb +1 -1
  45. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +1 -2
  46. data/spec/rspec/core/hooks_spec.rb +2 -0
  47. data/spec/rspec/core/memoized_helpers_spec.rb +154 -113
  48. data/spec/rspec/core/metadata_spec.rb +25 -25
  49. data/spec/rspec/core/option_parser_spec.rb +19 -1
  50. data/spec/rspec/core/project_initializer_spec.rb +4 -4
  51. data/spec/rspec/core/rake_task_spec.rb +25 -4
  52. data/spec/rspec/core/shared_context_spec.rb +4 -4
  53. data/spec/rspec/core/shared_example_group_spec.rb +1 -1
  54. data/spec/rspec/core_spec.rb +36 -2
  55. data/spec/spec_helper.rb +3 -0
  56. data/spec/support/helper_methods.rb +16 -1
  57. data/spec/support/shared_example_groups.rb +1 -0
  58. data/spec/support/silence_dsl_deprecations.rb +32 -0
  59. metadata +10 -7
  60. data/spec/rspec/core/formatters/text_mate_formatted-2.1.0.html +0 -425
@@ -2,7 +2,7 @@ require_rspec = if defined?(require_relative)
2
2
  lambda do |path|
3
3
  require_relative path
4
4
  end
5
- else
5
+ else # for 1.8.7
6
6
  lambda do |path|
7
7
  require "rspec/#{path}"
8
8
  end
@@ -11,6 +11,7 @@ end
11
11
  require 'set'
12
12
  require 'time'
13
13
  require 'rbconfig'
14
+ require_rspec['core/caller_filter']
14
15
  require_rspec['core/filter_manager']
15
16
  require_rspec['core/dsl']
16
17
  require_rspec['core/extensions/kernel']
@@ -94,7 +95,7 @@ DEPRECATION WARNING
94
95
  * RSpec.configuration with a block is deprecated and has no effect.
95
96
  * please use RSpec.configure with a block instead.
96
97
 
97
- Called from #{caller(0)[1]}
98
+ Called from #{CallerFilter.first_non_rspec_line}
98
99
  *****************************************************************
99
100
 
100
101
  WARNING
@@ -126,6 +127,37 @@ WARNING
126
127
  world.example_groups.clear
127
128
  end
128
129
 
130
+ # The example being executed.
131
+ #
132
+ # The primary audience for this method is library authors who need access
133
+ # to the example currently being executed and also want to support all
134
+ # versions of RSpec 2 and 3.
135
+ #
136
+ # @example
137
+ #
138
+ # RSpec.configure do |c|
139
+ # # context.example is deprecated, but RSpec.current_example is not
140
+ # # available until RSpec 3.0.
141
+ # fetch_current_example = RSpec.respond_to?(:current_example) ?
142
+ # proc { RSpec.current_example } : proc { |context| context.example }
143
+ #
144
+ # c.before(:each) do
145
+ # example = fetch_current_example.call(self)
146
+ #
147
+ # # ...
148
+ # end
149
+ # end
150
+ #
151
+ def self.current_example
152
+ Thread.current[:_rspec_current_example]
153
+ end
154
+
155
+ # Set the current example being executed.
156
+ # @api private
157
+ def self.current_example=(example)
158
+ Thread.current[:_rspec_current_example] = example
159
+ end
160
+
129
161
  # @private
130
162
  def self.windows_os?
131
163
  RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/
@@ -141,6 +173,12 @@ WARNING
141
173
  define_method(:now,&::Time.method(:now))
142
174
  end
143
175
  end
176
+
177
+ # @private path to executable file
178
+ def self.path_to_executable
179
+ File.expand_path('../../../exe/rspec', __FILE__)
180
+ end
181
+
144
182
  end
145
183
 
146
184
  MODULES_TO_AUTOLOAD = {
@@ -0,0 +1,55 @@
1
+ module RSpec
2
+ # Consistent implementation for "cleaning" the caller method to strip out
3
+ # non-rspec lines. This enables errors to be reported at the call site in
4
+ # the code using the library, which is far more useful than the particular
5
+ # internal method that raised an error.
6
+ class CallerFilter
7
+
8
+ RSPEC_LIBS = %w[
9
+ core
10
+ mocks
11
+ expectations
12
+ matchers
13
+ rails
14
+ ]
15
+
16
+ ADDITIONAL_TOP_LEVEL_FILES = %w[ autorun ]
17
+
18
+ LIB_REGEX = %r{/lib/rspec/(#{(RSPEC_LIBS + ADDITIONAL_TOP_LEVEL_FILES).join('|')})(\.rb|/)}
19
+
20
+ if RUBY_VERSION >= '2.0.0'
21
+ def self.first_non_rspec_line
22
+ # `caller` is an expensive method that scales linearly with the size of
23
+ # the stack. The performance hit for fetching it in chunks is small,
24
+ # and since the target line is probably near the top of the stack, the
25
+ # overall improvement of a chunked search like this is significant.
26
+ #
27
+ # See benchmarks/caller.rb for measurements.
28
+
29
+ # Initial value here is mostly arbitrary, but is chosen to give good
30
+ # performance on the common case of creating a double.
31
+ increment = 5
32
+ i = 1
33
+ line = nil
34
+
35
+ while !line
36
+ stack = caller(i, increment)
37
+ raise "No non-lib lines in stack" unless stack
38
+
39
+ line = stack.find { |l| l !~ LIB_REGEX }
40
+
41
+ i += increment
42
+ increment *= 2 # The choice of two here is arbitrary.
43
+ end
44
+
45
+ line
46
+ end
47
+ else
48
+ # Earlier rubies do not support the two argument form of `caller`. This
49
+ # fallback is logically the same, but slower.
50
+ def self.first_non_rspec_line
51
+ caller.find { |line| line !~ LIB_REGEX }
52
+ end
53
+ end
54
+ end
55
+ end
@@ -17,12 +17,12 @@ module RSpec
17
17
  # @param [IO] out
18
18
  def run(err, out)
19
19
  @configuration.error_stream = err
20
- @configuration.output_stream ||= out
20
+ @configuration.output_stream = out if @configuration.output_stream == $stdout
21
21
  @options.configure(@configuration)
22
22
  @configuration.load_spec_files
23
23
  @world.announce_filters
24
24
 
25
- @configuration.reporter.report(@world.example_count, @configuration.randomize? ? @configuration.seed : nil) do |reporter|
25
+ @configuration.reporter.report(@world.example_count, @configuration.send(:_randomize?) ? @configuration.seed : nil) do |reporter|
26
26
  begin
27
27
  @configuration.run_hook(:before, :suite)
28
28
  @world.example_groups.ordered.map {|g| g.run(reporter)}.all? ? 0 : @configuration.failure_exit_code
@@ -1,7 +1,7 @@
1
1
  require 'fileutils'
2
2
  require 'rspec/core/backtrace_cleaner'
3
3
  require 'rspec/core/ruby_project'
4
- require 'rspec/core/formatters/deprecation_formatter.rb'
4
+ require 'rspec/core/formatters/deprecation_formatter'
5
5
 
6
6
  module RSpec
7
7
  module Core
@@ -104,10 +104,6 @@ module RSpec
104
104
  # The exit code to return if there are any failures (default: 1).
105
105
  add_setting :failure_exit_code
106
106
 
107
- # Determines the order in which examples are run (default: OS standard
108
- # load order for files, declaration order for groups and examples).
109
- define_reader :order
110
-
111
107
  # Indicates files configured to be required
112
108
  define_reader :requires
113
109
 
@@ -116,11 +112,53 @@ module RSpec
116
112
 
117
113
  # Default: `$stdout`.
118
114
  # Also known as `output` and `out`
119
- add_setting :output_stream, :alias_with => [:output, :out]
115
+ define_reader :output_stream
116
+ def output_stream=(value)
117
+ if @reporter && !value.equal?(@output_stream)
118
+ warn "RSpec's reporter has already been initialized with " +
119
+ "#{output_stream.inspect} as the output stream, so your change to "+
120
+ "`output_stream` will be ignored. You should configure it earlier for " +
121
+ "it to take effect. (Called from #{CallerFilter.first_non_rspec_line})"
122
+ else
123
+ @output_stream = value
124
+ end
125
+ end
126
+
127
+ # @deprecated use RSpec::Core::Configuration#output_stream instead.
128
+ def output
129
+ RSpec.deprecate("RSpec::Core::Configuration#output", :replacement => "RSpec::Core::Configuration#output_stream")
130
+ output_stream
131
+ end
132
+
133
+ # @deprecated use RSpec::Core::Configuration#output_stream= instead.
134
+ def output=(value)
135
+ RSpec.deprecate("RSpec::Core::Configuration#output=", :replacement => "RSpec::Core::Configuration#output_stream=")
136
+ self.output_stream = value
137
+ end
138
+
139
+ # @deprecated use RSpec::Core::Configuration#output_stream instead.
140
+ def out
141
+ RSpec.deprecate("RSpec::Core::Configuration#out", :replacement => "RSpec::Core::Configuration#output_stream")
142
+ output_stream
143
+ end
144
+
145
+ # @deprecated use RSpec::Core::Configuration#output_stream= instead.
146
+ def out=(value)
147
+ RSpec.deprecate("RSpec::Core::Configuration#out=", :replacement => "RSpec::Core::Configuration#output_stream=")
148
+ self.output_stream = value
149
+ end
120
150
 
121
151
  # Load files matching this pattern (default: `'**/*_spec.rb'`)
122
152
  add_setting :pattern, :alias_with => :filename_pattern
123
153
 
154
+ def pattern= value
155
+ if @spec_files_loaded
156
+ Kernel.warn "WARNING: Configuring `pattern` to #{value} has no effect since RSpec has already loaded the spec files. Called from #{CallerFilter.first_non_rspec_line}"
157
+ end
158
+ @pattern = value
159
+ end
160
+ alias :filename_pattern= :pattern=
161
+
124
162
  # Report the times for the slowest examples (default: `false`).
125
163
  # Use this to specify the number of examples to include in the profile.
126
164
  add_setting :profile_examples
@@ -170,6 +208,14 @@ module RSpec
170
208
  # end
171
209
  add_setting :treat_symbols_as_metadata_keys_with_true_values
172
210
 
211
+ def treat_symbols_as_metadata_keys_with_true_values=(value)
212
+ unless value
213
+ RSpec.deprecate("RSpec.configuration.treat_symbols_as_metadata_keys_with_true_values = false")
214
+ end
215
+
216
+ @treat_symbols_as_metadata_keys_with_true_values = value
217
+ end
218
+
173
219
  # @private
174
220
  add_setting :tty
175
221
  # @private
@@ -190,13 +236,17 @@ module RSpec
190
236
  @files_to_run = []
191
237
  @formatters = []
192
238
  @color = false
239
+ @order = nil
193
240
  @pattern = '**/*_spec.rb'
194
241
  @failure_exit_code = 1
242
+ @spec_files_loaded = false
195
243
 
196
244
  @backtrace_cleaner = BacktraceCleaner.new
197
245
 
198
246
  @default_path = 'spec'
199
247
  @deprecation_stream = $stderr
248
+ @output_stream = $stdout
249
+ @reporter = nil
200
250
  @filter_manager = FilterManager.new
201
251
  @preferred_options = {}
202
252
  @seed = srand % 0xFFFF
@@ -226,6 +276,7 @@ module RSpec
226
276
 
227
277
  # @private
228
278
  def reset
279
+ @spec_files_loaded = false
229
280
  @reporter = nil
230
281
  @formatters.clear
231
282
  end
@@ -516,6 +567,18 @@ module RSpec
516
567
  end
517
568
 
518
569
  def debug=(bool)
570
+ if bool
571
+ # Usually this is called automatically by the --debug CLI option, so the
572
+ # deprecation message doesn't mention `RSpec::Core::Configuration#debug=`
573
+ RSpec.deprecate("RSpec's built-in debugger support",
574
+ :replacement => "a CLI option like `-rruby-debug` or `-rdebugger`")
575
+ else
576
+ # ...but the only way to call this with a false value is to
577
+ # call it directly, so here we mention the method name.
578
+ # There's no replacement for it since it's a no-op, though.
579
+ RSpec.deprecate("RSpec::Core::Configuration#debug=")
580
+ end
581
+
519
582
  return unless bool
520
583
  begin
521
584
  require 'ruby-debug'
@@ -537,6 +600,9 @@ EOM
537
600
  end
538
601
 
539
602
  def debug?
603
+ RSpec.deprecate("RSpec::Core::Configuration#debug?",
604
+ :replacement => "defined?(Debugger)")
605
+
540
606
  !!defined?(Debugger)
541
607
  end
542
608
 
@@ -574,7 +640,7 @@ EOM
574
640
  custom_formatter(formatter_to_use) ||
575
641
  (raise ArgumentError, "Formatter '#{formatter_to_use}' unknown - maybe you meant 'documentation' or 'progress'?.")
576
642
 
577
- paths << output if paths.empty?
643
+ paths << output_stream if paths.empty?
578
644
  formatters << formatter_class.new(*paths.map {|p| String === p ? file_at(p) : p})
579
645
  end
580
646
 
@@ -894,6 +960,7 @@ EOM
894
960
  # @private
895
961
  def load_spec_files
896
962
  files_to_run.uniq.each {|f| load File.expand_path(f) }
963
+ @spec_files_loaded = true
897
964
  raise_if_rspec_1_is_loaded
898
965
  end
899
966
 
@@ -930,8 +997,28 @@ EOM
930
997
  order_and_seed_from_order(type)
931
998
  end
932
999
 
1000
+ # Determines the order in which examples are run (default: OS standard
1001
+ # load order for files, declaration order for groups and examples).
1002
+ def order
1003
+ RSpec.warn_deprecation(
1004
+ "RSpec::Core::Configuration#order is deprecated with no replacement. " +
1005
+ "In RSpec 3 individal example groups can use a particular ordering, " +
1006
+ "so `order` is no longer a global property of the entire suite. " +
1007
+ "Called from #{CallerFilter.first_non_rspec_line}."
1008
+ )
1009
+
1010
+ value_for(:order, @order)
1011
+ end
1012
+
933
1013
  def randomize?
934
- order.to_s.match(/rand/)
1014
+ RSpec.warn_deprecation(
1015
+ "RSpec::Core::Configuration#randomize? is deprecated with no replacement. " +
1016
+ "In RSpec 3 individal example groups can use a particular ordering, " +
1017
+ "so `randomize?` is no longer a binary property of the entire suite. " +
1018
+ "Called from #{CallerFilter.first_non_rspec_line}."
1019
+ )
1020
+
1021
+ value_for(:order, @order).to_s.match(/rand/)
935
1022
  end
936
1023
 
937
1024
  # @private
@@ -959,6 +1046,7 @@ EOM
959
1046
  # @see #order=
960
1047
  # @see #seed=
961
1048
  def order_examples(&block)
1049
+ RSpec.deprecate("RSpec::Configuration#order_examples", :replacement => "RSpec::Configuration#register_ordering(:global)")
962
1050
  @example_ordering_block = block
963
1051
  @order = "custom" unless built_in_orderer?(block)
964
1052
  end
@@ -982,6 +1070,7 @@ EOM
982
1070
  # @see #order=
983
1071
  # @see #seed=
984
1072
  def order_groups(&block)
1073
+ RSpec.deprecate("RSpec::Configuration#order_groups", :replacement => "RSpec::Configuration#register_ordering(:global)")
985
1074
  @group_ordering_block = block
986
1075
  @order = "custom" unless built_in_orderer?(block)
987
1076
  end
@@ -1009,6 +1098,46 @@ EOM
1009
1098
  order_examples(&block)
1010
1099
  end
1011
1100
 
1101
+ # In RSpec 3, this registers a named ordering strategy that can later be
1102
+ # used to order an example group's subgroups by adding
1103
+ # `:order => <name>` metadata to the example group.
1104
+ #
1105
+ # In RSpec 2.99, only `register_ordering(:global)` is supported,
1106
+ # to set the global ordering.
1107
+ #
1108
+ # @param name [Symbol] The name of the ordering.
1109
+ # @yield Block that will order the given examples or example groups
1110
+ # @yieldparam list [Array<RSpec::Core::Example>, Array<RSpec::Core::ExampleGropu>] The examples or groups to order
1111
+ # @yieldreturn [Array<RSpec::Core::Example>, Array<RSpec::Core::ExampleGroup>] The re-ordered examples or groups
1112
+ #
1113
+ # @example
1114
+ # RSpec.configure do |rspec|
1115
+ # rspec.register_ordering :reverse do |list|
1116
+ # list.reverse
1117
+ # end
1118
+ # end
1119
+ #
1120
+ # describe MyClass, :order => :reverse do
1121
+ # # ...
1122
+ # end
1123
+ #
1124
+ # @note Pass the symbol `:global` to set the ordering strategy that
1125
+ # will be used to order the top-level example groups and any example
1126
+ # groups that do not have declared `:order` metadata.
1127
+ def register_ordering(name, &block)
1128
+ unless name == :global
1129
+ raise ArgumentError,
1130
+ "Ordering name `#{name.inspect}` given, `:global` expected. " +
1131
+ "RSpec 3 will support named orderings (that can be used for " +
1132
+ "individual example groups) but 2.99 only supports using this " +
1133
+ "to set the global order."
1134
+ end
1135
+
1136
+ @group_ordering_block = block
1137
+ @example_ordering_block = block
1138
+ @order = "custom"
1139
+ end
1140
+
1012
1141
  # Set Ruby warnings on or off
1013
1142
  def warnings= value
1014
1143
  $VERBOSE = !!value
@@ -1018,8 +1147,59 @@ EOM
1018
1147
  $VERBOSE
1019
1148
  end
1020
1149
 
1150
+ # Exposes the current running example via the named
1151
+ # helper method. RSpec 2.x exposed this via `example`,
1152
+ # but in RSpec 3.0, the example is instead exposed via
1153
+ # an arg yielded to `it`, `before`, `let`, etc. However,
1154
+ # some extension gems (such as Capybara) depend on the
1155
+ # RSpec 2.x's `example` method, so this config option
1156
+ # can be used to maintain compatibility.
1157
+ #
1158
+ # @param method_name [Symbol] the name of the helper method
1159
+ #
1160
+ # @example
1161
+ #
1162
+ # RSpec.configure do |rspec|
1163
+ # rspec.expose_current_running_example_as :example
1164
+ # end
1165
+ #
1166
+ # describe MyClass do
1167
+ # before do
1168
+ # # `example` can be used here because of the above config.
1169
+ # do_something if example.metadata[:type] == "foo"
1170
+ # end
1171
+ # end
1172
+ def expose_current_running_example_as(method_name)
1173
+ ExposeCurrentExample.module_eval do
1174
+ extend RSpec::SharedContext
1175
+ let(method_name) { |ex| ex }
1176
+ end
1177
+
1178
+ include ExposeCurrentExample
1179
+ end
1180
+
1181
+ module ExposeCurrentExample; end
1182
+
1183
+ # Turns deprecation warnings into errors, in order to surface
1184
+ # the full backtrace of the call site. This can be useful when
1185
+ # you need more context to address a deprecation than the
1186
+ # single-line call site normally provided.
1187
+ #
1188
+ # @example
1189
+ #
1190
+ # RSpec.configure do |rspec|
1191
+ # rspec.raise_errors_for_deprecations!
1192
+ # end
1193
+ def raise_errors_for_deprecations!
1194
+ self.deprecation_stream = Formatters::DeprecationFormatter::RaiseErrorStream.new
1195
+ end
1196
+
1021
1197
  private
1022
1198
 
1199
+ def _randomize?
1200
+ value_for(:order, @order).to_s.match(/rand/)
1201
+ end
1202
+
1023
1203
  def get_files_to_run(paths)
1024
1204
  paths.map do |path|
1025
1205
  path = path.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
@@ -1140,7 +1320,8 @@ MESSAGE
1140
1320
  end
1141
1321
 
1142
1322
  def order_and_seed_from_seed(value)
1143
- order_groups_and_examples(&RANDOM_ORDERING)
1323
+ @group_ordering_block = RANDOM_ORDERING
1324
+ @example_ordering_block = RANDOM_ORDERING
1144
1325
  @order, @seed = 'rand', value.to_i
1145
1326
  [@order, @seed]
1146
1327
  end
@@ -1155,11 +1336,18 @@ MESSAGE
1155
1336
  @order = order
1156
1337
  @seed = seed = seed.to_i if seed
1157
1338
 
1158
- if randomize?
1159
- order_groups_and_examples(&RANDOM_ORDERING)
1160
- elsif order == 'default'
1339
+ if order.to_s.match(/rand/)
1340
+ @group_ordering_block = RANDOM_ORDERING
1341
+ @example_ordering_block = RANDOM_ORDERING
1342
+ elsif %w[ default defined ].include?(order)
1343
+ if order == 'default'
1344
+ RSpec.deprecate("RSpec::Core::Configuration#order = 'default'",
1345
+ :replacement => "RSpec::Core::Configuration#order = 'defined'")
1346
+ end
1347
+
1161
1348
  @order, @seed = nil, nil
1162
- order_groups_and_examples(&DEFAULT_ORDERING)
1349
+ @group_ordering_block = DEFAULT_ORDERING
1350
+ @example_ordering_block = DEFAULT_ORDERING
1163
1351
  end
1164
1352
 
1165
1353
  return order, seed