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
@@ -1,10 +1,23 @@
1
1
  module RSpec
2
2
  module Core
3
+ # Provides the main entry point to run a suite of RSpec examples.
3
4
  class Runner
4
5
 
5
- # Register an at_exit hook that runs the suite.
6
+ # Register an `at_exit` hook that runs the suite when the process exits.
7
+ #
8
+ # @note This is not generally needed. The `rspec` command takes care
9
+ # of running examples for you without involving an `at_exit`
10
+ # hook. This is only needed if you are running specs using
11
+ # the `ruby` command, and even then, the normal way to invoke
12
+ # this is by requiring `rspec/autorun`.
6
13
  def self.autorun
7
- return if autorun_disabled? || installed_at_exit? || running_in_drb?
14
+ if autorun_disabled?
15
+ RSpec.deprecate("Requiring `rspec/autorun` when running RSpec via the `rspec` command")
16
+ return
17
+ elsif installed_at_exit? || running_in_drb?
18
+ return
19
+ end
20
+
8
21
  at_exit do
9
22
  # Don't bother running any specs and just let the program terminate
10
23
  # if we got here due to an unrescued exception (anything other than
@@ -14,73 +27,41 @@ module RSpec
14
27
  # We got here because either the end of the program was reached or
15
28
  # somebody called Kernel#exit. Run the specs and then override any
16
29
  # existing exit status with RSpec's exit status if any specs failed.
17
- status = run(ARGV, $stderr, $stdout).to_i
18
- exit status if status != 0
30
+ invoke
19
31
  end
20
32
  @installed_at_exit = true
21
33
  end
22
- AT_EXIT_HOOK_BACKTRACE_LINE = "#{__FILE__}:#{__LINE__ - 2}:in `autorun'"
23
34
 
24
- def self.disable_autorun!
25
- @autorun_disabled = true
26
- end
27
-
28
- def self.autorun_disabled?
29
- @autorun_disabled ||= false
35
+ # Runs the suite of specs and exits the process with an appropriate exit code.
36
+ def self.invoke
37
+ disable_autorun!
38
+ status = run(ARGV, $stderr, $stdout).to_i
39
+ exit(status) if status != 0
30
40
  end
31
41
 
32
- def self.installed_at_exit?
33
- @installed_at_exit ||= false
34
- end
35
-
36
- def self.running_in_drb?
37
- defined?(DRb) &&
38
- (DRb.current_server rescue false) &&
39
- DRb.current_server.uri =~ /druby\:\/\/127.0.0.1\:/
40
- end
41
-
42
- def self.trap_interrupt
43
- trap('INT') do
44
- exit!(1) if RSpec.wants_to_quit
45
- RSpec.wants_to_quit = true
46
- STDERR.puts "\nExiting... Interrupt again to exit immediately."
47
- end
48
- end
49
-
50
- # Run a suite of RSpec examples.
42
+ # Run a suite of RSpec examples. Does not exit.
51
43
  #
52
44
  # This is used internally by RSpec to run a suite, but is available
53
45
  # for use by any other automation tool.
54
46
  #
55
47
  # If you want to run this multiple times in the same process, and you
56
- # want files like spec_helper.rb to be reloaded, be sure to load `load`
48
+ # want files like `spec_helper.rb` to be reloaded, be sure to load `load`
57
49
  # instead of `require`.
58
50
  #
59
- # #### Parameters
60
- # * +args+ - an array of command-line-supported arguments
61
- # * +err+ - error stream (Default: $stderr)
62
- # * +out+ - output stream (Default: $stdout)
63
- #
64
- # #### Returns
65
- # * +Fixnum+ - exit status code (0/1)
51
+ # @param args [Array] command-line-supported arguments
52
+ # @param err [IO] error stream
53
+ # @param out [IO] output stream
54
+ # @return [Fixnum] exit status code. 0 if all specs passed,
55
+ # or the configured failure exit code (1 by default) if specs
56
+ # failed.
66
57
  def self.run(args, err=$stderr, out=$stdout)
67
58
  trap_interrupt
68
59
  options = ConfigurationOptions.new(args)
69
- options.parse_options
70
-
71
- major, minor, point = RUBY_VERSION.split('.').map { |v| v.to_i }
72
-
73
- if major == 1 && ( (minor == 9 && point < 2) || (minor == 8 && point < 7) )
74
- RSpec.deprecate "RSpec support for Ruby #{RUBY_VERSION}",
75
- :replacement => "1.8.7 or >= 1.9.2",
76
- :call_site => nil
77
- end
78
-
79
60
 
80
61
  if options.options[:drb]
81
- require 'rspec/core/drb_command_line'
62
+ require 'rspec/core/drb'
82
63
  begin
83
- DRbCommandLine.new(options).run(err, out)
64
+ DRbRunner.new(options).run(err, out)
84
65
  rescue DRb::DRbConnError
85
66
  err.puts "No DRb server is running. Running in local process instead ..."
86
67
  new(options).run(err, out)
@@ -88,8 +69,92 @@ module RSpec
88
69
  else
89
70
  new(options).run(err, out)
90
71
  end
91
- ensure
92
- RSpec.reset
72
+ end
73
+
74
+ def initialize(options, configuration=RSpec.configuration, world=RSpec.world)
75
+ @options = options
76
+ @configuration = configuration
77
+ @world = world
78
+ end
79
+
80
+ # Configures and runs a spec suite.
81
+ #
82
+ # @param err [IO] error stream
83
+ # @param out [IO] output stream
84
+ def run(err, out)
85
+ setup(err, out)
86
+ run_specs(@world.ordered_example_groups)
87
+ end
88
+
89
+ # Wires together the various configuration objects and state holders.
90
+ #
91
+ # @param err [IO] error stream
92
+ # @param out [IO] output stream
93
+ def setup(err, out)
94
+ @configuration.error_stream = err
95
+ @configuration.output_stream = out if @configuration.output_stream == $stdout
96
+ @options.configure(@configuration)
97
+ @configuration.load_spec_files
98
+ @world.announce_filters
99
+ end
100
+
101
+ # Runs the provided example groups.
102
+ #
103
+ # @param example_groups [Array<RSpec::Core::ExampleGroup>] groups to run
104
+ # @return [Fixnum] exit status code. 0 if all specs passed,
105
+ # or the configured failure exit code (1 by default) if specs
106
+ # failed.
107
+ def run_specs(example_groups)
108
+ @configuration.reporter.report(@world.example_count(example_groups)) do |reporter|
109
+ begin
110
+ hook_context = SuiteHookContext.new
111
+ @configuration.hooks.run(:before, :suite, hook_context)
112
+ example_groups.map { |g| g.run(reporter) }.all? ? 0 : @configuration.failure_exit_code
113
+ ensure
114
+ @configuration.hooks.run(:after, :suite, hook_context)
115
+ end
116
+ end
117
+ end
118
+
119
+ # @private
120
+ def self.disable_autorun!
121
+ @autorun_disabled = true
122
+ end
123
+
124
+ # @private
125
+ def self.autorun_disabled?
126
+ @autorun_disabled ||= false
127
+ end
128
+
129
+ # @private
130
+ def self.installed_at_exit?
131
+ @installed_at_exit ||= false
132
+ end
133
+
134
+ # @private
135
+ def self.running_in_drb?
136
+ begin
137
+ if defined?(DRb) && DRb.current_server
138
+ require 'socket'
139
+ require 'uri'
140
+
141
+ local_ipv4 = IPSocket.getaddress(Socket.gethostname)
142
+
143
+ local_drb = ["127.0.0.1", "localhost", local_ipv4].any? { |addr| addr == URI(DRb.current_server.uri).host }
144
+ end
145
+ rescue DRb::DRbServerNotFound
146
+ ensure
147
+ return local_drb || false
148
+ end
149
+ end
150
+
151
+ # @private
152
+ def self.trap_interrupt
153
+ trap('INT') do
154
+ exit!(1) if RSpec.world.wants_to_quit
155
+ RSpec.world.wants_to_quit = true
156
+ STDERR.puts "\nExiting... Interrupt again to exit immediately."
157
+ end
93
158
  end
94
159
  end
95
160
  end
@@ -7,7 +7,7 @@ module RSpec
7
7
  #
8
8
  # module LoggedInAsAdmin
9
9
  # extend RSpec::Core::SharedContext
10
- # before(:each) do
10
+ # before(:example) do
11
11
  # log_in_as :admin
12
12
  # end
13
13
  # end
@@ -17,39 +17,39 @@ module RSpec
17
17
  # # ...
18
18
  # end
19
19
  module SharedContext
20
- # @api private
20
+ # @private
21
21
  def included(group)
22
22
  __shared_context_recordings.each do |recording|
23
23
  recording.playback_onto(group)
24
24
  end
25
25
  end
26
26
 
27
- # @api private
27
+ # @private
28
28
  def __shared_context_recordings
29
29
  @__shared_context_recordings ||= []
30
30
  end
31
31
 
32
+ # @private
32
33
  Recording = Struct.new(:method_name, :args, :block) do
33
34
  def playback_onto(group)
34
35
  group.__send__(method_name, *args, &block)
35
36
  end
36
37
  end
37
38
 
38
- # @api private
39
+ # @private
39
40
  def self.record(methods)
40
41
  methods.each do |meth|
41
- class_eval <<-EOS, __FILE__, __LINE__ + 1
42
- def #{meth}(*args, &block)
43
- __shared_context_recordings << Recording.new(:#{meth}, args, block)
44
- end
45
- EOS
42
+ define_method(meth) do |*args, &block|
43
+ __shared_context_recordings << Recording.new(meth, args, block)
44
+ end
46
45
  end
47
46
  end
48
47
 
48
+ # @private
49
49
  record [:describe, :context] + Hooks.instance_methods(false) +
50
50
  MemoizedHelpers::ClassMethods.instance_methods(false)
51
51
  end
52
52
  end
53
-
53
+ # @private
54
54
  SharedContext = Core::SharedContext
55
55
  end
@@ -1,163 +1,158 @@
1
1
  module RSpec
2
2
  module Core
3
+ # Shared example groups let you define common context and/or common
4
+ # examples that you wish to use in multiple example groups.
5
+ #
6
+ # When defined, the shared group block is stored for later evaluation.
7
+ # It can later be included in an example group either explicitly
8
+ # (using `include_examples`, `include_context` or `it_behaves_like`)
9
+ # or implicitly (via matching metadata).
10
+ #
11
+ # Named shared example groups are scoped based on where they are
12
+ # defined. Shared groups defined in an example group are available
13
+ # for inclusion in that example group or any child example groups,
14
+ # but not in any parent or sibling example groups. Shared example
15
+ # groups defined at the top level can be included from any example group.
3
16
  module SharedExampleGroup
4
17
  # @overload shared_examples(name, &block)
5
- # @overload shared_examples(name, tags, &block)
18
+ # @param name [String, Symbol, Module] identifer to use when looking up this shared group
19
+ # @param block The block to be eval'd
20
+ # @overload shared_examples(name, metadata, &block)
21
+ # @param name [String, Symbol, Module] identifer to use when looking up this shared group
22
+ # @param metadata [Array<Symbol>, Hash] metadata to attach to this group; any example group
23
+ # with matching metadata will automatically include this shared example group.
24
+ # @param block The block to be eval'd
25
+ # @overload shared_examples(metadata, &block)
26
+ # @param metadata [Array<Symbol>, Hash] metadata to attach to this group; any example group
27
+ # with matching metadata will automatically include this shared example group.
28
+ # @param block The block to be eval'd
6
29
  #
7
- # Wraps the `block` in a module which can then be included in example
8
- # groups using `include_examples`, `include_context`, or
9
- # `it_behaves_like`.
10
- #
11
- # @param [String] name to match when looking up this shared group
12
- # @param block to be eval'd in a nested example group generated by `it_behaves_like`
30
+ # Stores the block for later use. The block will be evaluated
31
+ # in the context of an example group via `include_examples`,
32
+ # `include_context`, or `it_behaves_like`.
13
33
  #
14
34
  # @example
15
- #
16
35
  # shared_examples "auditable" do
17
36
  # it "stores an audit record on save!" do
18
- # lambda { auditable.save! }.should change(Audit, :count).by(1)
37
+ # expect { auditable.save! }.to change(Audit, :count).by(1)
19
38
  # end
20
39
  # end
21
40
  #
22
- # class Account do
41
+ # describe Account do
23
42
  # it_behaves_like "auditable" do
24
- # def auditable; Account.new; end
43
+ # let(:auditable) { Account.new }
25
44
  # end
26
45
  # end
27
46
  #
28
47
  # @see ExampleGroup.it_behaves_like
29
48
  # @see ExampleGroup.include_examples
30
49
  # @see ExampleGroup.include_context
31
- def shared_examples(*args, &block)
32
- SharedExampleGroup.registry.add_group(self, *args, &block)
33
- end
34
-
35
- alias_method :shared_context, :shared_examples
36
- alias_method :shared_examples_for, :shared_examples
37
-
38
- def share_examples_for(*args, &block)
39
- RSpec.deprecate("`share_examples_for`", :replacement => "`shared_examples` or `shared_examples_for`")
40
- shared_examples(*args, &block)
41
- end
42
-
43
- # @deprecated
44
- def share_as(name, &block)
45
- RSpec.deprecate("Rspec::Core::SharedExampleGroup#share_as",
46
- :replacement => "RSpec::SharedContext or shared_examples")
47
- SharedExampleGroup.registry.add_const(self, name, &block)
48
- end
50
+ def shared_examples(name, *args, &block)
51
+ top_level = self == ExampleGroup
52
+ if top_level && RSpec.thread_local_metadata[:in_example_group]
53
+ raise "Creating isolated shared examples from within a context is " +
54
+ "not allowed. Remove `RSpec.` prefix or move this to a " +
55
+ "top-level scope."
56
+ end
49
57
 
50
- def shared_example_groups
51
- SharedExampleGroup.registry.shared_example_groups_for('main', *ancestors[0..-1])
58
+ RSpec.world.shared_example_group_registry.add(self, name, *args, &block)
52
59
  end
60
+ alias shared_context shared_examples
61
+ alias shared_examples_for shared_examples
53
62
 
63
+ # @api private
64
+ #
65
+ # Shared examples top level DSL
54
66
  module TopLevelDSL
55
- def shared_examples(*args, &block)
56
- SharedExampleGroup.registry.add_group('main', *args, &block)
67
+ # @private
68
+ def self.definitions
69
+ proc do
70
+ def shared_examples(name, *args, &block)
71
+ RSpec.world.shared_example_group_registry.add(:main, name, *args, &block)
72
+ end
73
+ alias shared_context shared_examples
74
+ alias shared_examples_for shared_examples
75
+ end
57
76
  end
58
77
 
59
- alias_method :shared_context, :shared_examples
60
- alias_method :shared_examples_for, :shared_examples
61
-
62
- def share_examples_for(*args, &block)
63
- RSpec.deprecate("`share_examples_for`", :replacement => "`shared_examples` or `shared_examples_for`")
64
- shared_examples(*args, &block)
78
+ # @private
79
+ def self.exposed_globally?
80
+ @exposed_globally ||= false
65
81
  end
66
82
 
67
- def share_as(name, &block)
68
- RSpec.deprecate("`share_as`", :replacement => "`RSpec::SharedContext` or `shared_examples`")
69
- SharedExampleGroup.registry.add_const('main', name, &block)
83
+ # @api private
84
+ #
85
+ # Adds the top level DSL methods to Module and the top level binding
86
+ def self.expose_globally!
87
+ return if exposed_globally?
88
+ Core::DSL.change_global_dsl(&definitions)
89
+ @exposed_globally = true
70
90
  end
71
91
 
72
- def shared_example_groups
73
- SharedExampleGroup.registry.shared_example_groups_for('main')
92
+ # @api private
93
+ #
94
+ # Removes the top level DSL methods to Module and the top level binding
95
+ def self.remove_globally!
96
+ return unless exposed_globally?
97
+
98
+ Core::DSL.change_global_dsl do
99
+ undef shared_examples
100
+ undef shared_context
101
+ undef shared_examples_for
102
+ end
103
+
104
+ @exposed_globally = false
74
105
  end
75
- end
76
106
 
77
- def self.registry
78
- @registry ||= Registry.new
79
107
  end
80
108
 
81
109
  # @private
82
- #
83
- # Used internally to manage the shared example groups and
84
- # constants. We want to limit the number of methods we add
85
- # to objects we don't own (main and Module) so this allows
86
- # us to have helper methods that don't get added to those
87
- # objects.
88
110
  class Registry
89
- def add_group(source, *args, &block)
90
- ensure_block_has_source_location(block, CallerFilter.first_non_rspec_line)
91
-
92
- if key? args.first
93
- key = args.shift
94
- warn_if_key_taken source, key, block
95
- add_shared_example_group source, key, block
111
+ def add(context, name, *metadata_args, &block)
112
+ ensure_block_has_source_location(block) { CallerFilter.first_non_rspec_line }
113
+
114
+ if valid_name?(name)
115
+ warn_if_key_taken context, name, block
116
+ shared_example_groups[context][name] = block
117
+ else
118
+ metadata_args.unshift name
96
119
  end
97
120
 
98
- unless args.empty?
121
+ unless metadata_args.empty?
99
122
  mod = Module.new
100
- (class << mod; self; end).send :define_method, :extended do |host|
101
- host.class_eval(&block)
123
+ (class << mod; self; end).__send__(:define_method, :included) do |host|
124
+ host.class_exec(&block)
102
125
  end
103
- RSpec.configuration.extend mod, *args
126
+ RSpec.configuration.include mod, *metadata_args
104
127
  end
105
128
  end
106
129
 
107
- def add_const(source, name, &block)
108
- if Object.const_defined?(name)
109
- mod = Object.const_get(name)
110
- raise_name_error unless mod.created_from_caller(caller)
130
+ def find(lookup_contexts, name)
131
+ lookup_contexts.each do |context|
132
+ found = shared_example_groups[context][name]
133
+ return found if found
111
134
  end
112
135
 
113
- mod = Module.new do
114
- @shared_block = block
115
- @caller_line = caller.last
116
-
117
- def self.created_from_caller(other_caller)
118
- @caller_line == other_caller.last
119
- end
120
-
121
- def self.included(kls)
122
- kls.describe(&@shared_block)
123
- kls.children.first.metadata[:shared_group_name] = name
124
- end
125
- end
126
-
127
- shared_const = Object.const_set(name, mod)
128
- add_shared_example_group source, shared_const, block
129
- end
130
-
131
- def shared_example_groups_for(*sources)
132
- Collection.new(sources, shared_example_groups)
133
- end
134
-
135
- def shared_example_groups
136
- @shared_example_groups ||= Hash.new { |hash,key| hash[key] = Hash.new }
137
- end
138
-
139
- def clear
140
- shared_example_groups.clear
136
+ shared_example_groups[:main][name]
141
137
  end
142
138
 
143
139
  private
144
140
 
145
- def add_shared_example_group(source, key, block)
146
- shared_example_groups[source][key] = block
147
- end
148
-
149
- def key?(candidate)
150
- [String, Symbol, Module].any? { |cls| cls === candidate }
141
+ def shared_example_groups
142
+ @shared_example_groups ||= Hash.new { |hash, context| hash[context] = {} }
151
143
  end
152
144
 
153
- def raise_name_error
154
- raise NameError, "The first argument (#{name}) to share_as must be a legal name for a constant not already in use."
145
+ def valid_name?(candidate)
146
+ case candidate
147
+ when String, Symbol, Module then true
148
+ else false
149
+ end
155
150
  end
156
151
 
157
- def warn_if_key_taken(source, key, new_block)
158
- return unless existing_block = example_block_for(source, key)
152
+ def warn_if_key_taken(context, key, new_block)
153
+ return unless existing_block = shared_example_groups[context][key]
159
154
 
160
- Kernel.warn <<-WARNING.gsub(/^ +\|/, '')
155
+ RSpec.warn_with <<-WARNING.gsub(/^ +\|/, ''), :call_site => nil
161
156
  |WARNING: Shared example group '#{key}' has been previously defined at:
162
157
  | #{formatted_location existing_block}
163
158
  |...and you are now defining it at:
@@ -170,25 +165,17 @@ module RSpec
170
165
  block.source_location.join ":"
171
166
  end
172
167
 
173
- def example_block_for(source, key)
174
- shared_example_groups[source][key]
175
- end
176
-
177
168
  if Proc.method_defined?(:source_location)
178
- def ensure_block_has_source_location(block, caller_line); end
169
+ def ensure_block_has_source_location(block); end
179
170
  else # for 1.8.7
180
- def ensure_block_has_source_location(block, caller_line)
181
- block.extend Module.new {
182
- define_method :source_location do
183
- caller_line.split(':')
184
- end
185
- }
171
+ def ensure_block_has_source_location(block)
172
+ source_location = yield.split(':')
173
+ block.extend Module.new { define_method(:source_location) { source_location } }
186
174
  end
187
175
  end
188
176
  end
189
177
  end
190
178
  end
191
- end
192
179
 
193
- extend RSpec::Core::SharedExampleGroup::TopLevelDSL
194
- Module.send(:include, RSpec::Core::SharedExampleGroup::TopLevelDSL)
180
+ instance_exec(&Core::SharedExampleGroup::TopLevelDSL.definitions)
181
+ end
@@ -1,7 +1,9 @@
1
1
  module RSpec
2
2
  module Core
3
+ # Version information for RSpec Core.
3
4
  module Version
4
- STRING = '2.99.0'
5
+ # Current version of RSpec Core, in semantic versioning format.
6
+ STRING = '3.0.0'
5
7
  end
6
8
  end
7
9
  end
@@ -0,0 +1,40 @@
1
+ require "rspec/support/warnings"
2
+
3
+ module RSpec
4
+ module Core
5
+ # @private
6
+ module Warnings
7
+ # @private
8
+ #
9
+ # Used internally to print deprecation warnings
10
+ def deprecate(deprecated, data = {})
11
+ RSpec.configuration.reporter.deprecation(
12
+ {
13
+ :deprecated => deprecated,
14
+ :call_site => CallerFilter.first_non_rspec_line
15
+ }.merge(data)
16
+ )
17
+ end
18
+
19
+ # @private
20
+ #
21
+ # Used internally to print deprecation warnings
22
+ def warn_deprecation(message, opts = {})
23
+ RSpec.configuration.reporter.deprecation opts.merge( :message => message )
24
+ end
25
+
26
+ # @private
27
+ def warn_with(message, options = {})
28
+ if options[:use_spec_location_as_call_site]
29
+ message += "." unless message.end_with?(".")
30
+
31
+ if RSpec.current_example
32
+ message += " Warning generated from spec at `#{RSpec.current_example.location}`."
33
+ end
34
+ end
35
+
36
+ super(message, options)
37
+ end
38
+ end
39
+ end
40
+ end