rspec-core 3.0.0.beta2 → 3.0.0.rc1
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.yardopts +1 -0
- data/Changelog.md +297 -57
- data/README.md +16 -13
- data/lib/rspec/core.rb +55 -84
- data/lib/rspec/core/backport_random.rb +35 -3
- data/lib/rspec/core/backtrace_formatter.rb +4 -13
- data/lib/rspec/core/configuration.rb +330 -114
- data/lib/rspec/core/configuration_options.rb +38 -22
- data/lib/rspec/core/drb.rb +111 -0
- data/lib/rspec/core/dsl.rb +8 -2
- data/lib/rspec/core/example.rb +203 -94
- data/lib/rspec/core/example_group.rb +344 -316
- data/lib/rspec/core/filter_manager.rb +135 -90
- data/lib/rspec/core/flat_map.rb +1 -0
- data/lib/rspec/core/formatters.rb +50 -14
- data/lib/rspec/core/formatters/base_formatter.rb +32 -138
- data/lib/rspec/core/formatters/base_text_formatter.rb +32 -253
- data/lib/rspec/core/formatters/console_codes.rb +65 -0
- data/lib/rspec/core/formatters/deprecation_formatter.rb +24 -15
- data/lib/rspec/core/formatters/documentation_formatter.rb +7 -10
- data/lib/rspec/core/formatters/helpers.rb +15 -9
- data/lib/rspec/core/formatters/html_formatter.rb +17 -16
- data/lib/rspec/core/formatters/html_printer.rb +1 -0
- data/lib/rspec/core/formatters/json_formatter.rb +18 -20
- data/lib/rspec/core/formatters/profile_formatter.rb +67 -0
- data/lib/rspec/core/formatters/progress_formatter.rb +6 -7
- data/lib/rspec/core/formatters/snippet_extractor.rb +8 -6
- data/lib/rspec/core/hooks.rb +131 -125
- data/lib/rspec/core/memoized_helpers.rb +31 -26
- data/lib/rspec/core/metadata.rb +277 -184
- data/lib/rspec/core/metadata_filter.rb +86 -0
- data/lib/rspec/core/minitest_assertions_adapter.rb +28 -0
- data/lib/rspec/core/mocking_adapters/flexmock.rb +1 -1
- data/lib/rspec/core/mocking_adapters/mocha.rb +1 -1
- data/lib/rspec/core/mocking_adapters/null.rb +1 -1
- data/lib/rspec/core/mocking_adapters/rr.rb +2 -1
- data/lib/rspec/core/mocking_adapters/rspec.rb +1 -1
- data/lib/rspec/core/notifications.rb +435 -24
- data/lib/rspec/core/option_parser.rb +16 -25
- data/lib/rspec/core/ordering.rb +3 -1
- data/lib/rspec/core/pending.rb +57 -33
- data/lib/rspec/core/project_initializer.rb +2 -0
- data/lib/rspec/core/project_initializer/spec_helper.rb +5 -4
- data/lib/rspec/core/rake_task.rb +45 -20
- data/lib/rspec/core/reporter.rb +50 -22
- data/lib/rspec/core/ruby_project.rb +1 -0
- data/lib/rspec/core/runner.rb +93 -39
- data/lib/rspec/core/shared_context.rb +7 -5
- data/lib/rspec/core/shared_example_group.rb +85 -77
- data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
- data/lib/rspec/core/version.rb +3 -1
- data/lib/rspec/core/warnings.rb +35 -17
- data/lib/rspec/core/world.rb +57 -5
- metadata +56 -369
- metadata.gz.sig +3 -3
- data/features/README.md +0 -13
- data/features/Upgrade.md +0 -352
- data/features/command_line/README.md +0 -25
- data/features/command_line/dry_run.feature +0 -29
- data/features/command_line/example_name_option.feature +0 -97
- data/features/command_line/exit_status.feature +0 -82
- data/features/command_line/fail_fast.feature +0 -26
- data/features/command_line/format_option.feature +0 -75
- data/features/command_line/init.feature +0 -57
- data/features/command_line/line_number_appended_to_path.feature +0 -140
- data/features/command_line/line_number_option.feature +0 -58
- data/features/command_line/order.feature +0 -25
- data/features/command_line/pattern_option.feature +0 -49
- data/features/command_line/rake_task.feature +0 -122
- data/features/command_line/randomization.feature +0 -63
- data/features/command_line/require_option.feature +0 -43
- data/features/command_line/ruby.feature +0 -23
- data/features/command_line/tag.feature +0 -98
- data/features/command_line/warnings_option.feature +0 -29
- data/features/configuration/alias_example_to.feature +0 -39
- data/features/configuration/backtrace_exclusion_patterns.feature +0 -105
- data/features/configuration/custom_settings.feature +0 -84
- data/features/configuration/default_path.feature +0 -38
- data/features/configuration/deprecation_stream.feature +0 -58
- data/features/configuration/enable_global_dsl.feature +0 -54
- data/features/configuration/fail_fast.feature +0 -77
- data/features/configuration/failure_exit_code.feature +0 -36
- data/features/configuration/order_and_seed.feature +0 -3
- data/features/configuration/output_stream.feature +0 -24
- data/features/configuration/overriding_global_ordering.feature +0 -93
- data/features/configuration/pattern.feature +0 -38
- data/features/configuration/profile.feature +0 -220
- data/features/configuration/read_options_from_file.feature +0 -90
- data/features/configuration/run_all_when_everything_filtered.feature +0 -76
- data/features/example_groups/aliasing.feature +0 -48
- data/features/example_groups/basic_structure.feature +0 -55
- data/features/example_groups/shared_context.feature +0 -74
- data/features/example_groups/shared_examples.feature +0 -286
- data/features/expectation_framework_integration/configure_expectation_framework.feature +0 -102
- data/features/filtering/exclusion_filters.feature +0 -135
- data/features/filtering/if_and_unless.feature +0 -138
- data/features/filtering/inclusion_filters.feature +0 -101
- data/features/formatters/configurable_colors.feature +0 -31
- data/features/formatters/custom_formatter.feature +0 -68
- data/features/formatters/json_formatter.feature +0 -30
- data/features/formatters/regression_tests.feature +0 -95
- data/features/formatters/text_formatter.feature +0 -46
- data/features/helper_methods/arbitrary_methods.feature +0 -40
- data/features/helper_methods/let.feature +0 -50
- data/features/helper_methods/modules.feature +0 -146
- data/features/hooks/around_hooks.feature +0 -344
- data/features/hooks/before_and_after_hooks.feature +0 -427
- data/features/hooks/filtering.feature +0 -232
- data/features/metadata/current_example.feature +0 -56
- data/features/metadata/described_class.feature +0 -17
- data/features/metadata/user_defined.feature +0 -100
- data/features/mock_framework_integration/use_any_framework.feature +0 -106
- data/features/mock_framework_integration/use_flexmock.feature +0 -94
- data/features/mock_framework_integration/use_mocha.feature +0 -95
- data/features/mock_framework_integration/use_rr.feature +0 -96
- data/features/mock_framework_integration/use_rspec.feature +0 -95
- data/features/pending_and_skipped_examples/README.md +0 -3
- data/features/pending_and_skipped_examples/pending_examples.feature +0 -118
- data/features/pending_and_skipped_examples/skipped_examples.feature +0 -106
- data/features/spec_files/arbitrary_file_suffix.feature +0 -13
- data/features/step_definitions/additional_cli_steps.rb +0 -83
- data/features/subject/explicit_subject.feature +0 -101
- data/features/subject/implicit_subject.feature +0 -63
- data/features/subject/one_liner_syntax.feature +0 -71
- data/features/support/env.rb +0 -21
- data/features/support/require_expect_syntax_in_aruba_specs.rb +0 -16
- data/features/support/rubinius.rb +0 -6
- data/lib/rspec/core/command_line.rb +0 -35
- data/lib/rspec/core/drb_command_line.rb +0 -26
- data/lib/rspec/core/drb_options.rb +0 -87
- data/lib/rspec/core/formatters/legacy_formatter.rb +0 -227
- data/lib/rspec/core/shared_example_group/collection.rb +0 -27
- data/spec/command_line/order_spec.rb +0 -211
- data/spec/rspec/core/backtrace_formatter_spec.rb +0 -230
- data/spec/rspec/core/command_line_spec.rb +0 -112
- data/spec/rspec/core/command_line_spec_output.txt +0 -0
- data/spec/rspec/core/configuration_options_spec.rb +0 -409
- data/spec/rspec/core/configuration_spec.rb +0 -1479
- data/spec/rspec/core/drb_command_line_spec.rb +0 -102
- data/spec/rspec/core/drb_options_spec.rb +0 -193
- data/spec/rspec/core/dsl_spec.rb +0 -88
- data/spec/rspec/core/example_group_spec.rb +0 -1533
- data/spec/rspec/core/example_spec.rb +0 -642
- data/spec/rspec/core/filter_manager_spec.rb +0 -229
- data/spec/rspec/core/formatters/base_formatter_spec.rb +0 -64
- data/spec/rspec/core/formatters/base_text_formatter_spec.rb +0 -303
- data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +0 -208
- data/spec/rspec/core/formatters/documentation_formatter_spec.rb +0 -75
- data/spec/rspec/core/formatters/helpers_spec.rb +0 -104
- data/spec/rspec/core/formatters/html_formatted-2.1.0.html +0 -392
- data/spec/rspec/core/formatters/html_formatted.html +0 -397
- data/spec/rspec/core/formatters/html_formatter_spec.rb +0 -122
- data/spec/rspec/core/formatters/json_formatter_spec.rb +0 -206
- data/spec/rspec/core/formatters/legacy_formatter_spec.rb +0 -137
- data/spec/rspec/core/formatters/progress_formatter_spec.rb +0 -43
- data/spec/rspec/core/formatters/snippet_extractor_spec.rb +0 -26
- data/spec/rspec/core/formatters_spec.rb +0 -120
- data/spec/rspec/core/hooks_filtering_spec.rb +0 -227
- data/spec/rspec/core/hooks_spec.rb +0 -294
- data/spec/rspec/core/memoized_helpers_spec.rb +0 -495
- data/spec/rspec/core/metadata_spec.rb +0 -491
- data/spec/rspec/core/option_parser_spec.rb +0 -262
- data/spec/rspec/core/ordering_spec.rb +0 -102
- data/spec/rspec/core/pending_example_spec.rb +0 -117
- data/spec/rspec/core/pending_spec.rb +0 -8
- data/spec/rspec/core/project_initializer_spec.rb +0 -73
- data/spec/rspec/core/rake_task_spec.rb +0 -146
- data/spec/rspec/core/random_spec.rb +0 -47
- data/spec/rspec/core/reporter_spec.rb +0 -155
- data/spec/rspec/core/resources/a_bar.rb +0 -0
- data/spec/rspec/core/resources/a_foo.rb +0 -0
- data/spec/rspec/core/resources/a_spec.rb +0 -1
- data/spec/rspec/core/resources/custom_example_group_runner.rb +0 -14
- data/spec/rspec/core/resources/formatter_specs.rb +0 -58
- data/spec/rspec/core/resources/utf8_encoded.rb +0 -8
- data/spec/rspec/core/rspec_matchers_spec.rb +0 -45
- data/spec/rspec/core/ruby_project_spec.rb +0 -26
- data/spec/rspec/core/runner_spec.rb +0 -151
- data/spec/rspec/core/shared_context_spec.rb +0 -102
- data/spec/rspec/core/shared_example_group/collection_spec.rb +0 -57
- data/spec/rspec/core/shared_example_group_spec.rb +0 -114
- data/spec/rspec/core/warnings_spec.rb +0 -29
- data/spec/rspec/core/world_spec.rb +0 -142
- data/spec/rspec/core_spec.rb +0 -91
- data/spec/spec_helper.rb +0 -160
- data/spec/support/config_options_helper.rb +0 -13
- data/spec/support/formatter_support.rb +0 -83
- data/spec/support/helper_methods.rb +0 -26
- data/spec/support/isolate_load_path_mutation.rb +0 -5
- data/spec/support/isolated_directory.rb +0 -10
- data/spec/support/isolated_home_directory.rb +0 -16
- data/spec/support/legacy_formatter_using_sub_classing_example.rb +0 -87
- data/spec/support/matchers.rb +0 -85
- data/spec/support/mathn_integration_support.rb +0 -12
- data/spec/support/old_style_formatter_example.rb +0 -69
- data/spec/support/shared_example_groups.rb +0 -13
- data/spec/support/spec_files.rb +0 -44
- data/spec/support/stderr_splitter.rb +0 -36
@@ -1,5 +1,9 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Core
|
3
|
+
# This module is included in {ExampleGroup}, making the methods
|
4
|
+
# available to be called from within example blocks.
|
5
|
+
#
|
6
|
+
# @see ClassMethods
|
3
7
|
module MemoizedHelpers
|
4
8
|
# @note `subject` was contributed by Joe Ferris to support the one-liner
|
5
9
|
# syntax embraced by shoulda matchers:
|
@@ -41,13 +45,13 @@ module RSpec
|
|
41
45
|
# end
|
42
46
|
#
|
43
47
|
# @note Because `subject` is designed to create state that is reset between
|
44
|
-
# each example, and `before(:
|
48
|
+
# each example, and `before(:context)` is designed to setup state that is
|
45
49
|
# shared across _all_ examples in an example group, `subject` is _not_
|
46
|
-
# intended to be used in a `before(:
|
47
|
-
# a warning when you reference a `subject` from `before(:all)` and we plan
|
48
|
-
# to have it raise an error in RSpec 3.
|
50
|
+
# intended to be used in a `before(:context)` hook.
|
49
51
|
#
|
50
52
|
# @see #should
|
53
|
+
# @see #should_not
|
54
|
+
# @see #is_expected
|
51
55
|
def subject
|
52
56
|
__memoized.fetch(:subject) do
|
53
57
|
__memoized[:subject] = begin
|
@@ -115,7 +119,7 @@ module RSpec
|
|
115
119
|
expect(subject)
|
116
120
|
end
|
117
121
|
|
118
|
-
|
122
|
+
private
|
119
123
|
|
120
124
|
# @private
|
121
125
|
def __memoized
|
@@ -123,14 +127,14 @@ module RSpec
|
|
123
127
|
end
|
124
128
|
|
125
129
|
# Used internally to customize the behavior of the
|
126
|
-
# memoized hash when used in a `before(:
|
130
|
+
# memoized hash when used in a `before(:context)` hook.
|
127
131
|
#
|
128
132
|
# @private
|
129
|
-
class
|
130
|
-
def self.
|
133
|
+
class ContextHookMemoizedHash
|
134
|
+
def self.isolate_for_context_hook(example_group_instance)
|
131
135
|
hash = self
|
132
136
|
|
133
|
-
example_group_instance.
|
137
|
+
example_group_instance.instance_exec do
|
134
138
|
@__memoized = hash
|
135
139
|
|
136
140
|
begin
|
@@ -159,9 +163,10 @@ is reset between each example, while #{hook_expression} exists to
|
|
159
163
|
EOS
|
160
164
|
end
|
161
165
|
|
166
|
+
# @private
|
162
167
|
class Before < self
|
163
168
|
def self.hook_expression
|
164
|
-
"`before(:
|
169
|
+
"`before(:context)`"
|
165
170
|
end
|
166
171
|
|
167
172
|
def self.article
|
@@ -173,9 +178,10 @@ EOS
|
|
173
178
|
end
|
174
179
|
end
|
175
180
|
|
181
|
+
# @private
|
176
182
|
class After < self
|
177
183
|
def self.hook_expression
|
178
|
-
"`after(:
|
184
|
+
"`after(:context)`"
|
179
185
|
end
|
180
186
|
|
181
187
|
def self.article
|
@@ -188,10 +194,9 @@ EOS
|
|
188
194
|
end
|
189
195
|
end
|
190
196
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
197
|
+
# This module is extended onto {ExampleGroup}, making the methods
|
198
|
+
# available to be called from within example group blocks.
|
199
|
+
# You can think of them as being analagous to class macros.
|
195
200
|
module ClassMethods
|
196
201
|
# Generates a method whose return value is memoized after the first
|
197
202
|
# call. Useful for reducing duplication between examples that assign
|
@@ -206,11 +211,9 @@ EOS
|
|
206
211
|
# though we have yet to see this in practice. You've been warned.
|
207
212
|
#
|
208
213
|
# @note Because `let` is designed to create state that is reset between
|
209
|
-
# each example, and `before(:
|
214
|
+
# each example, and `before(:context)` is designed to setup state that is
|
210
215
|
# shared across _all_ examples in an example group, `let` is _not_
|
211
|
-
# intended to be used in a `before(:
|
212
|
-
# a warning when you reference a `let` from `before(:all)` and we plan
|
213
|
-
# to have it raise an error in RSpec 3.
|
216
|
+
# intended to be used in a `before(:context)` hook.
|
214
217
|
#
|
215
218
|
# @example
|
216
219
|
#
|
@@ -265,7 +268,7 @@ EOS
|
|
265
268
|
# end
|
266
269
|
#
|
267
270
|
# describe Thing do
|
268
|
-
# after(:
|
271
|
+
# after(:example) { Thing.reset_count }
|
269
272
|
#
|
270
273
|
# context "using let" do
|
271
274
|
# let(:thing) { Thing.new }
|
@@ -307,7 +310,7 @@ EOS
|
|
307
310
|
# implicitly in one-liners and explicitly using an intention revealing
|
308
311
|
# name.
|
309
312
|
#
|
310
|
-
# @param [String,Symbol]
|
313
|
+
# @param name [String,Symbol] used to define an accessor with an
|
311
314
|
# intention revealing name
|
312
315
|
# @param block defines the value to be returned by `subject` in examples
|
313
316
|
#
|
@@ -328,6 +331,8 @@ EOS
|
|
328
331
|
# end
|
329
332
|
#
|
330
333
|
# @see MemoizedHelpers#should
|
334
|
+
# @see MemoizedHelpers#should_not
|
335
|
+
# @see MemoizedHelpers#is_expected
|
331
336
|
def subject(name=nil, &block)
|
332
337
|
if name
|
333
338
|
let(name, &block)
|
@@ -366,7 +371,7 @@ EOS
|
|
366
371
|
# end
|
367
372
|
#
|
368
373
|
# describe Thing do
|
369
|
-
# after(:
|
374
|
+
# after(:example) { Thing.reset_count }
|
370
375
|
#
|
371
376
|
# context "using subject" do
|
372
377
|
# subject { Thing.new }
|
@@ -400,7 +405,7 @@ EOS
|
|
400
405
|
end
|
401
406
|
end
|
402
407
|
|
403
|
-
# @
|
408
|
+
# @private
|
404
409
|
#
|
405
410
|
# Gets the LetDefinitions module. The module is mixed into
|
406
411
|
# the example group and is used to hold all let definitions.
|
@@ -425,13 +430,13 @@ EOS
|
|
425
430
|
end
|
426
431
|
end
|
427
432
|
|
428
|
-
# @
|
433
|
+
# @private
|
429
434
|
def self.define_helpers_on(example_group)
|
430
435
|
example_group.__send__(:include, module_for(example_group))
|
431
436
|
end
|
432
437
|
|
433
438
|
if Module.method(:const_defined?).arity == 1 # for 1.8
|
434
|
-
# @
|
439
|
+
# @private
|
435
440
|
#
|
436
441
|
# Gets the named constant or yields.
|
437
442
|
# On 1.8, const_defined? / const_get do not take into
|
@@ -444,7 +449,7 @@ EOS
|
|
444
449
|
end
|
445
450
|
end
|
446
451
|
else
|
447
|
-
# @
|
452
|
+
# @private
|
448
453
|
#
|
449
454
|
# Gets the named constant or yields.
|
450
455
|
# On 1.9, const_defined? / const_get take into account the
|
data/lib/rspec/core/metadata.rb
CHANGED
@@ -24,8 +24,11 @@ module RSpec
|
|
24
24
|
# @see FilterManager
|
25
25
|
# @see Configuration#filter_run_including
|
26
26
|
# @see Configuration#filter_run_excluding
|
27
|
-
|
28
|
-
|
27
|
+
module Metadata
|
28
|
+
# @api private
|
29
|
+
#
|
30
|
+
# @param line [String] current code line
|
31
|
+
# @return [String] relative path to line
|
29
32
|
def self.relative_path(line)
|
30
33
|
line = line.sub(File.expand_path("."), ".")
|
31
34
|
line = line.sub(/\A([^:]+:\d+)$/, '\\1')
|
@@ -50,264 +53,354 @@ module RSpec
|
|
50
53
|
hash
|
51
54
|
end
|
52
55
|
|
53
|
-
|
56
|
+
# @private
|
57
|
+
def self.backtrace_from(block)
|
58
|
+
return caller unless block.respond_to?(:source_location)
|
59
|
+
[block.source_location.join(':')]
|
60
|
+
end
|
54
61
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
+
# @private
|
63
|
+
# Used internally to populate metadata hashes with computed keys
|
64
|
+
# managed by RSpec.
|
65
|
+
class HashPopulator
|
66
|
+
attr_reader :metadata, :user_metadata, :description_args, :block
|
67
|
+
|
68
|
+
def initialize(metadata, user_metadata, description_args, block)
|
69
|
+
@metadata = metadata
|
70
|
+
@user_metadata = user_metadata
|
71
|
+
@description_args = description_args
|
72
|
+
@block = block
|
62
73
|
end
|
63
74
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
75
|
+
def populate
|
76
|
+
ensure_valid_user_keys
|
77
|
+
|
78
|
+
metadata[:execution_result] = Example::ExecutionResult.new
|
79
|
+
metadata[:block] = block
|
80
|
+
metadata[:description_args] = description_args
|
81
|
+
metadata[:description] = build_description_from(*metadata[:description_args])
|
82
|
+
metadata[:full_description] = full_description
|
83
|
+
metadata[:described_class] = described_class
|
84
|
+
|
85
|
+
populate_location_attributes
|
86
|
+
metadata.update(user_metadata)
|
87
|
+
RSpec.configuration.apply_derived_metadata_to(metadata)
|
67
88
|
end
|
68
89
|
|
69
|
-
|
70
|
-
|
71
|
-
def
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
store(:line_number, line_number)
|
79
|
-
when :execution_result
|
80
|
-
store(:execution_result, {})
|
81
|
-
when :describes, :described_class
|
82
|
-
klass = described_class
|
83
|
-
store(:described_class, klass)
|
84
|
-
# TODO (2011-11-07 DC) deprecate :describes as a key
|
85
|
-
store(:describes, klass)
|
86
|
-
when :full_description
|
87
|
-
store(:full_description, full_description)
|
88
|
-
when :description
|
89
|
-
store(:description, build_description_from(*self[:description_args]))
|
90
|
-
when :description_args
|
91
|
-
store(:description_args, [])
|
90
|
+
private
|
91
|
+
|
92
|
+
def populate_location_attributes
|
93
|
+
file_path, line_number = if backtrace = user_metadata.delete(:caller)
|
94
|
+
file_path_and_line_number_from(backtrace)
|
95
|
+
elsif block.respond_to?(:source_location)
|
96
|
+
block.source_location
|
97
|
+
else
|
98
|
+
file_path_and_line_number_from(caller)
|
92
99
|
end
|
93
|
-
end
|
94
100
|
|
95
|
-
|
96
|
-
|
101
|
+
file_path = Metadata.relative_path(file_path)
|
102
|
+
metadata[:file_path] = file_path
|
103
|
+
metadata[:line_number] = line_number.to_i
|
104
|
+
metadata[:location] = "#{file_path}:#{line_number}"
|
97
105
|
end
|
98
106
|
|
99
|
-
def
|
100
|
-
first_caller_from_outside_rspec
|
101
|
-
|
107
|
+
def file_path_and_line_number_from(backtrace)
|
108
|
+
first_caller_from_outside_rspec = backtrace.detect { |l| l !~ CallerFilter::LIB_REGEX }
|
109
|
+
first_caller_from_outside_rspec ||= backtrace.first
|
110
|
+
/(.+?):(\d+)(?:|:\d+)/.match(first_caller_from_outside_rspec).captures
|
102
111
|
end
|
103
112
|
|
104
|
-
def
|
105
|
-
|
113
|
+
def description_separator(parent_part, child_part)
|
114
|
+
if parent_part.is_a?(Module) && child_part =~ /^(#|::|\.)/
|
115
|
+
''
|
116
|
+
else
|
117
|
+
' '
|
118
|
+
end
|
106
119
|
end
|
107
120
|
|
108
|
-
def
|
109
|
-
return
|
110
|
-
|
121
|
+
def build_description_from(parent_description=nil, my_description=nil)
|
122
|
+
return parent_description.to_s unless my_description
|
123
|
+
separator = description_separator(parent_description, my_description)
|
124
|
+
parent_description.to_s + separator + my_description
|
111
125
|
end
|
112
126
|
|
113
|
-
def
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
127
|
+
def ensure_valid_user_keys
|
128
|
+
RESERVED_KEYS.each do |key|
|
129
|
+
if user_metadata.has_key?(key)
|
130
|
+
raise <<-EOM.gsub(/^\s+\|/, '')
|
131
|
+
|#{"*"*50}
|
132
|
+
|:#{key} is not allowed
|
133
|
+
|
|
134
|
+
|RSpec reserves some hash keys for its own internal use,
|
135
|
+
|including :#{key}, which is used on:
|
136
|
+
|
|
137
|
+
| #{CallerFilter.first_non_rspec_line}.
|
138
|
+
|
|
139
|
+
|Here are all of RSpec's reserved hash keys:
|
140
|
+
|
|
141
|
+
| #{RESERVED_KEYS.join("\n ")}
|
142
|
+
|#{"*"*50}
|
143
|
+
EOM
|
144
|
+
end
|
118
145
|
end
|
119
|
-
|
120
|
-
description
|
121
146
|
end
|
122
147
|
end
|
123
148
|
|
124
|
-
#
|
125
|
-
|
126
|
-
|
127
|
-
|
149
|
+
# @private
|
150
|
+
class ExampleHash < HashPopulator
|
151
|
+
def self.create(group_metadata, user_metadata, description, block)
|
152
|
+
example_metadata = group_metadata.dup
|
153
|
+
group_metadata = Hash.new(&ExampleGroupHash.backwards_compatibility_default_proc do |hash|
|
154
|
+
hash[:parent_example_group]
|
155
|
+
end)
|
156
|
+
group_metadata.update(example_metadata)
|
157
|
+
|
158
|
+
example_metadata[:example_group] = group_metadata
|
159
|
+
example_metadata.delete(:parent_example_group)
|
160
|
+
|
161
|
+
hash = new(example_metadata, user_metadata, [description].compact, block)
|
162
|
+
hash.populate
|
163
|
+
hash.metadata
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
128
167
|
|
129
168
|
def described_class
|
130
|
-
|
169
|
+
metadata[:example_group][:described_class]
|
131
170
|
end
|
132
171
|
|
133
172
|
def full_description
|
134
|
-
build_description_from(
|
173
|
+
build_description_from(
|
174
|
+
metadata[:example_group][:full_description],
|
175
|
+
metadata[:description]
|
176
|
+
)
|
135
177
|
end
|
136
178
|
end
|
137
179
|
|
138
|
-
#
|
139
|
-
|
140
|
-
|
141
|
-
|
180
|
+
# @private
|
181
|
+
class ExampleGroupHash < HashPopulator
|
182
|
+
def self.create(parent_group_metadata, user_metadata, *args, &block)
|
183
|
+
group_metadata = hash_with_backwards_compatibility_default_proc
|
184
|
+
group_metadata.update(parent_group_metadata)
|
185
|
+
group_metadata[:parent_example_group] = parent_group_metadata
|
186
|
+
|
187
|
+
hash = new(group_metadata, user_metadata, args, block)
|
188
|
+
hash.populate
|
189
|
+
hash.metadata
|
190
|
+
end
|
142
191
|
|
143
|
-
def
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
192
|
+
def self.hash_with_backwards_compatibility_default_proc
|
193
|
+
Hash.new(&backwards_compatibility_default_proc { |hash| hash })
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.backwards_compatibility_default_proc(&example_group_selector)
|
197
|
+
Proc.new do |hash, key|
|
198
|
+
case key
|
199
|
+
when :example_group
|
200
|
+
RSpec.deprecate("The `:example_group` key in an example group's metadata hash",
|
201
|
+
:replacement => "the example group's hash directly for the " +
|
202
|
+
"computed keys and `:parent_example_group` to access the parent " +
|
203
|
+
"example group metadata")
|
204
|
+
LegacyExampleGroupHash.new(example_group_selector.call(hash))
|
205
|
+
when :example_group_block
|
206
|
+
RSpec.deprecate("`metadata[:example_group_block]`",
|
207
|
+
:replacement => "`metadata[:block]`")
|
208
|
+
hash[:block]
|
209
|
+
when :describes
|
210
|
+
RSpec.deprecate("`metadata[:describes]`",
|
211
|
+
:replacement => "`metadata[:described_class]`")
|
212
|
+
hash[:described_class]
|
150
213
|
end
|
151
214
|
end
|
215
|
+
end
|
152
216
|
|
153
|
-
|
154
|
-
candidate = g[:description_args].first
|
155
|
-
return candidate unless String === candidate || Symbol === candidate
|
156
|
-
end
|
217
|
+
private
|
157
218
|
|
158
|
-
|
219
|
+
def described_class
|
220
|
+
candidate = metadata[:description_args].first
|
221
|
+
return candidate unless NilClass === candidate || String === candidate
|
222
|
+
parent_group = metadata[:parent_example_group]
|
223
|
+
parent_group && parent_group[:described_class]
|
159
224
|
end
|
160
225
|
|
161
226
|
def full_description
|
162
|
-
|
163
|
-
|
227
|
+
description = metadata[:description]
|
228
|
+
parent_example_group = metadata[:parent_example_group]
|
229
|
+
parent_description = parent_example_group[:full_description]
|
230
|
+
|
231
|
+
return description unless parent_description
|
164
232
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
groups << group[:example_group]
|
170
|
-
group = group[:example_group]
|
171
|
-
end
|
172
|
-
groups
|
173
|
-
end
|
233
|
+
separator = description_separator(parent_example_group[:description_args].last,
|
234
|
+
metadata[:description_args].first)
|
235
|
+
|
236
|
+
parent_description + separator + description
|
174
237
|
end
|
175
238
|
end
|
176
239
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
240
|
+
# @private
|
241
|
+
RESERVED_KEYS = [
|
242
|
+
:description,
|
243
|
+
:example_group,
|
244
|
+
:parent_example_group,
|
245
|
+
:execution_result,
|
246
|
+
:file_path,
|
247
|
+
:full_description,
|
248
|
+
:line_number,
|
249
|
+
:location,
|
250
|
+
:block
|
251
|
+
]
|
252
|
+
end
|
184
253
|
|
185
|
-
|
254
|
+
# Mixin that makes the including class imitate a hash for backwards
|
255
|
+
# compatibility. The including class should use `attr_accessor` to
|
256
|
+
# declare attributes.
|
257
|
+
# @private
|
258
|
+
module HashImitatable
|
259
|
+
def self.included(klass)
|
260
|
+
klass.extend ClassMethods
|
186
261
|
end
|
187
262
|
|
188
|
-
|
189
|
-
|
190
|
-
user_metadata = args.last.is_a?(Hash) ? args.pop : {}
|
191
|
-
ensure_valid_keys(user_metadata)
|
263
|
+
def to_h
|
264
|
+
hash = extra_hash_attributes.dup
|
192
265
|
|
193
|
-
self
|
194
|
-
|
266
|
+
self.class.hash_attribute_names.each do |name|
|
267
|
+
hash[name] = __send__(name)
|
268
|
+
end
|
195
269
|
|
196
|
-
|
270
|
+
hash
|
197
271
|
end
|
198
272
|
|
199
|
-
|
200
|
-
|
201
|
-
dup.extend(ExampleMetadataHash).configure_for_example(description, user_metadata)
|
202
|
-
end
|
273
|
+
(Hash.public_instance_methods - Object.public_instance_methods).each do |method_name|
|
274
|
+
next if [:[], :[]=, :to_h].include?(method_name.to_sym)
|
203
275
|
|
204
|
-
|
205
|
-
|
206
|
-
filters.any? {|k,v| filter_applies?(k,v)}
|
207
|
-
end
|
276
|
+
define_method(method_name) do |*args, &block|
|
277
|
+
issue_deprecation(method_name, *args)
|
208
278
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
279
|
+
hash = hash_for_delegation
|
280
|
+
self.class.hash_attribute_names.each do |name|
|
281
|
+
hash.delete(name) unless instance_variable_defined?(:"@#{name}")
|
282
|
+
end
|
213
283
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
case value
|
224
|
-
when Regexp
|
225
|
-
metadata[key] =~ value
|
226
|
-
when Proc
|
227
|
-
case value.arity
|
228
|
-
when 0 then value.call
|
229
|
-
when 2 then value.call(metadata[key], metadata)
|
230
|
-
else value.call(metadata[key])
|
284
|
+
hash.__send__(method_name, *args, &block).tap do
|
285
|
+
# apply mutations back to the object
|
286
|
+
hash.each do |name, value|
|
287
|
+
if directly_supports_attribute?(name)
|
288
|
+
set_value(name, value)
|
289
|
+
else
|
290
|
+
extra_hash_attributes[name] = value
|
291
|
+
end
|
292
|
+
end
|
231
293
|
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def [](key)
|
298
|
+
issue_deprecation(:[], key)
|
299
|
+
|
300
|
+
if directly_supports_attribute?(key)
|
301
|
+
get_value(key)
|
232
302
|
else
|
233
|
-
|
303
|
+
extra_hash_attributes[key]
|
234
304
|
end
|
235
305
|
end
|
236
306
|
|
237
|
-
|
238
|
-
|
239
|
-
|
307
|
+
def []=(key, value)
|
308
|
+
issue_deprecation(:[]=, key, value)
|
309
|
+
|
310
|
+
if directly_supports_attribute?(key)
|
311
|
+
set_value(key, value)
|
312
|
+
else
|
313
|
+
extra_hash_attributes[key] = value
|
314
|
+
end
|
240
315
|
end
|
241
316
|
|
242
|
-
|
243
|
-
|
244
|
-
|
317
|
+
private
|
318
|
+
|
319
|
+
def extra_hash_attributes
|
320
|
+
@extra_hash_attributes ||= {}
|
245
321
|
end
|
246
322
|
|
247
|
-
|
248
|
-
|
249
|
-
# it ignores location filters for other files
|
250
|
-
line_number = example_group_declaration_line(locations)
|
251
|
-
line_number ? line_number_filter_applies?(line_number) : true
|
323
|
+
def directly_supports_attribute?(name)
|
324
|
+
self.class.hash_attribute_names.include?(name)
|
252
325
|
end
|
253
326
|
|
254
|
-
|
255
|
-
|
256
|
-
preceding_declaration_lines = line_numbers.map {|n| RSpec.world.preceding_declaration_line(n)}
|
257
|
-
!(relevant_line_numbers & preceding_declaration_lines).empty?
|
327
|
+
def get_value(name)
|
328
|
+
__send__(name)
|
258
329
|
end
|
259
330
|
|
260
|
-
|
331
|
+
def set_value(name, value)
|
332
|
+
__send__(:"#{name}=", value)
|
333
|
+
end
|
261
334
|
|
262
|
-
def
|
263
|
-
|
264
|
-
store(:caller, user_metadata.delete(:caller) || caller)
|
265
|
-
update(user_metadata)
|
335
|
+
def hash_for_delegation
|
336
|
+
to_h
|
266
337
|
end
|
267
338
|
|
268
|
-
|
339
|
+
def issue_deprecation(method_name, *args)
|
340
|
+
# no-op by default: subclasses can override
|
341
|
+
end
|
269
342
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
:full_description,
|
276
|
-
:line_number,
|
277
|
-
:location
|
278
|
-
]
|
343
|
+
# @private
|
344
|
+
module ClassMethods
|
345
|
+
def hash_attribute_names
|
346
|
+
@hash_attribute_names ||= []
|
347
|
+
end
|
279
348
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
349
|
+
def attr_accessor(*names)
|
350
|
+
hash_attribute_names.concat(names)
|
351
|
+
super
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
286
355
|
|
287
|
-
|
288
|
-
|
356
|
+
# @private
|
357
|
+
# Together with the example group metadata hash default block,
|
358
|
+
# provides backwards compatibility for the old `:example_group`
|
359
|
+
# key. In RSpec 2.x, the computed keys of a group's metadata
|
360
|
+
# were exposed from a nested subhash keyed by `[:example_group]`, and
|
361
|
+
# then the parent group's metadata was exposed by sub-subhash
|
362
|
+
# keyed by `[:example_group][:example_group]`.
|
363
|
+
#
|
364
|
+
# In RSpec 3, we reorganized this to that the computed keys are
|
365
|
+
# exposed directly of the group metadata hash (no nesting), and
|
366
|
+
# `:parent_example_group` returns the parent group's metadata.
|
367
|
+
#
|
368
|
+
# Maintaining backwards compatibility was difficult: we wanted
|
369
|
+
# `:example_group` to return an object that:
|
370
|
+
#
|
371
|
+
# * Exposes the top-level metadata keys that used to be nested
|
372
|
+
# under `:example_group`.
|
373
|
+
# * Supports mutation (rspec-rails, for example, assigns
|
374
|
+
# `metadata[:example_group][:described_class]` when you use
|
375
|
+
# anonymous controller specs) such that changes are written
|
376
|
+
# back to the top-level metadata hash.
|
377
|
+
# * Exposes the parent group metadata as `[:example_group][:example_group]`.
|
378
|
+
class LegacyExampleGroupHash
|
379
|
+
include HashImitatable
|
380
|
+
|
381
|
+
def initialize(metadata)
|
382
|
+
@metadata = metadata
|
383
|
+
parent_group_metadata = metadata.fetch(:parent_example_group) { {} }[:example_group]
|
384
|
+
self[:example_group] = parent_group_metadata if parent_group_metadata
|
385
|
+
end
|
289
386
|
|
290
|
-
|
387
|
+
def to_h
|
388
|
+
super.merge(@metadata)
|
389
|
+
end
|
291
390
|
|
292
|
-
|
391
|
+
private
|
293
392
|
|
294
|
-
|
295
|
-
|
296
|
-
EOM
|
297
|
-
end
|
298
|
-
end
|
393
|
+
def directly_supports_attribute?(name)
|
394
|
+
name != :example_group
|
299
395
|
end
|
300
396
|
|
301
|
-
def
|
302
|
-
|
397
|
+
def get_value(name)
|
398
|
+
@metadata[name]
|
303
399
|
end
|
304
400
|
|
305
|
-
|
306
|
-
|
307
|
-
def relevant_line_numbers(metadata=self)
|
308
|
-
[metadata[:line_number]] + (metadata[:example_group] ? relevant_line_numbers(metadata[:example_group]) : [])
|
401
|
+
def set_value(name, value)
|
402
|
+
@metadata[name] = value
|
309
403
|
end
|
310
|
-
|
311
404
|
end
|
312
405
|
end
|
313
406
|
end
|