rspec-core 2.99.2 → 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. checksums.yaml +14 -6
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +0 -0
  4. data/Changelog.md +103 -191
  5. data/License.txt +1 -0
  6. data/README.md +4 -25
  7. data/features/Upgrade.md +2 -14
  8. data/features/command_line/dry_run.feature +29 -0
  9. data/features/command_line/example_name_option.feature +1 -1
  10. data/features/command_line/fail_fast.feature +26 -0
  11. data/features/command_line/format_option.feature +3 -3
  12. data/features/command_line/line_number_option.feature +16 -11
  13. data/features/command_line/order.feature +2 -3
  14. data/features/command_line/pattern_option.feature +3 -3
  15. data/features/command_line/randomization.feature +63 -0
  16. data/features/command_line/require_option.feature +2 -2
  17. data/features/command_line/ruby.feature +1 -1
  18. data/features/configuration/alias_example_to.feature +13 -22
  19. data/features/configuration/{backtrace_clean_patterns.feature → backtrace_exclusion_patterns.feature} +17 -14
  20. data/features/configuration/custom_settings.feature +11 -11
  21. data/features/configuration/overriding_global_ordering.feature +93 -0
  22. data/features/configuration/profile.feature +13 -13
  23. data/features/configuration/read_options_from_file.feature +7 -7
  24. data/features/example_groups/basic_structure.feature +1 -1
  25. data/features/example_groups/shared_context.feature +8 -8
  26. data/features/example_groups/shared_examples.feature +6 -14
  27. data/features/expectation_framework_integration/configure_expectation_framework.feature +27 -122
  28. data/features/filtering/exclusion_filters.feature +2 -5
  29. data/features/filtering/inclusion_filters.feature +1 -5
  30. data/features/formatters/json_formatter.feature +2 -2
  31. data/features/formatters/text_formatter.feature +4 -4
  32. data/features/helper_methods/arbitrary_methods.feature +2 -2
  33. data/features/helper_methods/let.feature +5 -5
  34. data/features/helper_methods/modules.feature +5 -8
  35. data/features/hooks/around_hooks.feature +2 -2
  36. data/features/hooks/before_and_after_hooks.feature +14 -14
  37. data/features/hooks/filtering.feature +12 -14
  38. data/features/metadata/described_class.feature +1 -1
  39. data/features/metadata/user_defined.feature +16 -29
  40. data/features/mock_framework_integration/use_flexmock.feature +1 -1
  41. data/features/mock_framework_integration/use_mocha.feature +1 -1
  42. data/features/mock_framework_integration/use_rr.feature +1 -1
  43. data/features/mock_framework_integration/use_rspec.feature +5 -5
  44. data/features/pending/pending_examples.feature +5 -5
  45. data/features/spec_files/arbitrary_file_suffix.feature +1 -1
  46. data/features/step_definitions/additional_cli_steps.rb +3 -3
  47. data/features/subject/explicit_subject.feature +8 -8
  48. data/features/subject/implicit_receiver.feature +29 -0
  49. data/features/subject/implicit_subject.feature +4 -4
  50. data/features/support/env.rb +10 -3
  51. data/features/support/require_expect_syntax_in_aruba_specs.rb +16 -0
  52. data/lib/rspec/core.rb +11 -48
  53. data/lib/rspec/core/backport_random.rb +302 -0
  54. data/lib/rspec/core/backtrace_formatter.rb +65 -0
  55. data/lib/rspec/core/command_line.rb +7 -18
  56. data/lib/rspec/core/configuration.rb +202 -507
  57. data/lib/rspec/core/configuration_options.rb +17 -30
  58. data/lib/rspec/core/example.rb +29 -39
  59. data/lib/rspec/core/example_group.rb +166 -259
  60. data/lib/rspec/core/filter_manager.rb +30 -47
  61. data/lib/rspec/core/flat_map.rb +17 -0
  62. data/lib/rspec/core/formatters.rb +0 -138
  63. data/lib/rspec/core/formatters/base_formatter.rb +46 -1
  64. data/lib/rspec/core/formatters/base_text_formatter.rb +38 -61
  65. data/lib/rspec/core/formatters/deprecation_formatter.rb +21 -52
  66. data/lib/rspec/core/formatters/helpers.rb +0 -28
  67. data/lib/rspec/core/formatters/html_formatter.rb +1 -1
  68. data/lib/rspec/core/formatters/json_formatter.rb +38 -9
  69. data/lib/rspec/core/formatters/snippet_extractor.rb +14 -5
  70. data/lib/rspec/core/hooks.rb +55 -39
  71. data/lib/rspec/core/memoized_helpers.rb +17 -167
  72. data/lib/rspec/core/metadata.rb +16 -64
  73. data/lib/rspec/core/option_parser.rb +30 -39
  74. data/lib/rspec/core/ordering.rb +154 -0
  75. data/lib/rspec/core/pending.rb +12 -69
  76. data/lib/rspec/core/project_initializer.rb +12 -10
  77. data/lib/rspec/core/rake_task.rb +5 -108
  78. data/lib/rspec/core/reporter.rb +15 -18
  79. data/lib/rspec/core/runner.rb +16 -30
  80. data/lib/rspec/core/shared_context.rb +3 -5
  81. data/lib/rspec/core/shared_example_group.rb +3 -51
  82. data/lib/rspec/core/shared_example_group/collection.rb +1 -19
  83. data/lib/rspec/core/version.rb +1 -1
  84. data/lib/rspec/core/warnings.rb +22 -0
  85. data/lib/rspec/core/world.rb +12 -8
  86. data/spec/command_line/order_spec.rb +20 -23
  87. data/spec/rspec/core/backtrace_formatter_spec.rb +216 -0
  88. data/spec/rspec/core/command_line_spec.rb +32 -48
  89. data/spec/rspec/core/configuration_options_spec.rb +19 -50
  90. data/spec/rspec/core/configuration_spec.rb +142 -713
  91. data/spec/rspec/core/drb_command_line_spec.rb +2 -0
  92. data/spec/rspec/core/dsl_spec.rb +0 -1
  93. data/spec/rspec/core/example_group_spec.rb +192 -223
  94. data/spec/rspec/core/example_spec.rb +40 -16
  95. data/spec/rspec/core/filter_manager_spec.rb +2 -2
  96. data/spec/rspec/core/formatters/base_formatter_spec.rb +0 -41
  97. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +5 -123
  98. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +2 -87
  99. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +2 -3
  100. data/spec/rspec/core/formatters/{text_mate_formatted.html → html_formatted-1.8.7-jruby.html} +44 -25
  101. data/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html +477 -0
  102. data/spec/rspec/core/formatters/{html_formatted.html → html_formatted-1.8.7.html} +42 -25
  103. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +425 -0
  104. data/spec/rspec/core/formatters/html_formatted-1.9.3-jruby.html +416 -0
  105. data/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html +477 -0
  106. data/spec/rspec/core/formatters/html_formatted-1.9.3.html +419 -0
  107. data/spec/rspec/core/formatters/html_formatted-2.0.0.html +425 -0
  108. data/spec/rspec/core/formatters/html_formatter_spec.rb +21 -46
  109. data/spec/rspec/core/formatters/json_formatter_spec.rb +97 -8
  110. data/spec/rspec/core/hooks_filtering_spec.rb +5 -5
  111. data/spec/rspec/core/hooks_spec.rb +61 -47
  112. data/spec/rspec/core/memoized_helpers_spec.rb +20 -322
  113. data/spec/rspec/core/metadata_spec.rb +1 -24
  114. data/spec/rspec/core/option_parser_spec.rb +20 -62
  115. data/spec/rspec/core/ordering_spec.rb +102 -0
  116. data/spec/rspec/core/pending_example_spec.rb +0 -40
  117. data/spec/rspec/core/project_initializer_spec.rb +1 -25
  118. data/spec/rspec/core/rake_task_spec.rb +5 -72
  119. data/spec/rspec/core/random_spec.rb +47 -0
  120. data/spec/rspec/core/reporter_spec.rb +23 -48
  121. data/spec/rspec/core/runner_spec.rb +31 -39
  122. data/spec/rspec/core/shared_context_spec.rb +3 -15
  123. data/spec/rspec/core/shared_example_group/collection_spec.rb +4 -17
  124. data/spec/rspec/core/shared_example_group_spec.rb +12 -45
  125. data/spec/rspec/core/{deprecation_spec.rb → warnings_spec.rb} +3 -1
  126. data/spec/rspec/core_spec.rb +4 -21
  127. data/spec/spec_helper.rb +41 -5
  128. data/spec/support/helper_methods.rb +0 -29
  129. data/spec/support/sandboxed_mock_space.rb +0 -16
  130. data/spec/support/shared_example_groups.rb +7 -36
  131. data/spec/support/stderr_splitter.rb +36 -0
  132. metadata +163 -157
  133. metadata.gz.sig +1 -0
  134. data/exe/autospec +0 -13
  135. data/features/Autotest.md +0 -38
  136. data/features/configuration/treat_symbols_as_metadata_keys_with_true_values.feature +0 -52
  137. data/features/subject/attribute_of_subject.feature +0 -124
  138. data/features/subject/one_liner_syntax.feature +0 -71
  139. data/lib/autotest/discover.rb +0 -10
  140. data/lib/autotest/rspec2.rb +0 -77
  141. data/lib/rspec/core/backtrace_cleaner.rb +0 -46
  142. data/lib/rspec/core/backward_compatibility.rb +0 -55
  143. data/lib/rspec/core/caller_filter.rb +0 -60
  144. data/lib/rspec/core/deprecated_mutable_array_proxy.rb +0 -32
  145. data/lib/rspec/core/deprecation.rb +0 -26
  146. data/lib/rspec/core/extensions/instance_eval_with_args.rb +0 -44
  147. data/lib/rspec/core/extensions/kernel.rb +0 -9
  148. data/lib/rspec/core/extensions/module_eval_with_args.rb +0 -38
  149. data/lib/rspec/core/extensions/ordered.rb +0 -27
  150. data/lib/rspec/core/formatters/console_codes.rb +0 -42
  151. data/lib/rspec/core/formatters/text_mate_formatter.rb +0 -34
  152. data/lib/rspec/core/metadata_hash_builder.rb +0 -97
  153. data/lib/rspec/core/minitest_assertions_adapter.rb +0 -28
  154. data/lib/rspec/core/test_unit_assertions_adapter.rb +0 -30
  155. data/spec/autotest/discover_spec.rb +0 -49
  156. data/spec/autotest/failed_results_re_spec.rb +0 -45
  157. data/spec/autotest/rspec_spec.rb +0 -133
  158. data/spec/rspec/core/backtrace_cleaner_spec.rb +0 -68
  159. data/spec/rspec/core/caller_filter_spec.rb +0 -58
  160. data/spec/rspec/core/deprecations_spec.rb +0 -59
  161. data/spec/rspec/core/formatters/console_codes_spec.rb +0 -50
  162. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +0 -107
  163. data/spec/rspec/core/kernel_extensions_spec.rb +0 -9
  164. data/spec/rspec/core/pending_spec.rb +0 -27
  165. data/spec/support/silence_dsl_deprecations.rb +0 -32
@@ -16,9 +16,7 @@ module RSpec
16
16
 
17
17
  def printer
18
18
  @printer ||= case deprecation_stream
19
- when File
20
- ImmediatePrinter.new(FileStream.new(deprecation_stream), summary_stream, self)
21
- when RaiseErrorStream
19
+ when File, RaiseErrorStream
22
20
  ImmediatePrinter.new(deprecation_stream, summary_stream, self)
23
21
  else
24
22
  DelayedPrinter.new(deprecation_stream, summary_stream, self)
@@ -37,10 +35,6 @@ module RSpec
37
35
  printer.deprecation_summary
38
36
  end
39
37
 
40
- def start(example_count=nil)
41
- #no-op to fix #966
42
- end
43
-
44
38
  def deprecation_message_for(data)
45
39
  if data[:message]
46
40
  SpecifiedDeprecationMessage.new(data)
@@ -57,9 +51,6 @@ module RSpec
57
51
  |deprecation warnings into errors, giving you the full backtrace.
58
52
  EOS
59
53
 
60
- DEPRECATION_STREAM_NOTICE = "Pass `--deprecation-out` or set " +
61
- "`config.deprecation_stream` to a file for full output."
62
-
63
54
  SpecifiedDeprecationMessage = Struct.new(:type) do
64
55
  def initialize(data)
65
56
  @message = data[:message]
@@ -67,23 +58,17 @@ module RSpec
67
58
  end
68
59
 
69
60
  def to_s
70
- output_formatted @message
61
+ @message
71
62
  end
72
63
 
73
64
  def too_many_warnings_message
74
- msg = "Too many similar deprecation messages reported, disregarding further reports. "
75
- msg << DEPRECATION_STREAM_NOTICE
65
+ msg = "Too many similar deprecation messages reported, disregarding further reports."
66
+ msg << " Set config.deprecation_stream to a File for full output."
76
67
  msg
77
68
  end
78
69
 
79
70
  private
80
71
 
81
- def output_formatted(str)
82
- return str unless str.lines.count > 1
83
- separator = "#{'-' * 80}"
84
- "#{separator}\n#{str.chomp}\n#{separator}"
85
- end
86
-
87
72
  def deprecation_type_for(data)
88
73
  data[:message].gsub(/(\w+\/)+\w+\.rb:\d+/, '')
89
74
  end
@@ -92,7 +77,7 @@ module RSpec
92
77
  GeneratedDeprecationMessage = Struct.new(:type) do
93
78
  def initialize(data)
94
79
  @data = data
95
- super data.fetch(:type, data[:deprecated])
80
+ super data[:deprecated]
96
81
  end
97
82
 
98
83
  def to_s
@@ -103,18 +88,26 @@ module RSpec
103
88
  end
104
89
 
105
90
  def too_many_warnings_message
106
- msg = "Too many uses of deprecated '#{type}'. "
107
- msg << DEPRECATION_STREAM_NOTICE
91
+ msg = "Too many uses of deprecated '#{type}'."
92
+ msg << " Set config.deprecation_stream to a File for full output."
108
93
  msg
109
94
  end
110
95
  end
111
96
 
112
97
  class ImmediatePrinter
98
+ include ::RSpec::Core::Formatters::Helpers
99
+
113
100
  attr_reader :deprecation_stream, :summary_stream, :deprecation_formatter
114
101
 
115
102
  def initialize(deprecation_stream, summary_stream, deprecation_formatter)
116
103
  @deprecation_stream = deprecation_stream
117
104
 
105
+ # In one of my test suites, I got lots of duplicate output in the
106
+ # deprecation file (e.g. 200 of the same deprecation, even though
107
+ # the `puts` below was only called 6 times). Setting `sync = true`
108
+ # fixes this (but we really have no idea why!).
109
+ @deprecation_stream.sync = true
110
+
118
111
  @summary_stream = summary_stream
119
112
  @deprecation_formatter = deprecation_formatter
120
113
  end
@@ -125,8 +118,10 @@ module RSpec
125
118
  end
126
119
 
127
120
  def deprecation_summary
128
- return if deprecation_formatter.count.zero?
129
- deprecation_stream.summarize(summary_stream, deprecation_formatter.count)
121
+ if deprecation_formatter.count > 0
122
+ summary_stream.puts "\n#{pluralize(deprecation_formatter.count, 'deprecation')} logged to #{deprecation_stream.path}"
123
+ deprecation_stream.puts RAISE_ERROR_CONFIG_NOTICE
124
+ end
130
125
  end
131
126
  end
132
127
 
@@ -181,38 +176,12 @@ module RSpec
181
176
 
182
177
  # Not really a stream, but is usable in place of one.
183
178
  class RaiseErrorStream
184
- include ::RSpec::Core::Formatters::Helpers
185
-
186
179
  def puts(message)
187
180
  raise DeprecationError, message
188
181
  end
189
182
 
190
- def summarize(summary_stream, deprecation_count)
191
- summary_stream.puts "\n#{pluralize(deprecation_count, 'deprecation')} found."
192
- end
193
- end
194
-
195
- # Wraps a File object and provides file-specific operations.
196
- class FileStream
197
- include ::RSpec::Core::Formatters::Helpers
198
-
199
- def initialize(file)
200
- @file = file
201
-
202
- # In one of my test suites, I got lots of duplicate output in the
203
- # deprecation file (e.g. 200 of the same deprecation, even though
204
- # the `puts` below was only called 6 times). Setting `sync = true`
205
- # fixes this (but we really have no idea why!).
206
- @file.sync = true
207
- end
208
-
209
- def puts(*args)
210
- @file.puts(*args)
211
- end
212
-
213
- def summarize(summary_stream, deprecation_count)
214
- summary_stream.puts "\n#{pluralize(deprecation_count, 'deprecation')} logged to #{@file.path}"
215
- puts RAISE_ERROR_CONFIG_NOTICE
183
+ def sync=(value)
184
+ # no-op
216
185
  end
217
186
  end
218
187
 
@@ -1,34 +1,7 @@
1
1
  module RSpec
2
2
  module Core
3
- module BacktraceFormatter
4
- extend self
5
-
6
- def format_backtrace(backtrace, options = {})
7
- return "" unless backtrace
8
- return backtrace if options[:full_backtrace] == true
9
-
10
- if at_exit_index = backtrace.index(RSpec::Core::Runner::AT_EXIT_HOOK_BACKTRACE_LINE)
11
- backtrace = backtrace[0, at_exit_index]
12
- end
13
-
14
- cleansed = backtrace.map { |line| backtrace_line(line) }.compact
15
- cleansed.empty? ? backtrace : cleansed
16
- end
17
-
18
- protected
19
-
20
- def backtrace_line(line)
21
- return nil if RSpec.configuration.backtrace_formatter.exclude?(line)
22
- RSpec::Core::Metadata::relative_path(line)
23
- rescue SecurityError
24
- nil
25
- end
26
- end
27
-
28
3
  module Formatters
29
4
  module Helpers
30
- include BacktraceFormatter
31
-
32
5
  SUB_SECOND_PRECISION = 5
33
6
  DEFAULT_PRECISION = 2
34
7
 
@@ -104,7 +77,6 @@ module RSpec
104
77
  "#{count} #{string}#{'s' unless count.to_f == 1}"
105
78
  end
106
79
  end
107
-
108
80
  end
109
81
  end
110
82
  end
@@ -119,7 +119,7 @@ module RSpec
119
119
  #
120
120
  def extra_failure_content(exception)
121
121
  require 'rspec/core/formatters/snippet_extractor'
122
- backtrace = exception.backtrace.map {|line| backtrace_line(line)}
122
+ backtrace = exception.backtrace.map {|line| configuration.backtrace_formatter.backtrace_line(line)}
123
123
  backtrace.compact!
124
124
  @snippet_extractor ||= SnippetExtractor.new
125
125
  " <pre class=\"ruby\"><code>#{@snippet_extractor.snippet(backtrace)}</code></pre>"
@@ -27,6 +27,8 @@ module RSpec
27
27
  :pending_count => pending_count
28
28
  }
29
29
  @output_hash[:summary_line] = summary_line(example_count, failure_count, pending_count)
30
+
31
+ dump_profile unless mute_profile_output?(failure_count)
30
32
  end
31
33
 
32
34
  def summary_line(example_count, failure_count, pending_count)
@@ -39,15 +41,7 @@ module RSpec
39
41
  def stop
40
42
  super
41
43
  @output_hash[:examples] = examples.map do |example|
42
- {
43
- :description => example.description,
44
- :full_description => example.full_description,
45
- :status => example.execution_result[:status],
46
- # :example_group,
47
- # :execution_result,
48
- :file_path => example.metadata[:file_path],
49
- :line_number => example.metadata[:line_number],
50
- }.tap do |hash|
44
+ format_example(example).tap do |hash|
51
45
  if e=example.exception
52
46
  hash[:exception] = {
53
47
  :class => e.class.name,
@@ -64,6 +58,41 @@ module RSpec
64
58
  output.close if IO === output && output != $stdout
65
59
  end
66
60
 
61
+ def dump_profile
62
+ @output_hash[:profile] = {}
63
+ dump_profile_slowest_examples
64
+ dump_profile_slowest_example_groups
65
+ end
66
+
67
+ def dump_profile_slowest_examples
68
+ @output_hash[:profile] = {}
69
+ sorted_examples = slowest_examples
70
+ @output_hash[:profile][:examples] = sorted_examples[:examples].map do |example|
71
+ format_example(example).tap do |hash|
72
+ hash[:run_time] = example.execution_result[:run_time]
73
+ end
74
+ end
75
+ @output_hash[:profile][:slowest] = sorted_examples[:slows]
76
+ @output_hash[:profile][:total] = sorted_examples[:total]
77
+ end
78
+
79
+ def dump_profile_slowest_example_groups
80
+ @output_hash[:profile] ||= {}
81
+ @output_hash[:profile][:groups] = slowest_groups.map do |loc, hash|
82
+ hash.update(:location => loc)
83
+ end
84
+ end
85
+
86
+ private
87
+ def format_example(example)
88
+ {
89
+ :description => example.description,
90
+ :full_description => example.full_description,
91
+ :status => example.execution_result[:status],
92
+ :file_path => example.metadata[:file_path],
93
+ :line_number => example.metadata[:line_number]
94
+ }
95
+ end
67
96
  end
68
97
  end
69
98
  end
@@ -5,11 +5,21 @@ module RSpec
5
5
  #
6
6
  # Extracts code snippets by looking at the backtrace of the passed error and applies synax highlighting and line numbers using html.
7
7
  class SnippetExtractor
8
- class NullConverter; def convert(code, pre); code; end; end
8
+ class NullConverter
9
+ def convert(code)
10
+ %Q(#{code}\n<span class="comment"># Install the coderay gem to get syntax highlighting</span>)
11
+ end
12
+ end
13
+
14
+ class CoderayConverter
15
+ def convert(code)
16
+ CodeRay.scan(code, :ruby).html(:line_numbers => false)
17
+ end
18
+ end
9
19
 
10
20
  begin
11
- require 'syntax/convertors/html'
12
- @@converter = Syntax::Convertors::HTML.for_syntax "ruby"
21
+ require 'coderay'
22
+ @@converter = CoderayConverter.new
13
23
  rescue LoadError
14
24
  @@converter = NullConverter.new
15
25
  end
@@ -24,8 +34,7 @@ module RSpec
24
34
  # @see #post_process
25
35
  def snippet(backtrace)
26
36
  raw_code, line = snippet_for(backtrace[0])
27
- highlighted = @@converter.convert(raw_code, false)
28
- highlighted << "\n<span class=\"comment\"># gem install syntax to get syntax highlighting</span>" if @@converter.is_a?(NullConverter)
37
+ highlighted = @@converter.convert(raw_code)
29
38
  post_process(highlighted, line)
30
39
  end
31
40
 
@@ -1,8 +1,6 @@
1
1
  module RSpec
2
2
  module Core
3
3
  module Hooks
4
- include MetadataHashBuilder::WithConfigWarning
5
-
6
4
  class Hook
7
5
  attr_reader :block, :options
8
6
 
@@ -18,7 +16,7 @@ module RSpec
18
16
 
19
17
  class BeforeHook < Hook
20
18
  def run(example)
21
- example.instance_eval_with_args(example, &block)
19
+ example.instance_exec(example, &block)
22
20
  end
23
21
 
24
22
  def display_name
@@ -28,7 +26,7 @@ module RSpec
28
26
 
29
27
  class AfterHook < Hook
30
28
  def run(example)
31
- example.instance_eval_with_rescue("in an after hook", &block)
29
+ example.instance_exec_with_rescue("in an after hook", &block)
32
30
  end
33
31
 
34
32
  def display_name
@@ -61,18 +59,26 @@ EOS
61
59
  end
62
60
  end
63
61
 
64
- module HookCollectionAliases
65
- def self.included(host)
66
- host.send :alias_method, :prepend, :unshift
67
- host.send :alias_method, :append, :push
62
+ class BaseHookCollection
63
+ Array.public_instance_methods(false).each do |name|
64
+ define_method(name) { |*a, &b| hooks.__send__(name, *a, &b) }
68
65
  end
69
- end
70
66
 
71
- class HookCollection < Array
72
- include HookCollectionAliases
67
+ attr_reader :hooks
68
+ protected :hooks
73
69
 
70
+ alias append push
71
+ alias prepend unshift
72
+
73
+ def initialize(hooks=[])
74
+ @hooks = hooks
75
+ end
76
+ end
77
+
78
+ class HookCollection < BaseHookCollection
74
79
  def for(example_or_group)
75
- self.class.new(select {|hook| hook.options_apply?(example_or_group)}).
80
+ self.class.
81
+ new(hooks.select {|hook| hook.options_apply?(example_or_group)}).
76
82
  with(example_or_group)
77
83
  end
78
84
 
@@ -82,15 +88,13 @@ EOS
82
88
  end
83
89
 
84
90
  def run
85
- each {|h| h.run(@example) } unless empty?
91
+ hooks.each {|h| h.run(@example)}
86
92
  end
87
93
  end
88
94
 
89
- class AroundHookCollection < Array
90
- include HookCollectionAliases
91
-
95
+ class AroundHookCollection < BaseHookCollection
92
96
  def for(example, initial_procsy=nil)
93
- self.class.new(select {|hook| hook.options_apply?(example)}).
97
+ self.class.new(hooks.select {|hook| hook.options_apply?(example)}).
94
98
  with(example, initial_procsy)
95
99
  end
96
100
 
@@ -101,51 +105,61 @@ EOS
101
105
  end
102
106
 
103
107
  def run
104
- inject(@initial_procsy) do |procsy, around_hook|
105
- Example.procsy(procsy.metadata) do
106
- @example.instance_eval_with_args(procsy, &around_hook.block)
108
+ hooks.reduce(@initial_procsy) do |procsy, around_hook|
109
+ procsy.wrap do
110
+ @example.instance_exec(procsy, &around_hook.block)
107
111
  end
108
112
  end.call
109
113
  end
110
114
  end
111
115
 
112
- class GroupHookCollection < Array
116
+ class GroupHookCollection < BaseHookCollection
113
117
  def for(group)
114
118
  @group = group
115
119
  self
116
120
  end
117
121
 
118
122
  def run
119
- shift.run(@group) until empty?
123
+ hooks.shift.run(@group) until hooks.empty?
120
124
  end
121
125
  end
122
126
 
123
- module RegistersGlobals
124
- def register_globals host, globals
125
- [:before, :after, :around].each do |position|
126
- process host, globals, position, :each
127
- next if position == :around # no around(:all) hooks
128
- process host, globals, position, :all
129
- end
127
+ class HookCollections
128
+ def initialize(data)
129
+ @data = data
130
+ end
131
+
132
+ def [](key)
133
+ @data[key]
134
+ end
135
+
136
+ def register_globals(host, globals)
137
+ process(host, globals, :before, :each)
138
+ process(host, globals, :after, :each)
139
+ process(host, globals, :around, :each)
140
+
141
+ process(host, globals, :before, :all)
142
+ process(host, globals, :after, :all)
130
143
  end
131
144
 
132
145
  private
133
- def process host, globals, position, scope
146
+
147
+ def process(host, globals, position, scope)
134
148
  globals[position][scope].each do |hook|
135
- unless host.parent_groups.any? { |a| a.hooks[position][scope].include? hook }
136
- self[position][scope] << hook if scope == :each || hook.options_apply?(host)
137
- end
149
+ next unless scope == :each || hook.options_apply?(host)
150
+ next if host.parent_groups.any? {|a| a.hooks[position][scope].include?(hook)}
151
+ self[position][scope] << hook
138
152
  end
139
153
  end
140
154
  end
141
155
 
142
156
  # @private
143
157
  def hooks
144
- @hooks ||= {
158
+ @hooks ||= HookCollections.new(
145
159
  :around => { :each => AroundHookCollection.new },
146
160
  :before => { :each => HookCollection.new, :all => HookCollection.new, :suite => HookCollection.new },
147
161
  :after => { :each => HookCollection.new, :all => HookCollection.new, :suite => HookCollection.new }
148
- }.extend(RegistersGlobals)
162
+ )
149
163
  end
150
164
 
151
165
  # @api public
@@ -443,12 +457,14 @@ EOS
443
457
  # Runs all of the blocks stored with the hook in the context of the
444
458
  # example. If no example is provided, just calls the hook directly.
445
459
  def run_hook(hook, scope, example_or_group=ExampleGroup.new, initial_procsy=nil)
460
+ return if RSpec.configuration.dry_run?
461
+
446
462
  find_hook(hook, scope, example_or_group, initial_procsy).run
447
463
  end
448
464
 
449
465
  # @private
450
466
  def around_each_hooks_for(example, initial_procsy=nil)
451
- AroundHookCollection.new(parent_groups.map {|a| a.hooks[:around][:each]}.flatten).for(example, initial_procsy)
467
+ AroundHookCollection.new(FlatMap.flat_map(parent_groups) {|a| a.hooks[:around][:each]}).for(example, initial_procsy)
452
468
  end
453
469
 
454
470
  private
@@ -472,11 +488,11 @@ EOS
472
488
  end
473
489
 
474
490
  def before_each_hooks_for(example)
475
- HookCollection.new(parent_groups.reverse.map {|a| a.hooks[:before][:each]}.flatten).for(example)
491
+ HookCollection.new(FlatMap.flat_map(parent_groups.reverse) {|a| a.hooks[:before][:each]}).for(example)
476
492
  end
477
493
 
478
494
  def after_each_hooks_for(example)
479
- HookCollection.new(parent_groups.map {|a| a.hooks[:after][:each]}.flatten).for(example)
495
+ HookCollection.new(FlatMap.flat_map(parent_groups) {|a| a.hooks[:after][:each]}).for(example)
480
496
  end
481
497
 
482
498
  def register_hook prepend_or_append, hook, *args, &block
@@ -502,7 +518,7 @@ EOS
502
518
  end
503
519
 
504
520
  def scope_and_options_from(*args)
505
- return extract_scope_from(args), build_metadata_hash_from(args)
521
+ return extract_scope_from(args), Metadata.build_hash_from(args)
506
522
  end
507
523
 
508
524
  def extract_scope_from(args)