rspec-core 2.99.2 → 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. checksums.yaml +14 -6
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +103 -191
  5. data/License.txt +1 -0
  6. data/README.md +4 -25
  7. data/features/Upgrade.md +2 -14
  8. data/features/command_line/dry_run.feature +29 -0
  9. data/features/command_line/example_name_option.feature +1 -1
  10. data/features/command_line/fail_fast.feature +26 -0
  11. data/features/command_line/format_option.feature +3 -3
  12. data/features/command_line/line_number_option.feature +16 -11
  13. data/features/command_line/order.feature +2 -3
  14. data/features/command_line/pattern_option.feature +3 -3
  15. data/features/command_line/randomization.feature +63 -0
  16. data/features/command_line/require_option.feature +2 -2
  17. data/features/command_line/ruby.feature +1 -1
  18. data/features/configuration/alias_example_to.feature +13 -22
  19. data/features/configuration/{backtrace_clean_patterns.feature → backtrace_exclusion_patterns.feature} +17 -14
  20. data/features/configuration/custom_settings.feature +11 -11
  21. data/features/configuration/overriding_global_ordering.feature +93 -0
  22. data/features/configuration/profile.feature +13 -13
  23. data/features/configuration/read_options_from_file.feature +7 -7
  24. data/features/example_groups/basic_structure.feature +1 -1
  25. data/features/example_groups/shared_context.feature +8 -8
  26. data/features/example_groups/shared_examples.feature +6 -14
  27. data/features/expectation_framework_integration/configure_expectation_framework.feature +27 -122
  28. data/features/filtering/exclusion_filters.feature +2 -5
  29. data/features/filtering/inclusion_filters.feature +1 -5
  30. data/features/formatters/json_formatter.feature +2 -2
  31. data/features/formatters/text_formatter.feature +4 -4
  32. data/features/helper_methods/arbitrary_methods.feature +2 -2
  33. data/features/helper_methods/let.feature +5 -5
  34. data/features/helper_methods/modules.feature +5 -8
  35. data/features/hooks/around_hooks.feature +2 -2
  36. data/features/hooks/before_and_after_hooks.feature +14 -14
  37. data/features/hooks/filtering.feature +12 -14
  38. data/features/metadata/described_class.feature +1 -1
  39. data/features/metadata/user_defined.feature +16 -29
  40. data/features/mock_framework_integration/use_flexmock.feature +1 -1
  41. data/features/mock_framework_integration/use_mocha.feature +1 -1
  42. data/features/mock_framework_integration/use_rr.feature +1 -1
  43. data/features/mock_framework_integration/use_rspec.feature +5 -5
  44. data/features/pending/pending_examples.feature +5 -5
  45. data/features/spec_files/arbitrary_file_suffix.feature +1 -1
  46. data/features/step_definitions/additional_cli_steps.rb +3 -3
  47. data/features/subject/explicit_subject.feature +8 -8
  48. data/features/subject/implicit_receiver.feature +29 -0
  49. data/features/subject/implicit_subject.feature +4 -4
  50. data/features/support/env.rb +10 -3
  51. data/features/support/require_expect_syntax_in_aruba_specs.rb +16 -0
  52. data/lib/rspec/core.rb +11 -48
  53. data/lib/rspec/core/backport_random.rb +302 -0
  54. data/lib/rspec/core/backtrace_formatter.rb +65 -0
  55. data/lib/rspec/core/command_line.rb +7 -18
  56. data/lib/rspec/core/configuration.rb +202 -507
  57. data/lib/rspec/core/configuration_options.rb +17 -30
  58. data/lib/rspec/core/example.rb +29 -39
  59. data/lib/rspec/core/example_group.rb +166 -259
  60. data/lib/rspec/core/filter_manager.rb +30 -47
  61. data/lib/rspec/core/flat_map.rb +17 -0
  62. data/lib/rspec/core/formatters.rb +0 -138
  63. data/lib/rspec/core/formatters/base_formatter.rb +46 -1
  64. data/lib/rspec/core/formatters/base_text_formatter.rb +38 -61
  65. data/lib/rspec/core/formatters/deprecation_formatter.rb +21 -52
  66. data/lib/rspec/core/formatters/helpers.rb +0 -28
  67. data/lib/rspec/core/formatters/html_formatter.rb +1 -1
  68. data/lib/rspec/core/formatters/json_formatter.rb +38 -9
  69. data/lib/rspec/core/formatters/snippet_extractor.rb +14 -5
  70. data/lib/rspec/core/hooks.rb +55 -39
  71. data/lib/rspec/core/memoized_helpers.rb +17 -167
  72. data/lib/rspec/core/metadata.rb +16 -64
  73. data/lib/rspec/core/option_parser.rb +30 -39
  74. data/lib/rspec/core/ordering.rb +154 -0
  75. data/lib/rspec/core/pending.rb +12 -69
  76. data/lib/rspec/core/project_initializer.rb +12 -10
  77. data/lib/rspec/core/rake_task.rb +5 -108
  78. data/lib/rspec/core/reporter.rb +15 -18
  79. data/lib/rspec/core/runner.rb +16 -30
  80. data/lib/rspec/core/shared_context.rb +3 -5
  81. data/lib/rspec/core/shared_example_group.rb +3 -51
  82. data/lib/rspec/core/shared_example_group/collection.rb +1 -19
  83. data/lib/rspec/core/version.rb +1 -1
  84. data/lib/rspec/core/warnings.rb +22 -0
  85. data/lib/rspec/core/world.rb +12 -8
  86. data/spec/command_line/order_spec.rb +20 -23
  87. data/spec/rspec/core/backtrace_formatter_spec.rb +216 -0
  88. data/spec/rspec/core/command_line_spec.rb +32 -48
  89. data/spec/rspec/core/configuration_options_spec.rb +19 -50
  90. data/spec/rspec/core/configuration_spec.rb +142 -713
  91. data/spec/rspec/core/drb_command_line_spec.rb +2 -0
  92. data/spec/rspec/core/dsl_spec.rb +0 -1
  93. data/spec/rspec/core/example_group_spec.rb +192 -223
  94. data/spec/rspec/core/example_spec.rb +40 -16
  95. data/spec/rspec/core/filter_manager_spec.rb +2 -2
  96. data/spec/rspec/core/formatters/base_formatter_spec.rb +0 -41
  97. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +5 -123
  98. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +2 -87
  99. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +2 -3
  100. data/spec/rspec/core/formatters/{text_mate_formatted.html → html_formatted-1.8.7-jruby.html} +44 -25
  101. data/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html +477 -0
  102. data/spec/rspec/core/formatters/{html_formatted.html → html_formatted-1.8.7.html} +42 -25
  103. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +425 -0
  104. data/spec/rspec/core/formatters/html_formatted-1.9.3-jruby.html +416 -0
  105. data/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html +477 -0
  106. data/spec/rspec/core/formatters/html_formatted-1.9.3.html +419 -0
  107. data/spec/rspec/core/formatters/html_formatted-2.0.0.html +425 -0
  108. data/spec/rspec/core/formatters/html_formatter_spec.rb +21 -46
  109. data/spec/rspec/core/formatters/json_formatter_spec.rb +97 -8
  110. data/spec/rspec/core/hooks_filtering_spec.rb +5 -5
  111. data/spec/rspec/core/hooks_spec.rb +61 -47
  112. data/spec/rspec/core/memoized_helpers_spec.rb +20 -322
  113. data/spec/rspec/core/metadata_spec.rb +1 -24
  114. data/spec/rspec/core/option_parser_spec.rb +20 -62
  115. data/spec/rspec/core/ordering_spec.rb +102 -0
  116. data/spec/rspec/core/pending_example_spec.rb +0 -40
  117. data/spec/rspec/core/project_initializer_spec.rb +1 -25
  118. data/spec/rspec/core/rake_task_spec.rb +5 -72
  119. data/spec/rspec/core/random_spec.rb +47 -0
  120. data/spec/rspec/core/reporter_spec.rb +23 -48
  121. data/spec/rspec/core/runner_spec.rb +31 -39
  122. data/spec/rspec/core/shared_context_spec.rb +3 -15
  123. data/spec/rspec/core/shared_example_group/collection_spec.rb +4 -17
  124. data/spec/rspec/core/shared_example_group_spec.rb +12 -45
  125. data/spec/rspec/core/{deprecation_spec.rb → warnings_spec.rb} +3 -1
  126. data/spec/rspec/core_spec.rb +4 -21
  127. data/spec/spec_helper.rb +41 -5
  128. data/spec/support/helper_methods.rb +0 -29
  129. data/spec/support/sandboxed_mock_space.rb +0 -16
  130. data/spec/support/shared_example_groups.rb +7 -36
  131. data/spec/support/stderr_splitter.rb +36 -0
  132. metadata +163 -157
  133. metadata.gz.sig +1 -0
  134. data/exe/autospec +0 -13
  135. data/features/Autotest.md +0 -38
  136. data/features/configuration/treat_symbols_as_metadata_keys_with_true_values.feature +0 -52
  137. data/features/subject/attribute_of_subject.feature +0 -124
  138. data/features/subject/one_liner_syntax.feature +0 -71
  139. data/lib/autotest/discover.rb +0 -10
  140. data/lib/autotest/rspec2.rb +0 -77
  141. data/lib/rspec/core/backtrace_cleaner.rb +0 -46
  142. data/lib/rspec/core/backward_compatibility.rb +0 -55
  143. data/lib/rspec/core/caller_filter.rb +0 -60
  144. data/lib/rspec/core/deprecated_mutable_array_proxy.rb +0 -32
  145. data/lib/rspec/core/deprecation.rb +0 -26
  146. data/lib/rspec/core/extensions/instance_eval_with_args.rb +0 -44
  147. data/lib/rspec/core/extensions/kernel.rb +0 -9
  148. data/lib/rspec/core/extensions/module_eval_with_args.rb +0 -38
  149. data/lib/rspec/core/extensions/ordered.rb +0 -27
  150. data/lib/rspec/core/formatters/console_codes.rb +0 -42
  151. data/lib/rspec/core/formatters/text_mate_formatter.rb +0 -34
  152. data/lib/rspec/core/metadata_hash_builder.rb +0 -97
  153. data/lib/rspec/core/minitest_assertions_adapter.rb +0 -28
  154. data/lib/rspec/core/test_unit_assertions_adapter.rb +0 -30
  155. data/spec/autotest/discover_spec.rb +0 -49
  156. data/spec/autotest/failed_results_re_spec.rb +0 -45
  157. data/spec/autotest/rspec_spec.rb +0 -133
  158. data/spec/rspec/core/backtrace_cleaner_spec.rb +0 -68
  159. data/spec/rspec/core/caller_filter_spec.rb +0 -58
  160. data/spec/rspec/core/deprecations_spec.rb +0 -59
  161. data/spec/rspec/core/formatters/console_codes_spec.rb +0 -50
  162. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +0 -107
  163. data/spec/rspec/core/kernel_extensions_spec.rb +0 -9
  164. data/spec/rspec/core/pending_spec.rb +0 -27
  165. data/spec/support/silence_dsl_deprecations.rb +0 -32
@@ -8,14 +8,9 @@ module RSpec
8
8
  attr_reader :options
9
9
 
10
10
  def initialize(args)
11
- @args = args.dup
12
- if @args.include?("--default_path")
13
- @args[@args.index("--default_path")] = "--default-path"
14
- end
15
-
16
- if @args.include?("--line_number")
17
- @args[@args.index("--line_number")] = "--line-number"
18
- end
11
+ @args = args.map {|a|
12
+ a.sub("default_path", "default-path").sub("line_number", "line-number")
13
+ }
19
14
  end
20
15
 
21
16
  def configure(config)
@@ -29,11 +24,16 @@ module RSpec
29
24
  end
30
25
 
31
26
  def parse_options
32
- @options ||= extract_filters_from(*all_configs).inject do |merged, pending|
33
- merged.merge(pending) { |key, oldval, newval|
34
- MERGED_OPTIONS.include?(key) ? oldval + newval : newval
27
+ @options = (file_options << command_line_options << env_options).
28
+ each {|opts|
29
+ filter_manager.include opts.delete(:inclusion_filter) if opts.has_key?(:inclusion_filter)
30
+ filter_manager.exclude opts.delete(:exclusion_filter) if opts.has_key?(:exclusion_filter)
31
+ }.
32
+ inject {|h, opts|
33
+ h.merge(opts) {|k, oldval, newval|
34
+ [:libs, :requires].include?(k) ? oldval + newval : newval
35
+ }
35
36
  }
36
- end
37
37
  end
38
38
 
39
39
  def drb_argv
@@ -46,17 +46,15 @@ module RSpec
46
46
 
47
47
  private
48
48
 
49
- NON_FORCED_OPTIONS = [
50
- :debug, :requires, :profile, :drb, :libs, :files_or_directories_to_run,
49
+ UNFORCED_OPTIONS = [
50
+ :requires, :profile, :drb, :libs, :files_or_directories_to_run,
51
51
  :line_numbers, :full_description, :full_backtrace, :tty
52
52
  ].to_set
53
53
 
54
- MERGED_OPTIONS = [:requires, :libs].to_set
55
-
56
54
  UNPROCESSABLE_OPTIONS = [:libs, :formatters, :requires].to_set
57
55
 
58
56
  def force?(key)
59
- !NON_FORCED_OPTIONS.include?(key)
57
+ !UNFORCED_OPTIONS.include?(key)
60
58
  end
61
59
 
62
60
  def order(keys, *ordered)
@@ -78,17 +76,6 @@ module RSpec
78
76
  options[:formatters].each { |pair| config.add_formatter(*pair) } if options[:formatters]
79
77
  end
80
78
 
81
- def extract_filters_from(*configs)
82
- configs.compact.each do |config|
83
- filter_manager.include config.delete(:inclusion_filter) if config.has_key?(:inclusion_filter)
84
- filter_manager.exclude config.delete(:exclusion_filter) if config.has_key?(:exclusion_filter)
85
- end
86
- end
87
-
88
- def all_configs
89
- @all_configs ||= file_options << command_line_options << env_options
90
- end
91
-
92
79
  def file_options
93
80
  custom_options_file ? [custom_options] : [global_options, project_options, local_options]
94
81
  end
@@ -124,7 +111,7 @@ module RSpec
124
111
  def args_from_options_file(path)
125
112
  return [] unless path && File.exist?(path)
126
113
  config_string = options_file_as_erb_string(path)
127
- config_string.split(/\n+/).map {|l| Shellwords.shellwords(l) }.flatten
114
+ FlatMap.flat_map(config_string.split(/\n+/), &:shellsplit)
128
115
  end
129
116
 
130
117
  def options_file_as_erb_string(path)
@@ -147,7 +134,7 @@ module RSpec
147
134
  begin
148
135
  File.join(File.expand_path("~"), ".rspec")
149
136
  rescue ArgumentError
150
- warn "Unable to find ~/.rspec because the HOME environment variable is not set"
137
+ RSpec.warning "Unable to find ~/.rspec because the HOME environment variable is not set"
151
138
  nil
152
139
  end
153
140
  end
@@ -44,7 +44,7 @@ module RSpec
44
44
  delegate_to_metadata :full_description, :execution_result, :file_path, :pending, :location
45
45
 
46
46
  # Returns the string submitted to `example` or its aliases (e.g.
47
- # `specify`, `it`, etc). If no string is submitted (e.g. `it { is_expected.to
47
+ # `specify`, `it`, etc). If no string is submitted (e.g. `it { should
48
48
  # do_something }`) it returns the message generated by the matcher if
49
49
  # there is one, otherwise returns a message including the location of the
50
50
  # example.
@@ -85,8 +85,6 @@ module RSpec
85
85
 
86
86
  # @deprecated access options via metadata instead
87
87
  def options
88
- RSpec.deprecate("`RSpec::Core::Example#options`",
89
- :replacement => "`RSpec::Core::Example#metadata`")
90
88
  @options
91
89
  end
92
90
 
@@ -109,17 +107,16 @@ module RSpec
109
107
  start(reporter)
110
108
 
111
109
  begin
112
- unless pending
110
+ unless pending || RSpec.configuration.dry_run?
113
111
  with_around_each_hooks do
114
112
  begin
115
113
  run_before_each
116
- @example_group_instance.instance_eval_with_args(self, &@example_block)
117
- rescue Pending::SkipDeclaredInExample => e
114
+ @example_group_instance.instance_exec(self, &@example_block)
115
+ rescue Pending::PendingDeclaredInExample => e
118
116
  @pending_declared_in_example = e.message
119
117
  rescue Exception => e
120
118
  set_exception(e)
121
119
  ensure
122
- assign_generated_description
123
120
  run_after_each
124
121
  end
125
122
  end
@@ -131,6 +128,12 @@ module RSpec
131
128
  @example_group_instance.instance_variable_set(ivar, nil)
132
129
  end
133
130
  @example_group_instance = nil
131
+
132
+ begin
133
+ assign_generated_description
134
+ rescue Exception => e
135
+ set_exception(e, "while assigning the example description")
136
+ end
134
137
  end
135
138
 
136
139
  finish(reporter)
@@ -138,16 +141,8 @@ module RSpec
138
141
  RSpec.current_example = nil
139
142
  end
140
143
 
141
- # @api private
142
- #
143
- # Wraps the example block in a Proc so it can invoked using `run` or
144
- # `call` in [around](../Hooks#around-instance_method) hooks.
145
- def self.procsy(metadata, &proc)
146
- proc.extend(Procsy).with(metadata)
147
- end
148
-
149
- # Used to extend a `Proc` with behavior that makes it look something like
150
- # an {Example} in an {Hooks#around around} hook.
144
+ # Wraps a `Proc` and exposes a `run` method for use in {Hooks#around
145
+ # around} hooks.
151
146
  #
152
147
  # @note Procsy, itself, is not a public API, but we're documenting it
153
148
  # here to document how to interact with the object yielded to an
@@ -156,32 +151,30 @@ module RSpec
156
151
  # @example
157
152
  #
158
153
  # RSpec.configure do |c|
159
- # c.around do |ex| # ex is a Proc extended with Procsy
154
+ # c.around do |ex| # Procsy which wraps the example
160
155
  # if ex.metadata[:key] == :some_value && some_global_condition
161
156
  # raise "some message"
162
157
  # end
163
158
  # ex.run # run delegates to ex.call
164
159
  # end
165
160
  # end
166
- module Procsy
161
+ class Procsy
167
162
  # The `metadata` of the {Example} instance.
168
163
  attr_reader :metadata
169
164
 
170
- # @api private
171
- # @param [Proc]
172
- # Adds a `run` method to the extended Proc, allowing it to be invoked
173
- # in an [around](../Hooks#around-instance_method) hook using either
174
- # `run` or `call`.
175
- def self.extended(proc)
176
- # @api public
177
- # Foo bar
178
- def proc.run; call; end
165
+ Proc.public_instance_methods(false).each do |name|
166
+ define_method(name) { |*a, &b| @proc.__send__(name, *a, &b) }
179
167
  end
168
+ alias run call
180
169
 
181
- # @api private
182
- def with(metadata)
170
+ def initialize(metadata, &block)
183
171
  @metadata = metadata
184
- self
172
+ @proc = block
173
+ end
174
+
175
+ # @api private
176
+ def wrap(&block)
177
+ self.class.new(metadata, &block)
185
178
  end
186
179
  end
187
180
 
@@ -232,13 +225,13 @@ An error occurred #{context}
232
225
  end
233
226
 
234
227
  # @private
235
- def instance_eval_with_rescue(context = nil, &block)
236
- @example_group_instance.instance_eval_with_rescue(self, context, &block)
228
+ def instance_exec_with_rescue(context = nil, &block)
229
+ @example_group_instance.instance_exec_with_rescue(self, context, &block)
237
230
  end
238
231
 
239
232
  # @private
240
- def instance_eval_with_args(*args, &block)
241
- @example_group_instance.instance_eval_with_args(*args, &block)
233
+ def instance_exec(*args, &block)
234
+ @example_group_instance.instance_exec(*args, &block)
242
235
  end
243
236
 
244
237
  private
@@ -247,7 +240,7 @@ An error occurred #{context}
247
240
  if around_each_hooks.empty?
248
241
  yield
249
242
  else
250
- @example_group_class.run_around_each_hooks(self, Example.procsy(metadata, &block))
243
+ @example_group_class.run_around_each_hooks(self, Procsy.new(metadata, &block))
251
244
  end
252
245
  rescue Exception => e
253
246
  set_exception(e, "in an around(:each) hook")
@@ -308,9 +301,6 @@ An error occurred #{context}
308
301
  if metadata[:description_args].empty? and !pending?
309
302
  metadata[:description_args] << RSpec::Matchers.generated_description
310
303
  end
311
- rescue Exception => e
312
- set_exception(e, "while assigning the example description")
313
- ensure
314
304
  RSpec::Matchers.clear_generated_description
315
305
  end
316
306
 
@@ -13,14 +13,10 @@ module RSpec
13
13
  # which serves as a wrapper for an instance of the ExampleGroup in which it
14
14
  # is declared.
15
15
  class ExampleGroup
16
- extend MetadataHashBuilder::WithDeprecationWarning
17
- extend Extensions::ModuleEvalWithArgs
18
16
  extend Hooks
19
17
 
20
18
  include MemoizedHelpers
21
- include Extensions::InstanceEvalWithArgs
22
19
  include Pending
23
- include SharedExampleGroup
24
20
  extend SharedExampleGroup
25
21
 
26
22
  # @private
@@ -49,166 +45,116 @@ module RSpec
49
45
  end
50
46
 
51
47
  delegate_to_metadata :described_class, :file_path
52
-
48
+ alias_method :display_name, :description
53
49
  # @private
54
- def display_name
55
- RSpec.deprecate('`RSpec::Core::ExampleGroup.display_name`',
56
- :replacement => "`RSpec::Core::ExampleGroup.description`")
57
- description
58
- end
50
+ alias_method :describes, :described_class
59
51
 
60
52
  # @private
61
- def describes
62
- RSpec.deprecate('`RSpec::Core::ExampleGroup.describes`',
63
- :replacement => "`RSpec::Core::ExampleGroup.described_class`")
64
- described_class
65
- end
66
- end
67
-
68
- # @private
69
- # @macro [attach] define_example_method
70
- # @param [String] name
71
- # @param [Hash] extra_options
72
- # @param [Block] implementation
73
- # @yield [Example] the example object
74
- def self.define_example_method(name, extra_options={})
75
- module_eval(<<-END_RUBY, __FILE__, __LINE__)
76
- def self.#{name}(desc=nil, *args, &block)
77
- if #{name.inspect} == :pending
78
- RSpec.warn_deprecation(<<-EOS.gsub(/^\s+\\|/, ''))
79
- |The semantics of `RSpec::Core::ExampleGroup.pending` are changing in RSpec 3.
80
- |In RSpec 2.x, it caused the example to be skipped. In RSpec 3, the example will
81
- |still be run but is expected to fail, and will be marked as a failure (rather
82
- |than as pending) if the example passes, just like how `pending` with a block
83
- |from within an example already works.
84
- |
85
- |To keep the same skip semantics, change `pending` to `skip`. Otherwise, if you
86
- |want the new RSpec 3 behavior, you can safely ignore this warning and continue
87
- |to upgrade to RSpec 3 without addressing it.
88
- |
89
- |Called from \#{CallerFilter.first_non_rspec_line}.
90
- |
91
- EOS
92
- end
93
- options = build_metadata_hash_from(args)
53
+ # @macro [attach] define_example_method
54
+ # @param [String] name
55
+ # @param [Hash] extra_options
56
+ # @param [Block] implementation
57
+ # @yield [Example] the example object
58
+ def self.define_example_method(name, extra_options={})
59
+ define_method(name) do |*all_args, &block|
60
+ desc, *args = *all_args
61
+ options = Metadata.build_hash_from(args)
94
62
  options.update(:pending => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
95
- # Backport from RSpec 3 to assist with upgrading
96
- options.update(:pending => options[:skip]) if options[:skip]
97
- options.update(#{extra_options.inspect})
63
+ options.update(extra_options)
98
64
  examples << RSpec::Core::Example.new(self, desc, options, block)
99
65
  examples.last
100
66
  end
101
- END_RUBY
102
- end
67
+ end
103
68
 
104
- # Defines an example within a group.
105
- # @example
106
- # example do
107
- # end
108
- #
109
- # example "does something" do
110
- # end
111
- #
112
- # example "does something", :with => 'additional metadata' do
113
- # end
114
- #
115
- # example "does something" do |ex|
116
- # # ex is the Example object that evals this block
117
- # end
118
- define_example_method :example
119
- # Defines an example within a group.
120
- # @example
121
- define_example_method :it
122
- # Defines an example within a group.
123
- # This is here primarily for backward compatibility with early versions
124
- # of RSpec which used `context` and `specify` instead of `describe` and
125
- # `it`.
126
- define_example_method :specify
127
-
128
- # Shortcut to define an example with `:focus` => true
129
- # @see example
130
- define_example_method :focus, :focused => true, :focus => true
131
- # Shortcut to define an example with `:focus` => true
132
- # @see example
133
- define_example_method :fit, :focused => true, :focus => true
134
-
135
- # Shortcut to define an example with :pending => true
136
- # @see example
137
- define_example_method :pending, :pending => true
138
- # Shortcut to define an example with :pending => true
139
- # Backported from RSpec 3 to aid migration.
140
- # @see example
141
- define_example_method :skip, :pending => true
142
- # Shortcut to define an example with :pending => 'Temporarily disabled with xexample'
143
- # @see example
144
- define_example_method :xexample, :pending => 'Temporarily disabled with xexample'
145
- # Shortcut to define an example with :pending => 'Temporarily disabled with xit'
146
- # @see example
147
- define_example_method :xit, :pending => 'Temporarily disabled with xit'
148
- # Shortcut to define an example with :pending => 'Temporarily disabled with xspecify'
149
- # @see example
150
- define_example_method :xspecify, :pending => 'Temporarily disabled with xspecify'
151
-
152
- # Shortcut to define an example with `:focus` => true
153
- # @see example
154
- def self.focused(desc=nil, *args, &block)
155
- RSpec.deprecate("`RSpec::Core::ExampleGroup.focused`",
156
- :replacement => "`RSpec::Core::ExampleGroup.focus`")
157
-
158
- metadata = Hash === args.last ? args.pop : {}
159
- metadata.merge!(:focus => true, :focused => true)
160
- args << metadata
161
-
162
- example(desc, *args, &block)
163
- end
164
-
165
- # Works like `alias_method :name, :example` with the added benefit of
166
- # assigning default metadata to the generated example.
167
- #
168
- # @note Use with caution. This extends the language used in your
169
- # specs, but does not add any additional documentation. We use this
170
- # in rspec to define methods like `focus` and `xit`, but we also add
171
- # docs for those methods.
172
- def self.alias_example_to name, extra={}
173
- RSpec.deprecate("`RSpec::Core::ExampleGroup.alias_example_to`",
174
- :replacement => "`RSpec::Core::Configuration#alias_example_to`")
175
- define_example_method name, extra
176
- end
69
+ # Defines an example within a group.
70
+ # @example
71
+ # example do
72
+ # end
73
+ #
74
+ # example "does something" do
75
+ # end
76
+ #
77
+ # example "does something", :with => 'additional metadata' do
78
+ # end
79
+ #
80
+ # example "does something" do |ex|
81
+ # # ex is the Example object that evals this block
82
+ # end
83
+ define_example_method :example
84
+ # Defines an example within a group.
85
+ # @example
86
+ define_example_method :it
87
+ # Defines an example within a group.
88
+ # This is here primarily for backward compatibility with early versions
89
+ # of RSpec which used `context` and `specify` instead of `describe` and
90
+ # `it`.
91
+ define_example_method :specify
92
+
93
+ # Shortcut to define an example with `:focus` => true
94
+ # @see example
95
+ define_example_method :focus, :focused => true, :focus => true
96
+ # Shortcut to define an example with `:focus` => true
97
+ # @see example
98
+ define_example_method :focused, :focused => true, :focus => true
99
+ # Shortcut to define an example with `:focus` => true
100
+ # @see example
101
+ define_example_method :fit, :focused => true, :focus => true
102
+
103
+ # Shortcut to define an example with :pending => true
104
+ # @see example
105
+ define_example_method :pending, :pending => true
106
+ # Shortcut to define an example with :pending => 'Temporarily disabled with xexample'
107
+ # @see example
108
+ define_example_method :xexample, :pending => 'Temporarily disabled with xexample'
109
+ # Shortcut to define an example with :pending => 'Temporarily disabled with xit'
110
+ # @see example
111
+ define_example_method :xit, :pending => 'Temporarily disabled with xit'
112
+ # Shortcut to define an example with :pending => 'Temporarily disabled with xspecify'
113
+ # @see example
114
+ define_example_method :xspecify, :pending => 'Temporarily disabled with xspecify'
115
+
116
+ # Works like `alias_method :name, :example` with the added benefit of
117
+ # assigning default metadata to the generated example.
118
+ #
119
+ # @note Use with caution. This extends the language used in your
120
+ # specs, but does not add any additional documentation. We use this
121
+ # in rspec to define methods like `focus` and `xit`, but we also add
122
+ # docs for those methods.
123
+ def alias_example_to name, extra={}
124
+ (class << self; self; end).define_example_method name, extra
125
+ end
177
126
 
178
- # @private
179
- # @macro [attach] define_nested_shared_group_method
180
- #
181
- # @see SharedExampleGroup
182
- def self.define_nested_shared_group_method(new_name, report_label=nil)
183
- module_eval(<<-END_RUBY, __FILE__, __LINE__)
184
- def self.#{new_name}(name, *args, &customization_block)
185
- group = describe("#{report_label || "it should behave like"} \#{name}") do
127
+ # @private
128
+ # @macro [attach] define_nested_shared_group_method
129
+ #
130
+ # @see SharedExampleGroup
131
+ def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
132
+ define_method(new_name) do |name, *args, &customization_block|
133
+ group = describe("#{report_label} #{name}") do
186
134
  find_and_eval_shared("examples", name, *args, &customization_block)
187
135
  end
188
136
  group.metadata[:shared_group_name] = name
189
137
  group
190
138
  end
191
- END_RUBY
192
- end
139
+ end
193
140
 
194
- # Generates a nested example group and includes the shared content
195
- # mapped to `name` in the nested group.
196
- define_nested_shared_group_method :it_behaves_like, "behaves like"
197
- # Generates a nested example group and includes the shared content
198
- # mapped to `name` in the nested group.
199
- define_nested_shared_group_method :it_should_behave_like
141
+ # Generates a nested example group and includes the shared content
142
+ # mapped to `name` in the nested group.
143
+ define_nested_shared_group_method :it_behaves_like, "behaves like"
144
+ # Generates a nested example group and includes the shared content
145
+ # mapped to `name` in the nested group.
146
+ define_nested_shared_group_method :it_should_behave_like
200
147
 
201
- # Works like `alias_method :name, :it_behaves_like` with the added
202
- # benefit of assigning default metadata to the generated example.
203
- #
204
- # @note Use with caution. This extends the language used in your
205
- # specs, but does not add any additional documentation. We use this
206
- # in rspec to define `it_should_behave_like` (for backward
207
- # compatibility), but we also add docs for that method.
208
- def self.alias_it_behaves_like_to name, *args, &block
209
- RSpec.deprecate("`RSpec::Core::ExampleGroup.alias_it_behaves_like_to`",
210
- :replacement => "`RSpec::Core::Configuration#alias_it_behaves_like_to`")
211
- define_nested_shared_group_method name, *args, &block
148
+ # Works like `alias_method :name, :it_behaves_like` with the added
149
+ # benefit of assigning default metadata to the generated example.
150
+ #
151
+ # @note Use with caution. This extends the language used in your
152
+ # specs, but does not add any additional documentation. We use this
153
+ # in rspec to define `it_should_behave_like` (for backward
154
+ # compatibility), but we also add docs for that method.
155
+ def alias_it_behaves_like_to name, *args, &block
156
+ (class << self; self; end).define_nested_shared_group_method name, *args, &block
157
+ end
212
158
  end
213
159
 
214
160
  # Includes shared content mapped to `name` directly in the group in which
@@ -229,46 +175,12 @@ module RSpec
229
175
  find_and_eval_shared("examples", name, *args, &block)
230
176
  end
231
177
 
232
- if Proc.method_defined?(:parameters) # for >= 1.9
233
- # Warn when submitting the name of more than one example group to
234
- # include_examples, it_behaves_like, etc.
235
- #
236
- # Helpful when upgrading from rspec-1 (which supported multiple shared
237
- # groups in one call) to rspec-2 (which does not).
238
- #
239
- # See https://github.com/rspec/rspec-core/issues/1066 for background.
240
- def self.warn_unexpected_args(label, name, args, shared_block)
241
- if !args.empty? && shared_block.parameters.count == 0
242
- if shared_example_groups[args.first]
243
- warn <<-WARNING
244
- shared #{label} support#{'s' if /context/ =~ label.to_s} the name of only one example group, received #{[name, *args].inspect}
245
- called from #{CallerFilter.first_non_rspec_line}"
246
- WARNING
247
- else
248
- warn <<-WARNING
249
- shared #{label} #{name.inspect} expected #{shared_block.arity} args, got #{args.inspect}
250
- called from #{CallerFilter.first_non_rspec_line}"
251
- WARNING
252
- end
253
- end
254
- end
255
- else
256
- # no-op for Ruby < 1.9
257
- #
258
- # Ruby 1.8 reports lambda {}.arity == -1, so can't support this warning
259
- # reliably
260
- def self.warn_unexpected_args(*)
261
- end
262
- end
263
-
264
178
  # @private
265
179
  def self.find_and_eval_shared(label, name, *args, &customization_block)
266
180
  raise ArgumentError, "Could not find shared #{label} #{name.inspect}" unless
267
181
  shared_block = shared_example_groups[name]
268
182
 
269
- warn_unexpected_args(label, name, args, shared_block)
270
-
271
- module_eval_with_args(*args, &shared_block)
183
+ module_exec(*args, &shared_block)
272
184
  module_eval(&customization_block) if customization_block
273
185
  end
274
186
 
@@ -321,43 +233,14 @@ WARNING
321
233
  #
322
234
  # @see DSL#describe
323
235
  def self.describe(*args, &example_group_block)
324
- @_subclass_count ||= 0
325
- @_subclass_count += 1
326
-
327
- if Symbol === args.first || Hash === args.first
328
- description_arg_behavior_changing_in_rspec_3 = DescriptionBehaviorChange.new(
329
- args.first, CallerFilter.first_non_rspec_line
330
- )
331
- end
332
-
333
236
  args << {} unless args.last.is_a?(Hash)
334
- args.last.update(
335
- :example_group_block => example_group_block,
336
- :description_arg_behavior_changing_in_rspec_3 => description_arg_behavior_changing_in_rspec_3
337
- )
338
-
339
- # TODO 2010-05-05: Because we don't know if const_set is thread-safe
340
- child = const_set(
341
- "Nested_#{@_subclass_count}",
342
- subclass(self, args, &example_group_block)
343
- )
237
+ args.last.update(:example_group_block => example_group_block)
238
+
239
+ child = subclass(self, args, &example_group_block)
344
240
  children << child
345
241
  child
346
242
  end
347
243
 
348
- DescriptionBehaviorChange = Struct.new(:arg, :call_site) do
349
- def warning
350
- <<-EOS.gsub(/^\s+\|/, '')
351
- |The semantics of `describe <a #{arg.class.name}>` are changing in RSpec 3. In RSpec 2,
352
- |this would be treated as metadata, but as the first `describe` argument,
353
- |this will be treated as the described object (affecting the value of
354
- |`described_class`) in RSpec 3. If you want this to be treated as metadata,
355
- |pass a description as the first argument.
356
- |(Example group defined at #{call_site})
357
- EOS
358
- end
359
- end
360
-
361
244
  class << self
362
245
  alias_method :context, :describe
363
246
  end
@@ -366,6 +249,7 @@ WARNING
366
249
  def self.subclass(parent, args, &example_group_block)
367
250
  subclass = Class.new(parent)
368
251
  subclass.set_it_up(*args)
252
+ ExampleGroups.assign_const(subclass)
369
253
  subclass.module_eval(&example_group_block) if example_group_block
370
254
 
371
255
  # The LetDefinitions module must be included _after_ other modules
@@ -379,7 +263,7 @@ WARNING
379
263
 
380
264
  # @private
381
265
  def self.children
382
- @children ||= [].extend(Extensions::Ordered::ExampleGroups)
266
+ @children ||= []
383
267
  end
384
268
 
385
269
  # @private
@@ -418,9 +302,10 @@ WARNING
418
302
  ensure_example_groups_are_configured
419
303
 
420
304
  symbol_description = args.shift if args.first.is_a?(Symbol)
421
- args << build_metadata_hash_from(args)
305
+ args << Metadata.build_hash_from(args)
422
306
  args.unshift(symbol_description) if symbol_description
423
307
  @metadata = RSpec::Core::Metadata.new(superclass_metadata).process(*args)
308
+ @order = nil
424
309
  hooks.register_globals(self, RSpec.configuration.hooks)
425
310
  world.configure_group(self)
426
311
  end
@@ -494,7 +379,7 @@ WARNING
494
379
  begin
495
380
  run_before_all_hooks(new)
496
381
  result_for_this_group = run_examples(reporter)
497
- results_for_descendants = children.ordered.map {|child| child.run(reporter)}.all?
382
+ results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
498
383
  result_for_this_group && results_for_descendants
499
384
  rescue Exception => ex
500
385
  RSpec.wants_to_quit = true if fail_fast?
@@ -506,9 +391,25 @@ WARNING
506
391
  end
507
392
  end
508
393
 
394
+ # @private
395
+ def self.ordering_strategy
396
+ order = metadata.fetch(:order, :global)
397
+ registry = RSpec.configuration.ordering_registry
398
+
399
+ registry.fetch(order) do
400
+ warn <<-WARNING.gsub(/^ +\|/, '')
401
+ |WARNING: Ignoring unknown ordering specified using `:order => #{order.inspect}` metadata.
402
+ | Falling back to configured global ordering.
403
+ | Unrecognized ordering specified at: #{metadata[:example_group][:location]}
404
+ WARNING
405
+
406
+ registry.fetch(:global)
407
+ end
408
+ end
409
+
509
410
  # @private
510
411
  def self.run_examples(reporter)
511
- filtered_examples.ordered.map do |example|
412
+ ordering_strategy.order(filtered_examples).map do |example|
512
413
  next if RSpec.wants_to_quit
513
414
  instance = new
514
415
  set_ivars(instance, before_all_ivars)
@@ -562,44 +463,6 @@ WARNING
562
463
  ivars.each {|name, value| instance.instance_variable_set(name, value)}
563
464
  end
564
465
 
565
- def example=(current_example)
566
- RSpec.current_example = current_example
567
- end
568
-
569
- # @deprecated use a block argument
570
- def example
571
- warn_deprecation_of_example_accessor :example
572
- RSpec.current_example
573
- end
574
-
575
- # @deprecated use a block argument
576
- def running_example
577
- warn_deprecation_of_example_accessor :running_example
578
- RSpec.current_example
579
- end
580
-
581
- def warn_deprecation_of_example_accessor(name)
582
- RSpec.warn_deprecation(<<-EOS.gsub(/^\s*\|/, ''))
583
- |RSpec::Core::ExampleGroup##{name} is deprecated and will be removed
584
- |in RSpec 3. There are a few options for what you can use instead:
585
- |
586
- | - rspec-core's DSL methods (`it`, `before`, `after`, `let`, `subject`, etc)
587
- | now yield the example as a block argument, and that is the recommended
588
- | way to access the current example from those contexts.
589
- | - The current example is now exposed via `RSpec.current_example`,
590
- | which is accessible from any context.
591
- | - If you can't update the code at this call site (e.g. because it is in
592
- | an extension gem), you can use this snippet to continue making this
593
- | method available in RSpec 2.99 and RSpec 3:
594
- |
595
- | RSpec.configure do |c|
596
- | c.expose_current_running_example_as :#{name}
597
- | end
598
- |
599
- |(Called from #{CallerFilter.first_non_rspec_line})
600
- EOS
601
- end
602
-
603
466
  # Returns the class or module passed to the `describe` method (or alias).
604
467
  # Returns nil if the subject is not a class or module.
605
468
  # @example
@@ -617,9 +480,9 @@ WARNING
617
480
  # @private
618
481
  # instance_evals the block, capturing and reporting an exception if
619
482
  # raised
620
- def instance_eval_with_rescue(example, context = nil, &hook)
483
+ def instance_exec_with_rescue(example, context = nil, &hook)
621
484
  begin
622
- instance_eval_with_args(example, &hook)
485
+ instance_exec(example, &hook)
623
486
  rescue Exception => e
624
487
  if RSpec.current_example
625
488
  RSpec.current_example.set_exception(e, context)
@@ -630,4 +493,48 @@ WARNING
630
493
  end
631
494
  end
632
495
  end
496
+
497
+ # Namespace for the example group subclasses generated by top-level `describe`.
498
+ module ExampleGroups
499
+ def self.assign_const(group)
500
+ base_name = base_name_for(group)
501
+ const_scope = constant_scope_for(group)
502
+ name = disambiguate(base_name, const_scope)
503
+
504
+ const_scope.const_set(name, group)
505
+ end
506
+
507
+ def self.constant_scope_for(group)
508
+ const_scope = group.superclass
509
+ const_scope = self if const_scope == Core::ExampleGroup
510
+ const_scope
511
+ end
512
+
513
+ def self.base_name_for(group)
514
+ return "Anonymous" if group.description.empty?
515
+
516
+ # convert to CamelCase
517
+ name = ' ' + group.description
518
+ name.gsub!(/[^0-9a-zA-Z]+([0-9a-zA-Z])/) { $1.upcase }
519
+
520
+ name.lstrip! # Remove leading whitespace
521
+ name.gsub!(/\W/, '') # JRuby, RBX and others don't like non-ascii in const names
522
+
523
+ # Ruby requires first const letter to be A-Z. Use `Nested`
524
+ # as necessary to enforce that.
525
+ name.gsub!(/\A([^A-Z]|\z)/, 'Nested\1')
526
+
527
+ name
528
+ end
529
+
530
+ def self.disambiguate(name, const_scope)
531
+ return name unless const_scope.const_defined?(name)
532
+
533
+ # Add a trailing number if needed to disambiguate from an existing constant.
534
+ name << "_2"
535
+ name.next! while const_scope.const_defined?(name)
536
+ name
537
+ end
538
+ end
633
539
  end
540
+