rspec-core 2.13.1 → 2.14.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/Changelog.md +80 -0
  2. data/exe/autospec +1 -1
  3. data/features/README.md +2 -2
  4. data/features/command_line/format_option.feature +8 -14
  5. data/features/command_line/line_number_appended_to_path.feature +4 -4
  6. data/features/command_line/line_number_option.feature +1 -1
  7. data/features/command_line/rake_task.feature +2 -2
  8. data/features/command_line/require_option.feature +43 -0
  9. data/features/command_line/ruby.feature +2 -2
  10. data/features/command_line/warnings_option.feature +27 -0
  11. data/features/configuration/backtrace_clean_patterns.feature +2 -2
  12. data/features/configuration/deprecation_stream.feature +58 -0
  13. data/features/configuration/pattern.feature +8 -0
  14. data/features/configuration/profile.feature +59 -2
  15. data/features/configuration/read_options_from_file.feature +8 -5
  16. data/features/configuration/run_all_when_everything_filtered.feature +20 -4
  17. data/features/example_groups/basic_structure.feature +1 -1
  18. data/features/example_groups/shared_context.feature +1 -1
  19. data/features/example_groups/shared_examples.feature +72 -0
  20. data/features/filtering/exclusion_filters.feature +10 -10
  21. data/features/formatters/custom_formatter.feature +1 -1
  22. data/features/hooks/before_and_after_hooks.feature +19 -19
  23. data/features/mock_framework_integration/use_any_framework.feature +6 -6
  24. data/features/mock_framework_integration/use_flexmock.feature +3 -3
  25. data/features/mock_framework_integration/use_mocha.feature +3 -3
  26. data/features/mock_framework_integration/use_rr.feature +3 -3
  27. data/features/mock_framework_integration/use_rspec.feature +3 -3
  28. data/features/subject/implicit_subject.feature +1 -1
  29. data/lib/rspec/core.rb +20 -3
  30. data/lib/rspec/core/backtrace_cleaner.rb +46 -0
  31. data/lib/rspec/core/backward_compatibility.rb +3 -13
  32. data/lib/rspec/core/configuration.rb +136 -49
  33. data/lib/rspec/core/configuration_options.rb +19 -8
  34. data/lib/rspec/core/deprecation.rb +18 -30
  35. data/lib/rspec/core/example.rb +3 -3
  36. data/lib/rspec/core/example_group.rb +4 -3
  37. data/lib/rspec/core/extensions/kernel.rb +1 -1
  38. data/lib/rspec/core/filter_manager.rb +1 -1
  39. data/lib/rspec/core/formatters.rb +1 -1
  40. data/lib/rspec/core/formatters/base_formatter.rb +10 -1
  41. data/lib/rspec/core/formatters/base_text_formatter.rb +47 -10
  42. data/lib/rspec/core/formatters/deprecation_formatter.rb +35 -0
  43. data/lib/rspec/core/formatters/helpers.rb +12 -5
  44. data/lib/rspec/core/formatters/html_formatter.rb +7 -6
  45. data/lib/rspec/core/formatters/html_printer.rb +13 -12
  46. data/lib/rspec/core/formatters/json_formatter.rb +1 -2
  47. data/lib/rspec/core/formatters/text_mate_formatter.rb +1 -1
  48. data/lib/rspec/core/hooks.rb +9 -0
  49. data/lib/rspec/core/memoized_helpers.rb +19 -8
  50. data/lib/rspec/core/metadata.rb +3 -1
  51. data/lib/rspec/core/mocking/with_flexmock.rb +1 -1
  52. data/lib/rspec/core/mocking/with_rr.rb +1 -1
  53. data/lib/rspec/core/option_parser.rb +6 -2
  54. data/lib/rspec/core/pending.rb +1 -0
  55. data/lib/rspec/core/rake_task.rb +11 -19
  56. data/lib/rspec/core/reporter.rb +33 -4
  57. data/lib/rspec/core/shared_example_group.rb +56 -16
  58. data/lib/rspec/core/shared_example_group/collection.rb +42 -0
  59. data/lib/rspec/core/version.rb +1 -1
  60. data/lib/rspec/core/world.rb +2 -3
  61. data/spec/autotest/rspec_spec.rb +2 -2
  62. data/spec/rspec/core/backtrace_cleaner_spec.rb +68 -0
  63. data/spec/rspec/core/configuration_options_spec.rb +15 -4
  64. data/spec/rspec/core/configuration_spec.rb +202 -19
  65. data/spec/rspec/core/deprecation_spec.rb +41 -0
  66. data/spec/rspec/core/deprecations_spec.rb +10 -12
  67. data/spec/rspec/core/drb_command_line_spec.rb +1 -1
  68. data/spec/rspec/core/example_group_spec.rb +37 -36
  69. data/spec/rspec/core/example_spec.rb +25 -4
  70. data/spec/rspec/core/filter_manager_spec.rb +6 -6
  71. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +101 -36
  72. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +78 -0
  73. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +2 -2
  74. data/spec/rspec/core/formatters/helpers_spec.rb +23 -7
  75. data/spec/rspec/core/formatters/html_formatted-1.8.7-jruby.html +20 -14
  76. data/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html +69 -169
  77. data/spec/rspec/core/formatters/html_formatted-1.8.7.html +28 -23
  78. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +42 -33
  79. data/spec/rspec/core/formatters/html_formatted-1.9.3-jruby.html +17 -23
  80. data/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html +57 -157
  81. data/spec/rspec/core/formatters/html_formatted-1.9.3.html +42 -33
  82. data/spec/rspec/core/formatters/html_formatted-2.0.0.html +42 -33
  83. data/spec/rspec/core/formatters/html_formatter_spec.rb +1 -0
  84. data/spec/rspec/core/formatters/progress_formatter_spec.rb +3 -3
  85. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-jruby.html +11 -14
  86. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-rbx.html +103 -203
  87. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7.html +30 -25
  88. data/spec/rspec/core/formatters/text_mate_formatted-1.9.2.html +42 -33
  89. data/spec/rspec/core/formatters/text_mate_formatted-1.9.3-jruby.html +20 -14
  90. data/spec/rspec/core/formatters/text_mate_formatted-1.9.3-rbx.html +103 -203
  91. data/spec/rspec/core/formatters/text_mate_formatted-1.9.3.html +42 -33
  92. data/spec/rspec/core/formatters/text_mate_formatted-2.0.0.html +42 -33
  93. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +1 -0
  94. data/spec/rspec/core/memoized_helpers_spec.rb +28 -0
  95. data/spec/rspec/core/metadata_spec.rb +8 -3
  96. data/spec/rspec/core/option_parser_spec.rb +8 -0
  97. data/spec/rspec/core/project_initializer_spec.rb +2 -2
  98. data/spec/rspec/core/rake_task_spec.rb +8 -8
  99. data/spec/rspec/core/reporter_spec.rb +26 -6
  100. data/spec/rspec/core/resources/formatter_specs.rb +3 -3
  101. data/spec/rspec/core/shared_context_spec.rb +20 -0
  102. data/spec/rspec/core/shared_example_group/collection_spec.rb +70 -0
  103. data/spec/rspec/core/shared_example_group_spec.rb +4 -4
  104. data/spec/rspec/core/world_spec.rb +1 -3
  105. data/spec/rspec/core_spec.rb +20 -0
  106. data/spec/spec_helper.rb +29 -29
  107. data/spec/support/helper_methods.rb +9 -1
  108. data/spec/support/isolate_load_path_mutation.rb +6 -0
  109. data/spec/support/sandboxed_mock_space.rb +100 -0
  110. metadata +28 -13
  111. data/features/filtering/run_all_when_everything_filtered.feature +0 -46
  112. data/lib/rspec/core/load_path.rb +0 -3
@@ -30,7 +30,7 @@ module RSpec
30
30
  @output.puts " <dd class=\"example passed\"><span class=\"passed_spec_name\">#{h(description)}</span><span class='duration'>#{formatted_run_time}s</span></dd>"
31
31
  end
32
32
 
33
- def print_example_failed( pending_fixed, description, run_time, failure_id, exception, extra_content )
33
+ def print_example_failed( pending_fixed, description, run_time, failure_id, exception, extra_content, escape_backtrace = false )
34
34
  formatted_run_time = sprintf("%.5f", run_time)
35
35
 
36
36
  @output.puts " <dd class=\"example #{pending_fixed ? 'pending_fixed' : 'failed'}\">"
@@ -39,7 +39,11 @@ module RSpec
39
39
  @output.puts " <div class=\"failure\" id=\"failure_#{failure_id}\">"
40
40
  if exception
41
41
  @output.puts " <div class=\"message\"><pre>#{h(exception[:message])}</pre></div>"
42
- @output.puts " <div class=\"backtrace\"><pre>#{exception[:backtrace]}</pre></div>"
42
+ if escape_backtrace
43
+ @output.puts " <div class=\"backtrace\"><pre>#{h exception[:backtrace]}</pre></div>"
44
+ else
45
+ @output.puts " <div class=\"backtrace\"><pre>#{exception[:backtrace]}</pre></div>"
46
+ end
43
47
  end
44
48
  @output.puts extra_content if extra_content
45
49
  @output.puts " </div>"
@@ -114,14 +118,14 @@ module RSpec
114
118
  </div>
115
119
 
116
120
  <div id="display-filters">
117
- <input id="passed_checkbox" name="passed_checkbox" type="checkbox" checked onchange="apply_filters()" value="1"> <label for="passed_checkbox">Passed</label>
118
- <input id="failed_checkbox" name="failed_checkbox" type="checkbox" checked onchange="apply_filters()" value="2"> <label for="failed_checkbox">Failed</label>
119
- <input id="pending_checkbox" name="pending_checkbox" type="checkbox" checked onchange="apply_filters()" value="3"> <label for="pending_checkbox">Pending</label>
121
+ <input id="passed_checkbox" name="passed_checkbox" type="checkbox" checked="checked" onchange="apply_filters()" value="1" /> <label for="passed_checkbox">Passed</label>
122
+ <input id="failed_checkbox" name="failed_checkbox" type="checkbox" checked="checked" onchange="apply_filters()" value="2" /> <label for="failed_checkbox">Failed</label>
123
+ <input id="pending_checkbox" name="pending_checkbox" type="checkbox" checked="checked" onchange="apply_filters()" value="3" /> <label for="pending_checkbox">Pending</label>
120
124
  </div>
121
125
 
122
126
  <div id="summary">
123
- <p id="totals">&nbsp;</p>
124
- <p id="duration">&nbsp;</p>
127
+ <p id="totals">&#160;</p>
128
+ <p id="duration">&#160;</p>
125
129
  </div>
126
130
  </div>
127
131
 
@@ -371,11 +375,8 @@ a {
371
375
  EOF
372
376
 
373
377
  HTML_HEADER = <<-EOF
374
- <?xml version="1.0" encoding="UTF-8"?>
375
- <!DOCTYPE html
376
- PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
377
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
378
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
378
+ <!DOCTYPE html>
379
+ <html lang='en'>
379
380
  <head>
380
381
  <title>RSpec results</title>
381
382
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
@@ -28,8 +28,7 @@ module RSpec
28
28
  }
29
29
  @output_hash[:summary_line] = summary_line(example_count, failure_count, pending_count)
30
30
 
31
- # Don't print out profiled info if there are failures, it just clutters the output
32
- dump_profile if profile_examples? && failure_count == 0
31
+ dump_profile unless mute_profile_output?(failure_count)
33
32
  end
34
33
 
35
34
  def summary_line(example_count, failure_count, pending_count)
@@ -17,7 +17,7 @@ module RSpec
17
17
  def format_backtrace_line_for_textmate(line)
18
18
  return nil unless line
19
19
  CGI.escapeHTML(line).sub(/([^:]*\.e?rb):(\d*)/) do
20
- "<a href=\"txmt://open?url=file://#{File.expand_path($1)}&line=#{$2}\">#{$1}:#{$2}</a> "
20
+ "<a href=\"txmt://open?url=file://#{File.expand_path($1)}&amp;line=#{$2}\">#{$1}:#{$2}</a> "
21
21
  end
22
22
  end
23
23
 
@@ -242,6 +242,15 @@ module RSpec
242
242
  # state of a shared object, resulting in an ordering dependency that can
243
243
  # make it difficult to reason about failures.
244
244
  #
245
+ # #### unsupported rspec constructs
246
+ #
247
+ # RSpec has several constructs that reset state between each example
248
+ # automatically. These are not intended for use from within `before(:all)`:
249
+ #
250
+ # * `let` declarations
251
+ # * `subject` declarations
252
+ # * Any mocking, stubbing or test double declaration
253
+ #
245
254
  # ### other frameworks
246
255
  #
247
256
  # Mock object frameworks and database transaction managers (like
@@ -36,6 +36,13 @@ module RSpec
36
36
  # it { should be_eligible_to_vote }
37
37
  # end
38
38
  #
39
+ # @note Because `subject` is designed to create state that is reset between
40
+ # each example, and `before(:all)` is designed to setup state that is
41
+ # shared across _all_ examples in an example group, `subject` is _not_
42
+ # intended to be used in a `before(:all)` hook. RSpec 2.13.1 prints
43
+ # a warning when you reference a `subject` from `before(:all)` and we plan
44
+ # to have it raise an error in RSpec 3.
45
+ #
39
46
  # @see #should
40
47
  def subject
41
48
  raise NotImplementedError, 'This definition is here for documentation purposes only'
@@ -132,6 +139,7 @@ EOS
132
139
 
133
140
  @example_group_instance.class.class_eval do
134
141
  hash.each do |key, value|
142
+ undef_method(key) if method_defined?(key)
135
143
  define_method(key) { value }
136
144
  end
137
145
  end
@@ -161,6 +169,13 @@ EOS
161
169
  # behave in surprising ways in examples that spawn separate threads,
162
170
  # though we have yet to see this in practice. You've been warned.
163
171
  #
172
+ # @note Because `let` is designed to create state that is reset between
173
+ # each example, and `before(:all)` is designed to setup state that is
174
+ # shared across _all_ examples in an example group, `let` is _not_
175
+ # intended to be used in a `before(:all)` hook. RSpec 2.13.1 prints
176
+ # a warning when you reference a `let` from `before(:all)` and we plan
177
+ # to have it raise an error in RSpec 3.
178
+ #
164
179
  # @example
165
180
  #
166
181
  # describe Thing do
@@ -177,7 +192,8 @@ EOS
177
192
  def let(name, &block)
178
193
  # We have to pass the block directly to `define_method` to
179
194
  # allow it to use method constructs like `super` and `return`.
180
- MemoizedHelpers.module_for(self).define_method(name, &block)
195
+ raise "#let or #subject called without a block" if block.nil?
196
+ MemoizedHelpers.module_for(self).send(:define_method, name, &block)
181
197
 
182
198
  # Apply the memoization. The method has been defined in an ancestor
183
199
  # module so we can use `super` here to get the value.
@@ -276,9 +292,9 @@ EOS
276
292
  def subject(name=nil, &block)
277
293
  if name
278
294
  let(name, &block)
279
- subject { __send__ name }
295
+ alias_method :subject, name
280
296
 
281
- self::NamedSubjectPreventSuper.define_method(name) do
297
+ self::NamedSubjectPreventSuper.send(:define_method, name) do
282
298
  raise NotImplementedError, "`super` in named subjects is not supported"
283
299
  end
284
300
  else
@@ -451,13 +467,8 @@ EOS
451
467
  get_constant_or_yield(example_group, :LetDefinitions) do
452
468
  mod = Module.new do
453
469
  include Module.new {
454
- public_class_method :define_method
455
470
  example_group.const_set(:NamedSubjectPreventSuper, self)
456
471
  }
457
-
458
- # Expose `define_method` as a public method, so we can
459
- # easily use it below.
460
- public_class_method :define_method
461
472
  end
462
473
 
463
474
  example_group.__send__(:include, mod)
@@ -73,6 +73,8 @@ module RSpec
73
73
  store(:full_description, full_description)
74
74
  when :description
75
75
  store(:description, build_description_from(*self[:description_args]))
76
+ when :description_args
77
+ store(:description_args, [])
76
78
  end
77
79
  end
78
80
 
@@ -244,7 +246,7 @@ module RSpec
244
246
  protected
245
247
 
246
248
  def configure_for_example(description, user_metadata)
247
- store(:description_args, [description])
249
+ store(:description_args, [description]) if description
248
250
  store(:caller, user_metadata.delete(:caller) || caller)
249
251
  update(user_metadata)
250
252
  end
@@ -8,7 +8,7 @@ require 'flexmock/rspec'
8
8
  module RSpec
9
9
  module Core
10
10
  module MockFrameworkAdapter
11
-
11
+
12
12
  def self.framework_name; :flexmock end
13
13
 
14
14
  include FlexMock::MockContainer
@@ -5,7 +5,7 @@ RSpec.configuration.backtrace_clean_patterns.push(RR::Errors::BACKTRACE_IDENTIFI
5
5
  module RSpec
6
6
  module Core
7
7
  module MockFrameworkAdapter
8
-
8
+
9
9
  def self.framework_name; :rr end
10
10
 
11
11
  include RR::Extensions::InstanceMethods
@@ -30,7 +30,7 @@ module RSpec::Core
30
30
  args.map! { |arg|
31
31
  case arg
32
32
  when "--formatter"
33
- RSpec.deprecate("the --formatter option", "-f or --format")
33
+ RSpec.deprecate("the --formatter option", :replacement => "-f or --format")
34
34
  "--format"
35
35
  when "--default_path"
36
36
  "--default-path"
@@ -119,7 +119,7 @@ module RSpec::Core
119
119
  end
120
120
 
121
121
  parser.on('-o', '--out FILE',
122
- 'Write output to a file instead of STDOUT. This option applies',
122
+ 'Write output to a file instead of $stdout. This option applies',
123
123
  ' to the previously specified --format, or the default format',
124
124
  ' if no format is specified.'
125
125
  ) do |o|
@@ -145,6 +145,10 @@ module RSpec::Core
145
145
  end
146
146
  end
147
147
 
148
+ parser.on('-w', '--warnings', 'Enable ruby warnings') do
149
+ options[:warnings] = true
150
+ end
151
+
148
152
  parser.separator <<-FILTERING
149
153
 
150
154
  **** Filtering/tags ****
@@ -92,6 +92,7 @@ module RSpec
92
92
  result = begin
93
93
  yield
94
94
  example.example_group_instance.instance_eval { verify_mocks_for_rspec }
95
+ true
95
96
  end
96
97
  example.metadata[:pending] = false
97
98
  rescue Exception => e
@@ -30,7 +30,7 @@ module RSpec
30
30
  # @deprecated
31
31
  # Has no effect. The rake task now checks ENV['BUNDLE_GEMFILE'] instead.
32
32
  def gemfile=(*)
33
- RSpec.deprecate("RSpec::Core::RakeTask#gemfile=", 'ENV["BUNDLE_GEMFILE"]')
33
+ RSpec.deprecate("RSpec::Core::RakeTask#gemfile=", :replacement => 'ENV["BUNDLE_GEMFILE"]')
34
34
  end
35
35
 
36
36
  # @deprecated
@@ -42,7 +42,7 @@ module RSpec
42
42
  # default:
43
43
  # false
44
44
  def warning=(true_or_false)
45
- RSpec.deprecate("RSpec::Core::RakeTask#warning=", 'ruby_opts="-w"')
45
+ RSpec.deprecate("RSpec::Core::RakeTask#warning=", :replacement => 'ruby_opts="-w"')
46
46
  @warning = true_or_false
47
47
  end
48
48
 
@@ -109,7 +109,7 @@ module RSpec
109
109
  # default:
110
110
  # nil
111
111
  def spec_opts=(opts)
112
- RSpec.deprecate('RSpec::Core::RakeTask#spec_opts=', 'rspec_opts=')
112
+ RSpec.deprecate('RSpec::Core::RakeTask#spec_opts=', :replacement => 'rspec_opts=')
113
113
  @rspec_opts = opts
114
114
  end
115
115
 
@@ -137,24 +137,16 @@ module RSpec
137
137
  @pattern = './spec{,/*/**}/*_spec.rb'
138
138
  end
139
139
 
140
- def has_files?
141
- empty = files_to_run.empty?
142
- puts "No examples matching #{pattern} could be found" if empty
143
- not empty
144
- end
145
-
146
140
  def run_task(verbose)
147
- files = has_files?
148
- if files
149
- command = spec_command
150
- begin
151
- puts command if verbose
152
- success = system(command)
153
- rescue
154
- puts failure_message if failure_message
155
- end
156
- raise("#{command} failed") if fail_on_error unless success
141
+ command = spec_command
142
+
143
+ begin
144
+ puts command if verbose
145
+ success = system(command)
146
+ rescue
147
+ puts failure_message if failure_message
157
148
  end
149
+ abort("#{command} failed") if fail_on_error unless success
158
150
  end
159
151
 
160
152
  private
@@ -1,11 +1,35 @@
1
1
  module RSpec::Core
2
2
  class Reporter
3
+ NOTIFICATIONS = %W[start message example_group_started example_group_finished example_started
4
+ example_passed example_failed example_pending start_dump dump_pending
5
+ dump_failures dump_summary seed close stop deprecation deprecation_summary].map(&:to_sym)
6
+
3
7
  def initialize(*formatters)
4
- @formatters = formatters
8
+ @listeners = Hash.new { |h,k| h[k] = [] }
9
+ formatters.each do |formatter|
10
+ register_listener(formatter, *NOTIFICATIONS)
11
+ end
5
12
  @example_count = @failure_count = @pending_count = 0
6
13
  @duration = @start = nil
7
14
  end
8
15
 
16
+ # @api
17
+ # @param [Object] An obect that wishes to be notified of reporter events
18
+ # @param [Array] Array of symbols represents the events a listener wishes to subscribe too
19
+ #
20
+ # Registers a listener to a list of notifications. The reporter will send notification of
21
+ # events to all registered listeners
22
+ def register_listener(listener, *notifications)
23
+ notifications.each do |notification|
24
+ @listeners[notification.to_sym] << listener if listener.respond_to?(notification)
25
+ end
26
+ true
27
+ end
28
+
29
+ def registered_listeners(notification)
30
+ @listeners[notification]
31
+ end
32
+
9
33
  # @api
10
34
  # @overload report(count, &block)
11
35
  # @overload report(count, seed, &block)
@@ -73,6 +97,10 @@ module RSpec::Core
73
97
  notify :example_pending, example
74
98
  end
75
99
 
100
+ def deprecation(message)
101
+ notify :deprecation, message
102
+ end
103
+
76
104
  def finish(seed)
77
105
  begin
78
106
  stop
@@ -80,6 +108,7 @@ module RSpec::Core
80
108
  notify :dump_pending
81
109
  notify :dump_failures
82
110
  notify :dump_summary, @duration, @example_count, @failure_count, @pending_count
111
+ notify :deprecation_summary
83
112
  notify :seed, seed if seed
84
113
  ensure
85
114
  notify :close
@@ -93,9 +122,9 @@ module RSpec::Core
93
122
  notify :stop
94
123
  end
95
124
 
96
- def notify(method, *args, &block)
97
- @formatters.each do |formatter|
98
- formatter.send method, *args, &block
125
+ def notify(event, *args, &block)
126
+ registered_listeners(event).each do |formatter|
127
+ formatter.send(event, *args, &block)
99
128
  end
100
129
  end
101
130
  end
@@ -28,8 +28,8 @@ module RSpec
28
28
  # @see ExampleGroup.it_behaves_like
29
29
  # @see ExampleGroup.include_examples
30
30
  # @see ExampleGroup.include_context
31
- def shared_examples *args, &block
32
- Registry.add_group(*args, &block)
31
+ def shared_examples(*args, &block)
32
+ Registry.add_group(self, *args, &block)
33
33
  end
34
34
 
35
35
  alias_method :shared_context, :shared_examples
@@ -39,8 +39,32 @@ module RSpec
39
39
  # @deprecated
40
40
  def share_as(name, &block)
41
41
  RSpec.deprecate("Rspec::Core::SharedExampleGroup#share_as",
42
- "RSpec::SharedContext or shared_examples")
43
- Registry.add_const(name, &block)
42
+ :replacement => "RSpec::SharedContext or shared_examples")
43
+ Registry.add_const(self, name, &block)
44
+ end
45
+
46
+ def shared_example_groups
47
+ Registry.shared_example_groups_for('main', *ancestors[0..-1])
48
+ end
49
+
50
+ module TopLevelDSL
51
+ def shared_examples(*args, &block)
52
+ Registry.add_group('main', *args, &block)
53
+ end
54
+
55
+ alias_method :shared_context, :shared_examples
56
+ alias_method :share_examples_for, :shared_examples
57
+ alias_method :shared_examples_for, :shared_examples
58
+
59
+ def share_as(name, &block)
60
+ RSpec.deprecate("Rspec::Core::SharedExampleGroup#share_as",
61
+ :replacement => "RSpec::SharedContext or shared_examples")
62
+ Registry.add_const('main', name, &block)
63
+ end
64
+
65
+ def shared_example_groups
66
+ Registry.shared_example_groups_for('main')
67
+ end
44
68
  end
45
69
 
46
70
  # @private
@@ -53,13 +77,13 @@ module RSpec
53
77
  module Registry
54
78
  extend self
55
79
 
56
- def add_group(*args, &block)
80
+ def add_group(source, *args, &block)
57
81
  ensure_block_has_source_location(block, caller[1])
58
82
 
59
83
  if key? args.first
60
84
  key = args.shift
61
- warn_if_key_taken key, block
62
- RSpec.world.shared_example_groups[key] = block
85
+ warn_if_key_taken source, key, block
86
+ add_shared_example_group source, key, block
63
87
  end
64
88
 
65
89
  unless args.empty?
@@ -71,7 +95,7 @@ module RSpec
71
95
  end
72
96
  end
73
97
 
74
- def add_const(name, &block)
98
+ def add_const(source, name, &block)
75
99
  if Object.const_defined?(name)
76
100
  mod = Object.const_get(name)
77
101
  raise_name_error unless mod.created_from_caller(caller)
@@ -92,12 +116,28 @@ module RSpec
92
116
  end
93
117
 
94
118
  shared_const = Object.const_set(name, mod)
95
- RSpec.world.shared_example_groups[shared_const] = block
119
+ add_shared_example_group source, shared_const, block
120
+ end
121
+
122
+ def shared_example_groups_for(*sources)
123
+ Collection.new(sources, shared_example_groups)
124
+ end
125
+
126
+ def shared_example_groups
127
+ @shared_example_groups ||= Hash.new { |hash,key| hash[key] = Hash.new }
128
+ end
129
+
130
+ def clear
131
+ @shared_example_groups.clear
96
132
  end
97
133
 
98
134
  private
99
135
 
100
- def key? candidate
136
+ def add_shared_example_group(source, key, block)
137
+ shared_example_groups[source][key] = block
138
+ end
139
+
140
+ def key?(candidate)
101
141
  [String, Symbol, Module].any? { |cls| cls === candidate }
102
142
  end
103
143
 
@@ -105,8 +145,8 @@ module RSpec
105
145
  raise NameError, "The first argument (#{name}) to share_as must be a legal name for a constant not already in use."
106
146
  end
107
147
 
108
- def warn_if_key_taken key, new_block
109
- return unless existing_block = example_block_for(key)
148
+ def warn_if_key_taken(source, key, new_block)
149
+ return unless existing_block = example_block_for(source, key)
110
150
 
111
151
  Kernel.warn <<-WARNING.gsub(/^ +\|/, '')
112
152
  |WARNING: Shared example group '#{key}' has been previously defined at:
@@ -117,12 +157,12 @@ module RSpec
117
157
  WARNING
118
158
  end
119
159
 
120
- def formatted_location block
160
+ def formatted_location(block)
121
161
  block.source_location.join ":"
122
162
  end
123
163
 
124
- def example_block_for key
125
- RSpec.world.shared_example_groups[key]
164
+ def example_block_for(source, key)
165
+ shared_example_groups[source][key]
126
166
  end
127
167
 
128
168
  def ensure_block_has_source_location(block, caller_line)
@@ -139,6 +179,6 @@ module RSpec
139
179
  end
140
180
  end
141
181
 
142
- extend RSpec::Core::SharedExampleGroup
182
+ extend RSpec::Core::SharedExampleGroup::TopLevelDSL
143
183
  Module.send(:include, RSpec::Core::SharedExampleGroup)
144
184