rspec-core 2.99.0 → 3.0.0

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 (216) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +1 -0
  4. data/Changelog.md +339 -1
  5. data/License.txt +1 -0
  6. data/README.md +19 -37
  7. data/exe/rspec +2 -23
  8. data/lib/rspec/core/backport_random.rb +336 -0
  9. data/lib/rspec/core/backtrace_formatter.rb +70 -0
  10. data/lib/rspec/core/configuration.rb +479 -577
  11. data/lib/rspec/core/configuration_options.rb +71 -54
  12. data/lib/rspec/core/drb.rb +111 -0
  13. data/lib/rspec/core/dsl.rb +86 -18
  14. data/lib/rspec/core/example.rb +267 -119
  15. data/lib/rspec/core/example_group.rb +381 -393
  16. data/lib/rspec/core/filter_manager.rb +133 -114
  17. data/lib/rspec/core/flat_map.rb +18 -0
  18. data/lib/rspec/core/formatters/base_formatter.rb +51 -125
  19. data/lib/rspec/core/formatters/base_text_formatter.rb +34 -286
  20. data/lib/rspec/core/formatters/console_codes.rb +24 -1
  21. data/lib/rspec/core/formatters/deprecation_formatter.rb +25 -26
  22. data/lib/rspec/core/formatters/documentation_formatter.rb +27 -25
  23. data/lib/rspec/core/formatters/helpers.rb +14 -36
  24. data/lib/rspec/core/formatters/html_formatter.rb +58 -65
  25. data/lib/rspec/core/formatters/html_printer.rb +12 -18
  26. data/lib/rspec/core/formatters/json_formatter.rb +54 -31
  27. data/lib/rspec/core/formatters/profile_formatter.rb +67 -0
  28. data/lib/rspec/core/formatters/progress_formatter.rb +11 -15
  29. data/lib/rspec/core/formatters/snippet_extractor.rb +22 -11
  30. data/lib/rspec/core/formatters.rb +90 -43
  31. data/lib/rspec/core/hooks.rb +325 -270
  32. data/lib/rspec/core/memoized_helpers.rb +45 -156
  33. data/lib/rspec/core/metadata.rb +284 -236
  34. data/lib/rspec/core/metadata_filter.rb +86 -0
  35. data/lib/rspec/core/mocking_adapters/flexmock.rb +29 -0
  36. data/lib/rspec/core/{mocking/with_mocha.rb → mocking_adapters/mocha.rb} +19 -16
  37. data/lib/rspec/core/mocking_adapters/null.rb +12 -0
  38. data/lib/rspec/core/mocking_adapters/rr.rb +29 -0
  39. data/lib/rspec/core/mocking_adapters/rspec.rb +30 -0
  40. data/lib/rspec/core/notifications.rb +511 -0
  41. data/lib/rspec/core/option_parser.rb +49 -74
  42. data/lib/rspec/core/ordering.rb +156 -0
  43. data/lib/rspec/core/pending.rb +94 -96
  44. data/lib/rspec/core/project_initializer/.rspec +3 -0
  45. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +78 -0
  46. data/lib/rspec/core/project_initializer.rb +24 -64
  47. data/lib/rspec/core/rake_task.rb +44 -130
  48. data/lib/rspec/core/reporter.rb +76 -59
  49. data/lib/rspec/core/ruby_project.rb +2 -1
  50. data/lib/rspec/core/runner.rb +117 -52
  51. data/lib/rspec/core/shared_context.rb +10 -10
  52. data/lib/rspec/core/shared_example_group.rb +108 -121
  53. data/lib/rspec/core/version.rb +3 -1
  54. data/lib/rspec/core/warnings.rb +40 -0
  55. data/lib/rspec/core/world.rb +66 -10
  56. data/lib/rspec/core.rb +64 -104
  57. data.tar.gz.sig +3 -0
  58. metadata +75 -322
  59. metadata.gz.sig +1 -0
  60. data/exe/autospec +0 -13
  61. data/features/Autotest.md +0 -38
  62. data/features/README.md +0 -17
  63. data/features/Upgrade.md +0 -364
  64. data/features/command_line/README.md +0 -28
  65. data/features/command_line/example_name_option.feature +0 -97
  66. data/features/command_line/exit_status.feature +0 -82
  67. data/features/command_line/format_option.feature +0 -75
  68. data/features/command_line/init.feature +0 -18
  69. data/features/command_line/line_number_appended_to_path.feature +0 -140
  70. data/features/command_line/line_number_option.feature +0 -53
  71. data/features/command_line/order.feature +0 -26
  72. data/features/command_line/pattern_option.feature +0 -49
  73. data/features/command_line/rake_task.feature +0 -122
  74. data/features/command_line/require_option.feature +0 -43
  75. data/features/command_line/ruby.feature +0 -22
  76. data/features/command_line/tag.feature +0 -98
  77. data/features/command_line/warnings_option.feature +0 -29
  78. data/features/configuration/alias_example_to.feature +0 -48
  79. data/features/configuration/backtrace_clean_patterns.feature +0 -102
  80. data/features/configuration/custom_settings.feature +0 -84
  81. data/features/configuration/default_path.feature +0 -38
  82. data/features/configuration/deprecation_stream.feature +0 -58
  83. data/features/configuration/fail_fast.feature +0 -77
  84. data/features/configuration/failure_exit_code.feature +0 -36
  85. data/features/configuration/order_and_seed.feature +0 -3
  86. data/features/configuration/output_stream.feature +0 -24
  87. data/features/configuration/pattern.feature +0 -38
  88. data/features/configuration/profile.feature +0 -220
  89. data/features/configuration/read_options_from_file.feature +0 -90
  90. data/features/configuration/run_all_when_everything_filtered.feature +0 -76
  91. data/features/configuration/show_failures_in_pending_blocks.feature +0 -61
  92. data/features/configuration/treat_symbols_as_metadata_keys_with_true_values.feature +0 -52
  93. data/features/example_groups/basic_structure.feature +0 -55
  94. data/features/example_groups/shared_context.feature +0 -74
  95. data/features/example_groups/shared_examples.feature +0 -294
  96. data/features/expectation_framework_integration/configure_expectation_framework.feature +0 -197
  97. data/features/filtering/exclusion_filters.feature +0 -138
  98. data/features/filtering/if_and_unless.feature +0 -168
  99. data/features/filtering/inclusion_filters.feature +0 -105
  100. data/features/formatters/configurable_colors.feature +0 -31
  101. data/features/formatters/custom_formatter.feature +0 -36
  102. data/features/formatters/json_formatter.feature +0 -30
  103. data/features/formatters/text_formatter.feature +0 -46
  104. data/features/helper_methods/arbitrary_methods.feature +0 -40
  105. data/features/helper_methods/let.feature +0 -50
  106. data/features/helper_methods/modules.feature +0 -149
  107. data/features/hooks/around_hooks.feature +0 -343
  108. data/features/hooks/before_and_after_hooks.feature +0 -427
  109. data/features/hooks/filtering.feature +0 -234
  110. data/features/metadata/current_example.feature +0 -56
  111. data/features/metadata/described_class.feature +0 -17
  112. data/features/metadata/user_defined.feature +0 -113
  113. data/features/mock_framework_integration/use_any_framework.feature +0 -106
  114. data/features/mock_framework_integration/use_flexmock.feature +0 -96
  115. data/features/mock_framework_integration/use_mocha.feature +0 -97
  116. data/features/mock_framework_integration/use_rr.feature +0 -98
  117. data/features/mock_framework_integration/use_rspec.feature +0 -97
  118. data/features/pending/pending_examples.feature +0 -229
  119. data/features/spec_files/arbitrary_file_suffix.feature +0 -13
  120. data/features/step_definitions/additional_cli_steps.rb +0 -49
  121. data/features/subject/attribute_of_subject.feature +0 -124
  122. data/features/subject/explicit_subject.feature +0 -101
  123. data/features/subject/implicit_subject.feature +0 -63
  124. data/features/subject/one_liner_syntax.feature +0 -71
  125. data/features/support/env.rb +0 -14
  126. data/features/support/rubinius.rb +0 -6
  127. data/lib/autotest/discover.rb +0 -10
  128. data/lib/autotest/rspec2.rb +0 -77
  129. data/lib/rspec/core/backtrace_cleaner.rb +0 -46
  130. data/lib/rspec/core/backward_compatibility.rb +0 -55
  131. data/lib/rspec/core/caller_filter.rb +0 -60
  132. data/lib/rspec/core/command_line.rb +0 -47
  133. data/lib/rspec/core/deprecated_mutable_array_proxy.rb +0 -32
  134. data/lib/rspec/core/deprecation.rb +0 -26
  135. data/lib/rspec/core/drb_command_line.rb +0 -26
  136. data/lib/rspec/core/drb_options.rb +0 -87
  137. data/lib/rspec/core/extensions/instance_eval_with_args.rb +0 -44
  138. data/lib/rspec/core/extensions/kernel.rb +0 -9
  139. data/lib/rspec/core/extensions/module_eval_with_args.rb +0 -38
  140. data/lib/rspec/core/extensions/ordered.rb +0 -27
  141. data/lib/rspec/core/formatters/text_mate_formatter.rb +0 -34
  142. data/lib/rspec/core/metadata_hash_builder.rb +0 -97
  143. data/lib/rspec/core/mocking/with_absolutely_nothing.rb +0 -11
  144. data/lib/rspec/core/mocking/with_flexmock.rb +0 -27
  145. data/lib/rspec/core/mocking/with_rr.rb +0 -27
  146. data/lib/rspec/core/mocking/with_rspec.rb +0 -27
  147. data/lib/rspec/core/shared_example_group/collection.rb +0 -45
  148. data/spec/autotest/discover_spec.rb +0 -49
  149. data/spec/autotest/failed_results_re_spec.rb +0 -45
  150. data/spec/autotest/rspec_spec.rb +0 -133
  151. data/spec/command_line/order_spec.rb +0 -204
  152. data/spec/rspec/core/backtrace_cleaner_spec.rb +0 -68
  153. data/spec/rspec/core/caller_filter_spec.rb +0 -58
  154. data/spec/rspec/core/command_line_spec.rb +0 -127
  155. data/spec/rspec/core/command_line_spec_output.txt +0 -0
  156. data/spec/rspec/core/configuration_options_spec.rb +0 -417
  157. data/spec/rspec/core/configuration_spec.rb +0 -2072
  158. data/spec/rspec/core/deprecation_spec.rb +0 -27
  159. data/spec/rspec/core/deprecations_spec.rb +0 -59
  160. data/spec/rspec/core/drb_command_line_spec.rb +0 -102
  161. data/spec/rspec/core/drb_options_spec.rb +0 -193
  162. data/spec/rspec/core/dsl_spec.rb +0 -25
  163. data/spec/rspec/core/example_group_spec.rb +0 -1337
  164. data/spec/rspec/core/example_spec.rb +0 -502
  165. data/spec/rspec/core/filter_manager_spec.rb +0 -246
  166. data/spec/rspec/core/formatters/base_formatter_spec.rb +0 -108
  167. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +0 -524
  168. data/spec/rspec/core/formatters/console_codes_spec.rb +0 -50
  169. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +0 -263
  170. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +0 -89
  171. data/spec/rspec/core/formatters/helpers_spec.rb +0 -104
  172. data/spec/rspec/core/formatters/html_formatted.html +0 -397
  173. data/spec/rspec/core/formatters/html_formatter_spec.rb +0 -131
  174. data/spec/rspec/core/formatters/json_formatter_spec.rb +0 -115
  175. data/spec/rspec/core/formatters/progress_formatter_spec.rb +0 -30
  176. data/spec/rspec/core/formatters/snippet_extractor_spec.rb +0 -26
  177. data/spec/rspec/core/formatters/text_mate_formatted.html +0 -397
  178. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +0 -107
  179. data/spec/rspec/core/hooks_filtering_spec.rb +0 -227
  180. data/spec/rspec/core/hooks_spec.rb +0 -269
  181. data/spec/rspec/core/kernel_extensions_spec.rb +0 -9
  182. data/spec/rspec/core/memoized_helpers_spec.rb +0 -776
  183. data/spec/rspec/core/metadata_spec.rb +0 -514
  184. data/spec/rspec/core/option_parser_spec.rb +0 -297
  185. data/spec/rspec/core/pending_example_spec.rb +0 -260
  186. data/spec/rspec/core/pending_spec.rb +0 -27
  187. data/spec/rspec/core/project_initializer_spec.rb +0 -130
  188. data/spec/rspec/core/rake_task_spec.rb +0 -202
  189. data/spec/rspec/core/reporter_spec.rb +0 -167
  190. data/spec/rspec/core/resources/a_bar.rb +0 -0
  191. data/spec/rspec/core/resources/a_foo.rb +0 -0
  192. data/spec/rspec/core/resources/a_spec.rb +0 -1
  193. data/spec/rspec/core/resources/custom_example_group_runner.rb +0 -14
  194. data/spec/rspec/core/resources/formatter_specs.rb +0 -60
  195. data/spec/rspec/core/resources/utf8_encoded.rb +0 -8
  196. data/spec/rspec/core/rspec_matchers_spec.rb +0 -45
  197. data/spec/rspec/core/ruby_project_spec.rb +0 -26
  198. data/spec/rspec/core/runner_spec.rb +0 -82
  199. data/spec/rspec/core/shared_context_spec.rb +0 -114
  200. data/spec/rspec/core/shared_example_group/collection_spec.rb +0 -70
  201. data/spec/rspec/core/shared_example_group_spec.rb +0 -138
  202. data/spec/rspec/core/world_spec.rb +0 -142
  203. data/spec/rspec/core_spec.rb +0 -108
  204. data/spec/spec_helper.rb +0 -135
  205. data/spec/support/config_options_helper.rb +0 -15
  206. data/spec/support/helper_methods.rb +0 -55
  207. data/spec/support/in_sub_process.rb +0 -37
  208. data/spec/support/isolate_load_path_mutation.rb +0 -6
  209. data/spec/support/isolated_directory.rb +0 -10
  210. data/spec/support/isolated_home_directory.rb +0 -16
  211. data/spec/support/matchers.rb +0 -65
  212. data/spec/support/mathn_integration_support.rb +0 -12
  213. data/spec/support/sandboxed_mock_space.rb +0 -116
  214. data/spec/support/shared_example_groups.rb +0 -42
  215. data/spec/support/silence_dsl_deprecations.rb +0 -32
  216. data/spec/support/spec_files.rb +0 -44
@@ -12,183 +12,278 @@ module RSpec
12
12
  # The object returned by `it "does something"` is an instance of Example,
13
13
  # which serves as a wrapper for an instance of the ExampleGroup in which it
14
14
  # is declared.
15
+ #
16
+ # Example group bodies (e.g. `describe` or `context` blocks) are evaluated
17
+ # in the context of a new subclass of ExampleGroup. Individual examples are
18
+ # evalutaed in the context of an instance of the specific ExampleGroup subclass
19
+ # to which they belong.
20
+ #
21
+ # Besides the class methods defined here, there are other interesting macros
22
+ # defined in {Hooks}, {MemoizedHelpers::ClassMethods} and {SharedExampleGroup}.
23
+ # There are additional instance methods available to your examples defined in
24
+ # {MemoizedHelpers} and {Pending}.
15
25
  class ExampleGroup
16
- extend MetadataHashBuilder::WithDeprecationWarning
17
- extend Extensions::ModuleEvalWithArgs
18
26
  extend Hooks
19
27
 
20
28
  include MemoizedHelpers
21
- include Extensions::InstanceEvalWithArgs
29
+ extend MemoizedHelpers::ClassMethods
22
30
  include Pending
23
- include SharedExampleGroup
24
- extend SharedExampleGroup
31
+ extend SharedExampleGroup
25
32
 
26
- # @private
27
- def self.world
28
- RSpec.world
33
+ unless respond_to?(:define_singleton_method)
34
+ # @private
35
+ def self.define_singleton_method(*a, &b)
36
+ (class << self; self; end).__send__(:define_method, *a, &b)
37
+ end
29
38
  end
30
39
 
31
- # @private
32
- def self.register
33
- world.register(self)
40
+ # @!group Metadata
41
+
42
+ # The [Metadata](Metadata) object associated with this group.
43
+ # @see Metadata
44
+ def self.metadata
45
+ @metadata if defined?(@metadata)
34
46
  end
35
47
 
36
- class << self
37
- # @private
38
- def self.delegate_to_metadata(*names)
39
- names.each do |name|
40
- define_method name do
41
- metadata[:example_group][name]
42
- end
43
- end
44
- end
48
+ # @private
49
+ # @return [Metadata] belonging to the parent of a nested {ExampleGroup}
50
+ def self.superclass_metadata
51
+ @superclass_metadata ||= self.superclass.respond_to?(:metadata) ? self.superclass.metadata : nil
52
+ end
45
53
 
46
- def description
47
- description = metadata[:example_group][:description]
48
- RSpec.configuration.format_docstrings_block.call(description)
54
+ # @private
55
+ def self.delegate_to_metadata(*names)
56
+ names.each do |name|
57
+ define_singleton_method(name) { metadata.fetch(name) }
49
58
  end
59
+ end
50
60
 
51
- delegate_to_metadata :described_class, :file_path
61
+ delegate_to_metadata :described_class, :file_path, :location
52
62
 
53
- # @private
54
- def display_name
55
- RSpec.deprecate('`RSpec::Core::ExampleGroup.display_name`',
56
- :replacement => "`RSpec::Core::ExampleGroup.description`")
57
- description
58
- end
63
+ # @return [String] the current example group description
64
+ def self.description
65
+ description = metadata[:description]
66
+ RSpec.configuration.format_docstrings_block.call(description)
67
+ end
59
68
 
60
- # @private
61
- def describes
62
- RSpec.deprecate('`RSpec::Core::ExampleGroup.describes`',
63
- :replacement => "`RSpec::Core::ExampleGroup.described_class`")
64
- described_class
65
- end
69
+ # Returns the class or module passed to the `describe` method (or alias).
70
+ # Returns nil if the subject is not a class or module.
71
+ # @example
72
+ # describe Thing do
73
+ # it "does something" do
74
+ # described_class == Thing
75
+ # end
76
+ # end
77
+ #
78
+ #
79
+ def described_class
80
+ self.class.described_class
66
81
  end
67
82
 
83
+ # @!endgroup
84
+
85
+ # @!group Defining Examples
86
+
68
87
  # @private
69
88
  # @macro [attach] define_example_method
70
- # @param [String] name
71
- # @param [Hash] extra_options
72
- # @param [Block] implementation
89
+ # @!scope class
90
+ # @param name [String]
91
+ # @param extra_options [Hash]
92
+ # @param implementation [Block]
73
93
  # @yield [Example] the example object
94
+ # @example
95
+ # $1 do
96
+ # end
97
+ #
98
+ # $1 "does something" do
99
+ # end
100
+ #
101
+ # $1 "does something", :with => 'additional metadata' do
102
+ # end
103
+ #
104
+ # $1 "does something" do |ex|
105
+ # # ex is the Example object that contains metadata about the example
106
+ # end
74
107
  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)
94
- 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})
98
- examples << RSpec::Core::Example.new(self, desc, options, block)
99
- examples.last
108
+ define_singleton_method(name) do |*all_args, &block|
109
+ desc, *args = *all_args
110
+ options = Metadata.build_hash_from(args)
111
+ options.update(:skip => RSpec::Core::Pending::NOT_YET_IMPLEMENTED) unless block
112
+ options.update(extra_options)
113
+
114
+ # Metadata inheritance normally happens in `Example#initialize`,
115
+ # but for `:pending` specifically we need it earlier.
116
+ pending_metadata = options[:pending] || metadata[:pending]
117
+
118
+ if pending_metadata
119
+ options, block = ExampleGroup.pending_metadata_and_block_for(
120
+ options.merge(:pending => pending_metadata),
121
+ block
122
+ )
100
123
  end
101
- END_RUBY
124
+
125
+ examples << RSpec::Core::Example.new(self, desc, options, block)
126
+ examples.last
127
+ end
102
128
  end
103
129
 
104
130
  # 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
131
  define_example_method :example
119
132
  # Defines an example within a group.
120
- # @example
133
+ # This is the primary API to define a code example.
121
134
  define_example_method :it
122
135
  # 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`.
136
+ # Useful for when your docstring does not read well off of `it`.
137
+ # @example
138
+ # RSpec.describe MyClass do
139
+ # specify "#do_something is deprecated" do
140
+ # # ...
141
+ # end
142
+ # end
126
143
  define_example_method :specify
127
144
 
128
- # Shortcut to define an example with `:focus` => true
145
+ # Shortcut to define an example with `:focus => true`
129
146
  # @see example
130
- define_example_method :focus, :focused => true, :focus => true
131
- # Shortcut to define an example with `:focus` => true
147
+ define_example_method :focus, :focus => true
148
+ # Shortcut to define an example with `:focus => true`
132
149
  # @see example
133
- define_example_method :fit, :focused => true, :focus => true
134
-
135
- # Shortcut to define an example with :pending => true
150
+ define_example_method :fexample, :focus => true
151
+ # Shortcut to define an example with `:focus => true`
136
152
  # @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.
153
+ define_example_method :fit, :focus => true
154
+ # Shortcut to define an example with `:focus => true`
140
155
  # @see example
141
- define_example_method :skip, :pending => true
142
- # Shortcut to define an example with :pending => 'Temporarily disabled with xexample'
156
+ define_example_method :fspecify, :focus => true
157
+ # Shortcut to define an example with `:skip => 'Temporarily skipped with xexample'`
143
158
  # @see example
144
- define_example_method :xexample, :pending => 'Temporarily disabled with xexample'
145
- # Shortcut to define an example with :pending => 'Temporarily disabled with xit'
159
+ define_example_method :xexample, :skip => 'Temporarily skipped with xexample'
160
+ # Shortcut to define an example with `:skip => 'Temporarily skipped with xit'`
146
161
  # @see example
147
- define_example_method :xit, :pending => 'Temporarily disabled with xit'
148
- # Shortcut to define an example with :pending => 'Temporarily disabled with xspecify'
162
+ define_example_method :xit, :skip => 'Temporarily skipped with xit'
163
+ # Shortcut to define an example with `:skip => 'Temporarily skipped with xspecify'`
149
164
  # @see example
150
- define_example_method :xspecify, :pending => 'Temporarily disabled with xspecify'
151
-
152
- # Shortcut to define an example with `:focus` => true
165
+ define_example_method :xspecify, :skip => 'Temporarily skipped with xspecify'
166
+ # Shortcut to define an example with `:skip => true`
167
+ # @see example
168
+ define_example_method :skip, :skip => true
169
+ # Shortcut to define an example with `:pending => true`
153
170
  # @see example
154
- def self.focused(desc=nil, *args, &block)
155
- RSpec.deprecate("`RSpec::Core::ExampleGroup.focused`",
156
- :replacement => "`RSpec::Core::ExampleGroup.focus`")
171
+ define_example_method :pending, :pending => true
157
172
 
158
- metadata = Hash === args.last ? args.pop : {}
159
- metadata.merge!(:focus => true, :focused => true)
160
- args << metadata
173
+ # @!endgroup
161
174
 
162
- example(desc, *args, &block)
163
- end
175
+ # @!group Defining Example Groups
164
176
 
165
- # Works like `alias_method :name, :example` with the added benefit of
166
- # assigning default metadata to the generated example.
177
+ # @private
178
+ # @macro [attach] alias_example_group_to
179
+ # @!scope class
180
+ # @param name [String] The example group doc string
181
+ # @param metadata [Hash] Additional metadata to attach to the example group
182
+ # @yield The example group definition
183
+ #
184
+ # Generates a subclass of this example group which inherits
185
+ # everything except the examples themselves.
186
+ #
187
+ # @example
188
+ #
189
+ # RSpec.describe "something" do # << This describe method is defined in
190
+ # # << RSpec::Core::DSL, included in the
191
+ # # << global namespace (optional)
192
+ # before do
193
+ # do_something_before
194
+ # end
167
195
  #
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
196
+ # let(:thing) { Thing.new }
197
+ #
198
+ # $1 "attribute (of something)" do
199
+ # # examples in the group get the before hook
200
+ # # declared above, and can access `thing`
201
+ # end
202
+ # end
203
+ #
204
+ # @see DSL#describe
205
+ def self.define_example_group_method(name, metadata={})
206
+ define_singleton_method(name) do |*args, &example_group_block|
207
+ thread_data = RSpec.thread_local_metadata
208
+ top_level = self == ExampleGroup
209
+
210
+ if top_level
211
+ if thread_data[:in_example_group]
212
+ raise "Creating an isolated context from within a context is " +
213
+ "not allowed. Change `RSpec.#{name}` to `#{name}` or " +
214
+ "move this to a top-level scope."
215
+ end
216
+
217
+ thread_data[:in_example_group] = true
218
+ end
219
+
220
+ begin
221
+
222
+ description = args.shift
223
+ combined_metadata = metadata.dup
224
+ combined_metadata.merge!(args.pop) if args.last.is_a? Hash
225
+ args << combined_metadata
226
+
227
+ subclass(self, description, args, &example_group_block).tap do |child|
228
+ children << child
229
+ end
230
+
231
+ ensure
232
+ thread_data.delete(:in_example_group) if top_level
233
+ end
234
+ end
235
+
236
+ RSpec::Core::DSL.expose_example_group_alias(name)
176
237
  end
177
238
 
239
+ define_example_group_method :example_group
240
+
241
+ # An alias of `example_group`. Generally used when grouping
242
+ # examples by a thing you are describing (e.g. an object, class or method).
243
+ # @see example_group
244
+ define_example_group_method :describe
245
+
246
+ # An alias of `example_group`. Generally used when grouping examples
247
+ # contextually (e.g. "with xyz", "when xyz" or "if xyz").
248
+ # @see example_group
249
+ define_example_group_method :context
250
+
251
+ # Shortcut to temporarily make an example group skipped.
252
+ # @see example_group
253
+ define_example_group_method :xdescribe, :skip => "Temporarily skipped with xdescribe"
254
+
255
+ # Shortcut to temporarily make an example group skipped.
256
+ # @see example_group
257
+ define_example_group_method :xcontext, :skip => "Temporarily skipped with xcontext"
258
+
259
+ # Shortcut to define an example group with `:focus => true`.
260
+ # @see example_group
261
+ define_example_group_method :fdescribe, :focus => true
262
+
263
+ # Shortcut to define an example group with `:focus => true`.
264
+ # @see example_group
265
+ define_example_group_method :fcontext, :focus => true
266
+
267
+ # @!endgroup
268
+
269
+ # @!group Including Shared Example Groups
270
+
178
271
  # @private
179
272
  # @macro [attach] define_nested_shared_group_method
273
+ # @!scope class
180
274
  #
181
275
  # @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
186
- find_and_eval_shared("examples", name, *args, &customization_block)
187
- end
188
- group.metadata[:shared_group_name] = name
189
- group
276
+ def self.define_nested_shared_group_method(new_name, report_label="it should behave like")
277
+ define_singleton_method(new_name) do |name, *args, &customization_block|
278
+ # Pass :caller so the :location metadata is set properly...
279
+ # otherwise, it'll be set to the next line because that's
280
+ # the block's source_location.
281
+ group = example_group("#{report_label} #{name}", :caller => caller) do
282
+ find_and_eval_shared("examples", name, *args, &customization_block)
190
283
  end
191
- END_RUBY
284
+ group.metadata[:shared_group_name] = name
285
+ group
286
+ end
192
287
  end
193
288
 
194
289
  # Generates a nested example group and includes the shared content
@@ -198,19 +293,6 @@ module RSpec
198
293
  # mapped to `name` in the nested group.
199
294
  define_nested_shared_group_method :it_should_behave_like
200
295
 
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
212
- end
213
-
214
296
  # Includes shared content mapped to `name` directly in the group in which
215
297
  # it is declared, as opposed to `it_behaves_like`, which creates a nested
216
298
  # group. If given a block, that block is also eval'd in the current context.
@@ -229,156 +311,75 @@ module RSpec
229
311
  find_and_eval_shared("examples", name, *args, &block)
230
312
  end
231
313
 
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
314
  # @private
265
315
  def self.find_and_eval_shared(label, name, *args, &customization_block)
266
- raise ArgumentError, "Could not find shared #{label} #{name.inspect}" unless
267
- shared_block = shared_example_groups[name]
268
-
269
- warn_unexpected_args(label, name, args, shared_block)
316
+ unless shared_block = RSpec.world.shared_example_group_registry.find(parent_groups, name)
317
+ raise ArgumentError, "Could not find shared #{label} #{name.inspect}"
318
+ end
270
319
 
271
- module_eval_with_args(*args, &shared_block)
272
- module_eval(&customization_block) if customization_block
320
+ module_exec(*args, &shared_block)
321
+ module_exec(&customization_block) if customization_block
273
322
  end
274
323
 
275
- # @private
276
- def self.examples
277
- @examples ||= []
278
- end
324
+ # @!endgroup
279
325
 
280
326
  # @private
281
- def self.filtered_examples
282
- world.filtered_examples[self]
283
- end
327
+ def self.subclass(parent, description, args, &example_group_block)
328
+ subclass = Class.new(parent)
329
+ subclass.set_it_up(description, *args, &example_group_block)
330
+ ExampleGroups.assign_const(subclass)
331
+ subclass.module_exec(&example_group_block) if example_group_block
284
332
 
285
- # @private
286
- def self.descendant_filtered_examples
287
- @descendant_filtered_examples ||= filtered_examples + children.inject([]){|l,c| l + c.descendant_filtered_examples}
288
- end
333
+ # The LetDefinitions module must be included _after_ other modules
334
+ # to ensure that it takes precedence when there are name collisions.
335
+ # Thus, we delay including it until after the example group block
336
+ # has been eval'd.
337
+ MemoizedHelpers.define_helpers_on(subclass)
289
338
 
290
- # The [Metadata](Metadata) object associated with this group.
291
- # @see Metadata
292
- def self.metadata
293
- @metadata if defined?(@metadata)
339
+ subclass
294
340
  end
295
341
 
296
342
  # @private
297
- # @return [Metadata] belonging to the parent of a nested {ExampleGroup}
298
- def self.superclass_metadata
299
- @superclass_metadata ||= self.superclass.respond_to?(:metadata) ? self.superclass.metadata : nil
300
- end
343
+ def self.set_it_up(*args, &example_group_block)
344
+ # Ruby 1.9 has a bug that can lead to infinite recursion and a
345
+ # SystemStackError if you include a module in a superclass after
346
+ # including it in a subclass: https://gist.github.com/845896
347
+ # To prevent this, we must include any modules in RSpec::Core::ExampleGroup
348
+ # before users create example groups and have a chance to include
349
+ # the same module in a subclass of RSpec::Core::ExampleGroup.
350
+ # So we need to configure example groups here.
351
+ ensure_example_groups_are_configured
301
352
 
302
- # Generates a subclass of this example group which inherits
303
- # everything except the examples themselves.
304
- #
305
- # ## Examples
306
- #
307
- # describe "something" do # << This describe method is defined in
308
- # # << RSpec::Core::DSL, included in the
309
- # # << global namespace
310
- # before do
311
- # do_something_before
312
- # end
313
- #
314
- # let(:thing) { Thing.new }
315
- #
316
- # describe "attribute (of something)" do
317
- # # examples in the group get the before hook
318
- # # declared above, and can access `thing`
319
- # end
320
- # end
321
- #
322
- # @see DSL#describe
323
- 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
353
+ description = args.shift
354
+ user_metadata = Metadata.build_hash_from(args)
355
+ args.unshift(description)
332
356
 
333
- 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
357
+ @metadata = Metadata::ExampleGroupHash.create(
358
+ superclass_metadata, user_metadata, *args, &example_group_block
337
359
  )
338
360
 
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
- )
344
- children << child
345
- child
346
- end
347
-
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 in RSpec 3. If you want this
354
- |to be treated as metadata, pass a description as the first argument.
355
- |(Example group defined at #{call_site})
356
- EOS
357
- end
361
+ hooks.register_globals(self, RSpec.configuration.hooks)
362
+ RSpec.world.configure_group(self)
358
363
  end
359
364
 
360
- class << self
361
- alias_method :context, :describe
365
+ # @private
366
+ def self.examples
367
+ @examples ||= []
362
368
  end
363
369
 
364
370
  # @private
365
- def self.subclass(parent, args, &example_group_block)
366
- subclass = Class.new(parent)
367
- subclass.set_it_up(*args)
368
- subclass.module_eval(&example_group_block) if example_group_block
369
-
370
- # The LetDefinitions module must be included _after_ other modules
371
- # to ensure that it takes precendence when there are name collisions.
372
- # Thus, we delay including it until after the example group block
373
- # has been eval'd.
374
- MemoizedHelpers.define_helpers_on(subclass)
371
+ def self.filtered_examples
372
+ RSpec.world.filtered_examples[self]
373
+ end
375
374
 
376
- subclass
375
+ # @private
376
+ def self.descendant_filtered_examples
377
+ @descendant_filtered_examples ||= filtered_examples + children.inject([]){|l,c| l + c.descendant_filtered_examples}
377
378
  end
378
379
 
379
380
  # @private
380
381
  def self.children
381
- @children ||= [].extend(Extensions::Ordered::ExampleGroups)
382
+ @children ||= []
382
383
  end
383
384
 
384
385
  # @private
@@ -406,124 +407,103 @@ WARNING
406
407
  end
407
408
 
408
409
  # @private
409
- def self.set_it_up(*args)
410
- # Ruby 1.9 has a bug that can lead to infinite recursion and a
411
- # SystemStackError if you include a module in a superclass after
412
- # including it in a subclass: https://gist.github.com/845896
413
- # To prevent this, we must include any modules in RSpec::Core::ExampleGroup
414
- # before users create example groups and have a chance to include
415
- # the same module in a subclass of RSpec::Core::ExampleGroup.
416
- # So we need to configure example groups here.
417
- ensure_example_groups_are_configured
418
-
419
- symbol_description = args.shift if args.first.is_a?(Symbol)
420
- args << build_metadata_hash_from(args)
421
- args.unshift(symbol_description) if symbol_description
422
- @metadata = RSpec::Core::Metadata.new(superclass_metadata).process(*args)
423
- hooks.register_globals(self, RSpec.configuration.hooks)
424
- world.configure_group(self)
425
- end
426
-
427
- # @private
428
- def self.before_all_ivars
429
- @before_all_ivars ||= {}
410
+ def self.before_context_ivars
411
+ @before_context_ivars ||= {}
430
412
  end
431
413
 
432
414
  # @private
433
- def self.store_before_all_ivars(example_group_instance)
415
+ def self.store_before_context_ivars(example_group_instance)
434
416
  return if example_group_instance.instance_variables.empty?
435
417
 
436
418
  example_group_instance.instance_variables.each { |ivar|
437
- before_all_ivars[ivar] = example_group_instance.instance_variable_get(ivar)
419
+ before_context_ivars[ivar] = example_group_instance.instance_variable_get(ivar)
438
420
  }
439
421
  end
440
422
 
441
423
  # @private
442
- def self.assign_before_all_ivars(ivars, example_group_instance)
443
- ivars.each { |ivar, val| example_group_instance.instance_variable_set(ivar, val) }
444
- end
445
-
446
- # @private
447
- def self.run_before_all_hooks(example_group_instance)
424
+ def self.run_before_context_hooks(example_group_instance)
448
425
  return if descendant_filtered_examples.empty?
449
426
  begin
450
- assign_before_all_ivars(superclass.before_all_ivars, example_group_instance)
427
+ set_ivars(example_group_instance, superclass.before_context_ivars)
451
428
 
452
- AllHookMemoizedHash::Before.isolate_for_all_hook(example_group_instance) do
453
- run_hook(:before, :all, example_group_instance)
429
+ ContextHookMemoizedHash::Before.isolate_for_context_hook(example_group_instance) do
430
+ hooks.run(:before, :context, example_group_instance)
454
431
  end
455
432
  ensure
456
- store_before_all_ivars(example_group_instance)
433
+ store_before_context_ivars(example_group_instance)
457
434
  end
458
435
  end
459
436
 
460
437
  # @private
461
- def self.run_around_each_hooks(example, initial_procsy)
462
- run_hook(:around, :each, example, initial_procsy)
463
- end
464
-
465
- # @private
466
- def self.run_before_each_hooks(example)
467
- run_hook(:before, :each, example)
468
- end
469
-
470
- # @private
471
- def self.run_after_each_hooks(example)
472
- run_hook(:after, :each, example)
473
- end
474
-
475
- # @private
476
- def self.run_after_all_hooks(example_group_instance)
438
+ def self.run_after_context_hooks(example_group_instance)
477
439
  return if descendant_filtered_examples.empty?
478
- assign_before_all_ivars(before_all_ivars, example_group_instance)
440
+ set_ivars(example_group_instance, before_context_ivars)
479
441
 
480
- AllHookMemoizedHash::After.isolate_for_all_hook(example_group_instance) do
481
- run_hook(:after, :all, example_group_instance)
442
+ ContextHookMemoizedHash::After.isolate_for_context_hook(example_group_instance) do
443
+ hooks.run(:after, :context, example_group_instance)
482
444
  end
483
445
  end
484
446
 
485
447
  # Runs all the examples in this group
486
448
  def self.run(reporter)
487
- if RSpec.wants_to_quit
488
- RSpec.clear_remaining_example_groups if top_level?
449
+ if RSpec.world.wants_to_quit
450
+ RSpec.world.clear_remaining_example_groups if top_level?
489
451
  return
490
452
  end
491
453
  reporter.example_group_started(self)
492
454
 
493
455
  begin
494
- run_before_all_hooks(new)
456
+ run_before_context_hooks(new)
495
457
  result_for_this_group = run_examples(reporter)
496
- results_for_descendants = children.ordered.map {|child| child.run(reporter)}.all?
458
+ results_for_descendants = ordering_strategy.order(children).map { |child| child.run(reporter) }.all?
497
459
  result_for_this_group && results_for_descendants
460
+ rescue Pending::SkipDeclaredInExample => ex
461
+ for_filtered_examples(reporter) {|example| example.skip_with_exception(reporter, ex) }
498
462
  rescue Exception => ex
499
- RSpec.wants_to_quit = true if fail_fast?
500
- fail_filtered_examples(ex, reporter)
463
+ RSpec.world.wants_to_quit = true if fail_fast?
464
+ for_filtered_examples(reporter) {|example| example.fail_with_exception(reporter, ex) }
501
465
  ensure
502
- run_after_all_hooks(new)
503
- before_all_ivars.clear
466
+ run_after_context_hooks(new)
467
+ before_context_ivars.clear
504
468
  reporter.example_group_finished(self)
505
469
  end
506
470
  end
507
471
 
472
+ # @private
473
+ def self.ordering_strategy
474
+ order = metadata.fetch(:order, :global)
475
+ registry = RSpec.configuration.ordering_registry
476
+
477
+ registry.fetch(order) do
478
+ warn <<-WARNING.gsub(/^ +\|/, '')
479
+ |WARNING: Ignoring unknown ordering specified using `:order => #{order.inspect}` metadata.
480
+ | Falling back to configured global ordering.
481
+ | Unrecognized ordering specified at: #{location}
482
+ WARNING
483
+
484
+ registry.fetch(:global)
485
+ end
486
+ end
487
+
508
488
  # @private
509
489
  def self.run_examples(reporter)
510
- filtered_examples.ordered.map do |example|
511
- next if RSpec.wants_to_quit
490
+ ordering_strategy.order(filtered_examples).map do |example|
491
+ next if RSpec.world.wants_to_quit
512
492
  instance = new
513
- set_ivars(instance, before_all_ivars)
493
+ set_ivars(instance, before_context_ivars)
514
494
  succeeded = example.run(instance, reporter)
515
- RSpec.wants_to_quit = true if fail_fast? && !succeeded
495
+ RSpec.world.wants_to_quit = true if fail_fast? && !succeeded
516
496
  succeeded
517
497
  end.all?
518
498
  end
519
499
 
520
500
  # @private
521
- def self.fail_filtered_examples(exception, reporter)
522
- filtered_examples.each { |example| example.fail_with_exception(reporter, exception) }
501
+ def self.for_filtered_examples(reporter, &block)
502
+ filtered_examples.each(&block)
523
503
 
524
504
  children.each do |child|
525
505
  reporter.example_group_started(child)
526
- child.fail_filtered_examples(exception, reporter)
506
+ child.for_filtered_examples(reporter, &block)
527
507
  reporter.example_group_finished(child)
528
508
  end
529
509
  false
@@ -536,17 +516,17 @@ WARNING
536
516
 
537
517
  # @private
538
518
  def self.any_apply?(filters)
539
- metadata.any_apply?(filters)
519
+ MetadataFilter.any_apply?(filters, metadata)
540
520
  end
541
521
 
542
522
  # @private
543
523
  def self.all_apply?(filters)
544
- metadata.all_apply?(filters)
524
+ MetadataFilter.all_apply?(filters, metadata)
545
525
  end
546
526
 
547
527
  # @private
548
528
  def self.declaration_line_numbers
549
- @declaration_line_numbers ||= [metadata[:example_group][:line_number]] +
529
+ @declaration_line_numbers ||= [metadata[:line_number]] +
550
530
  examples.collect {|e| e.metadata[:line_number]} +
551
531
  children.inject([]) {|l,c| l + c.declaration_line_numbers}
552
532
  end
@@ -561,72 +541,80 @@ WARNING
561
541
  ivars.each {|name, value| instance.instance_variable_set(name, value)}
562
542
  end
563
543
 
564
- def example=(current_example)
565
- RSpec.current_example = current_example
566
- end
544
+ # @private
545
+ def self.pending_metadata_and_block_for(options, block)
546
+ if String === options[:pending]
547
+ reason = options[:pending]
548
+ else
549
+ options[:pending] = true
550
+ reason = RSpec::Core::Pending::NO_REASON_GIVEN
551
+ end
567
552
 
568
- # @deprecated use a block argument
569
- def example
570
- warn_deprecation_of_example_accessor :example
571
- RSpec.current_example
572
- end
553
+ # Assign :caller so that the callback's source_location isn't used
554
+ # as the example location.
555
+ options[:caller] ||= Metadata.backtrace_from(block)
573
556
 
574
- # @deprecated use a block argument
575
- def running_example
576
- warn_deprecation_of_example_accessor :running_example
577
- RSpec.current_example
578
- end
557
+ # This will fail if no block is provided, which is effectively the
558
+ # same as failing the example so it will be marked correctly as
559
+ # pending.
560
+ callback = Proc.new { pending(reason); instance_exec(&block) }
579
561
 
580
- def warn_deprecation_of_example_accessor(name)
581
- RSpec.warn_deprecation(<<-EOS.gsub(/^\s*\|/, ''))
582
- |RSpec::Core::ExampleGroup##{name} is deprecated and will be removed
583
- |in RSpec 3. There are a few options for what you can use instead:
584
- |
585
- | - rspec-core's DSL methods (`it`, `before`, `after`, `let`, `subject`, etc)
586
- | now yield the example as a block argument, and that is the recommended
587
- | way to access the current example from those contexts.
588
- | - The current example is now exposed via `RSpec.current_example`,
589
- | which is accessible from any context.
590
- | - If you can't update the code at this call site (e.g. because it is in
591
- | an extension gem), you can use this snippet to continue making this
592
- | method available in RSpec 2.99 and RSpec 3:
593
- |
594
- | RSpec.configure do |c|
595
- | c.expose_current_running_example_as :#{name}
596
- | end
597
- |
598
- |(Called from #{CallerFilter.first_non_rspec_line})
599
- EOS
562
+ return options, callback
600
563
  end
564
+ end
601
565
 
602
- # Returns the class or module passed to the `describe` method (or alias).
603
- # Returns nil if the subject is not a class or module.
604
- # @example
605
- # describe Thing do
606
- # it "does something" do
607
- # described_class == Thing
608
- # end
609
- # end
610
- #
611
- #
612
- def described_class
613
- self.class.described_class
566
+ # @private
567
+ # Unnamed example group used by `SuiteHookContext`.
568
+ class AnonymousExampleGroup < ExampleGroup
569
+ def self.metadata
570
+ {}
614
571
  end
572
+ end
573
+ end
615
574
 
616
- # @private
617
- # instance_evals the block, capturing and reporting an exception if
618
- # raised
619
- def instance_eval_with_rescue(example, context = nil, &hook)
620
- begin
621
- instance_eval_with_args(example, &hook)
622
- rescue Exception => e
623
- if RSpec.current_example
624
- RSpec.current_example.set_exception(e, context)
625
- else
626
- raise
627
- end
628
- end
629
- end
575
+ # @private
576
+ #
577
+ # Namespace for the example group subclasses generated by top-level `describe`.
578
+ module ExampleGroups
579
+ def self.assign_const(group)
580
+ base_name = base_name_for(group)
581
+ const_scope = constant_scope_for(group)
582
+ name = disambiguate(base_name, const_scope)
583
+
584
+ const_scope.const_set(name, group)
585
+ end
586
+
587
+ def self.constant_scope_for(group)
588
+ const_scope = group.superclass
589
+ const_scope = self if const_scope == Core::ExampleGroup
590
+ const_scope
591
+ end
592
+
593
+ def self.base_name_for(group)
594
+ return "Anonymous" if group.description.empty?
595
+
596
+ # convert to CamelCase
597
+ name = ' ' + group.description
598
+ name.gsub!(/[^0-9a-zA-Z]+([0-9a-zA-Z])/) { $1.upcase }
599
+
600
+ name.lstrip! # Remove leading whitespace
601
+ name.gsub!(/\W/, '') # JRuby, RBX and others don't like non-ascii in const names
602
+
603
+ # Ruby requires first const letter to be A-Z. Use `Nested`
604
+ # as necessary to enforce that.
605
+ name.gsub!(/\A([^A-Z]|\z)/, 'Nested\1')
606
+
607
+ name
608
+ end
609
+
610
+ def self.disambiguate(name, const_scope)
611
+ return name unless const_scope.const_defined?(name)
612
+
613
+ # Add a trailing number if needed to disambiguate from an existing constant.
614
+ name << "_2"
615
+ name.next! while const_scope.const_defined?(name)
616
+ name
630
617
  end
631
618
  end
632
619
  end
620
+