diff --git a/benchmarks/singleton_example_groups/with_config_hooks.rb b/benchmarks/singleton_example_groups/with_config_hooks.rb index cf3bd3ac1c..08f49265fd 100644 --- a/benchmarks/singleton_example_groups/with_config_hooks.rb +++ b/benchmarks/singleton_example_groups/with_config_hooks.rb @@ -10,20 +10,19 @@ BenchmarkHelpers.run_benchmarks __END__ - No match -- without singleton group support - 614.535 (±33.8%) i/s - 2.520k + 575.250 (±29.0%) i/s - 2.484k No match -- with singleton group support - 555.190 (±21.1%) i/s - 2.496k + 503.671 (±21.8%) i/s - 2.250k Example match -- without singleton group support - 574.821 (±31.5%) i/s - 2.491k + 544.191 (±25.7%) i/s - 2.160k Example match -- with singleton group support - 436.391 (±25.2%) i/s - 1.872k + 413.538 (±22.2%) i/s - 1.715k Group match -- without singleton group support - 544.063 (±31.4%) i/s - 2.112k + 517.998 (±28.2%) i/s - 2.058k Group match -- with singleton group support - 457.098 (±18.8%) i/s - 1.961k + 431.554 (±15.3%) i/s - 1.960k Both match -- without singleton group support - 554.004 (±30.1%) i/s - 2.255k + 525.306 (±25.1%) i/s - 2.107k in 5.556760s Both match -- with singleton group support - 452.834 (±19.7%) i/s - 1.935k + 440.288 (±16.6%) i/s - 1.848k diff --git a/benchmarks/singleton_example_groups/with_config_hooks_module_inclusions_and_shared_context_inclusions.rb b/benchmarks/singleton_example_groups/with_config_hooks_module_inclusions_and_shared_context_inclusions.rb index b76751d8ec..9eee773b14 100644 --- a/benchmarks/singleton_example_groups/with_config_hooks_module_inclusions_and_shared_context_inclusions.rb +++ b/benchmarks/singleton_example_groups/with_config_hooks_module_inclusions_and_shared_context_inclusions.rb @@ -18,18 +18,18 @@ __END__ No match -- without singleton group support - 452.015 (±33.8%) i/s - 1.900k + 544.396 (±34.0%) i/s - 2.340k No match -- with singleton group support - 464.520 (±31.0%) i/s - 1.887k + 451.635 (±31.0%) i/s - 1.935k Example match -- without singleton group support - 476.961 (±34.6%) i/s - 1.978k in 5.340615s + 538.788 (±23.8%) i/s - 2.450k Example match -- with singleton group support - 76.177 (±34.1%) i/s - 266.000 + 342.990 (±22.4%) i/s - 1.440k Group match -- without singleton group support - 364.554 (±28.3%) i/s - 1.372k + 509.969 (±26.7%) i/s - 2.070k Group match -- with singleton group support - 281.761 (±24.1%) i/s - 1.200k + 405.284 (±20.5%) i/s - 1.518k Both match -- without singleton group support - 281.521 (±27.4%) i/s - 1.188k + 513.344 (±24.0%) i/s - 1.927k Both match -- with singleton group support - 297.886 (±18.1%) i/s - 1.288k + 406.111 (±18.5%) i/s - 1.760k diff --git a/benchmarks/singleton_example_groups/with_module_inclusions.rb b/benchmarks/singleton_example_groups/with_module_inclusions.rb index 8d133c6e0d..e3a8c43fe2 100644 --- a/benchmarks/singleton_example_groups/with_module_inclusions.rb +++ b/benchmarks/singleton_example_groups/with_module_inclusions.rb @@ -11,18 +11,18 @@ __END__ No match -- without singleton group support - 519.880 (±33.9%) i/s - 2.162k + 555.498 (±27.0%) i/s - 2.496k No match -- with singleton group support - 481.334 (±28.5%) i/s - 2.028k + 529.826 (±23.0%) i/s - 2.397k in 5.402305s Example match -- without singleton group support - 491.348 (±29.9%) i/s - 2.068k + 541.845 (±29.0%) i/s - 2.208k Example match -- with singleton group support - 407.257 (±22.3%) i/s - 1.782k + 465.440 (±20.4%) i/s - 2.091k Group match -- without singleton group support - 483.403 (±36.4%) i/s - 1.815k + 530.976 (±24.1%) i/s - 2.303k Group match -- with singleton group support - 424.932 (±29.4%) i/s - 1.804k + 505.291 (±18.8%) i/s - 2.226k Both match -- without singleton group support - 397.831 (±31.9%) i/s - 1.720k + 542.168 (±28.4%) i/s - 2.067k in 5.414905s Both match -- with singleton group support - 424.233 (±25.5%) i/s - 1.720k + 503.226 (±27.2%) i/s - 1.880k in 5.621210s diff --git a/benchmarks/singleton_example_groups/with_no_config_hooks_or_inclusions.rb b/benchmarks/singleton_example_groups/with_no_config_hooks_or_inclusions.rb index 78529f3abb..ec7849d2b1 100644 --- a/benchmarks/singleton_example_groups/with_no_config_hooks_or_inclusions.rb +++ b/benchmarks/singleton_example_groups/with_no_config_hooks_or_inclusions.rb @@ -5,18 +5,18 @@ __END__ No match -- without singleton group support - 504.865 (±31.9%) i/s - 2.128k + 565.198 (±28.8%) i/s - 2.438k No match -- with singleton group support - 463.115 (±26.6%) i/s - 1.998k + 539.781 (±18.9%) i/s - 2.496k Example match -- without singleton group support - 472.825 (±31.9%) i/s - 1.938k + 539.287 (±28.2%) i/s - 2.450k in 5.555471s Example match -- with singleton group support - 436.539 (±33.9%) i/s - 1.840k + 511.576 (±28.1%) i/s - 2.058k Group match -- without singleton group support - 460.643 (±33.4%) i/s - 1.892k + 535.298 (±23.2%) i/s - 2.352k Group match -- with singleton group support - 430.339 (±23.2%) i/s - 1.911k + 539.454 (±19.1%) i/s - 2.350k Both match -- without singleton group support - 406.712 (±26.6%) i/s - 1.848k + 550.932 (±32.1%) i/s - 2.145k in 5.930432s Both match -- with singleton group support - 470.299 (±26.4%) i/s - 1.890k + 540.183 (±19.6%) i/s - 2.300k diff --git a/benchmarks/singleton_example_groups/with_shared_context_inclusions.rb b/benchmarks/singleton_example_groups/with_shared_context_inclusions.rb index 28ab30e365..2d99ec6d2a 100644 --- a/benchmarks/singleton_example_groups/with_shared_context_inclusions.rb +++ b/benchmarks/singleton_example_groups/with_shared_context_inclusions.rb @@ -11,18 +11,18 @@ __END__ No match -- without singleton group support - 503.700 (±33.2%) i/s - 2.184k + 563.304 (±29.6%) i/s - 2.385k No match -- with singleton group support - 471.018 (±26.8%) i/s - 2.009k + 538.738 (±22.3%) i/s - 2.209k Example match -- without singleton group support - 467.859 (±34.8%) i/s - 2.021k in 5.600106s + 546.605 (±25.6%) i/s - 2.450k Example match -- with singleton group support - 84.138 (±34.5%) i/s - 296.000 in 5.515586s + 421.111 (±23.5%) i/s - 1.845k Group match -- without singleton group support - 384.144 (±27.9%) i/s - 1.560k + 536.267 (±27.4%) i/s - 2.050k Group match -- with singleton group support - 349.301 (±27.5%) i/s - 1.288k + 508.644 (±17.7%) i/s - 2.268k Both match -- without singleton group support - 388.100 (±25.8%) i/s - 1.702k + 538.047 (±27.7%) i/s - 2.067k in 5.431649s Both match -- with singleton group support - 339.310 (±20.3%) i/s - 1.504k + 505.388 (±26.7%) i/s - 1.880k in 5.578614s diff --git a/lib/rspec/core/configuration.rb b/lib/rspec/core/configuration.rb index a2a03d0481..f5dd8f9543 100644 --- a/lib/rspec/core/configuration.rb +++ b/lib/rspec/core/configuration.rb @@ -1158,8 +1158,12 @@ def configure_group_with(group, module_list, application_method) # Used internally to extend the singleton class of a single example's # example group instance with modules using `include` and/or `extend`. def configure_example(example) - @include_modules.items_for(example.metadata).each do |mod| - safe_include(mod, example.example_group_instance.singleton_class) + # We replace the metadata so that SharedExampleGroupModule#included + # has access to the example's metadata[:location]. + example.example_group_instance.singleton_class.with_replaced_metadata(example.metadata) do + @include_modules.items_for(example.metadata).each do |mod| + safe_include(mod, example.example_group_instance.singleton_class) + end end end diff --git a/lib/rspec/core/example_group.rb b/lib/rspec/core/example_group.rb index ffe4f0c49f..184ee946da 100644 --- a/lib/rspec/core/example_group.rb +++ b/lib/rspec/core/example_group.rb @@ -45,7 +45,21 @@ def self.idempotently_define_singleton_method(name, &definition) # The [Metadata](Metadata) object associated with this group. # @see Metadata def self.metadata - @metadata if defined?(@metadata) + @metadata ||= nil + end + + # Temporarily replace the provided metadata. + # Intended primarily to allow an example group's singleton class + # to return the metadata of the example that it exists for. This + # is necessary for shared example group inclusion to work properly + # with singleton example groups. + # @private + def self.with_replaced_metadata(meta) + orig_metadata = metadata + @metadata = meta + yield + ensure + @metadata = orig_metadata end # @private @@ -333,7 +347,7 @@ def self.find_and_eval_shared(label, name, inclusion_location, *args, &customiza raise ArgumentError, "Could not find shared #{label} #{name.inspect}" end - SharedExampleGroupInclusionStackFrame.with_frame(name, inclusion_location) do + SharedExampleGroupInclusionStackFrame.with_frame(name, Metadata.relative_path(inclusion_location)) do module_exec(*args, &shared_block) module_exec(&customization_block) if customization_block end diff --git a/lib/rspec/core/shared_example_group.rb b/lib/rspec/core/shared_example_group.rb index fcffb853e3..4af32607cb 100644 --- a/lib/rspec/core/shared_example_group.rb +++ b/lib/rspec/core/shared_example_group.rb @@ -20,7 +20,8 @@ def inspect # Our definition evaluates the shared group block in the context of the # including example group. def included(klass) - SharedExampleGroupInclusionStackFrame.with_frame(@description, RSpec::CallerFilter.first_non_rspec_line) do + inclusion_line = klass.metadata[:location] + SharedExampleGroupInclusionStackFrame.with_frame(@description, inclusion_line) do klass.class_exec(&@definition) end end diff --git a/spec/rspec/core/metadata_spec.rb b/spec/rspec/core/metadata_spec.rb index f454e3eb9b..5203072dd9 100644 --- a/spec/rspec/core/metadata_spec.rb +++ b/spec/rspec/core/metadata_spec.rb @@ -189,7 +189,7 @@ def metadata_for(*args) expect(meta[:shared_group_inclusion_backtrace]).to match [ an_object_having_attributes( :shared_group_name => "some shared behavior", - :inclusion_location => a_string_including("#{__FILE__}:#{line}") + :inclusion_location => a_string_including("#{Metadata.relative_path __FILE__}:#{line}") ) ] end end @@ -213,7 +213,7 @@ def metadata_for(*args) expect(meta[:shared_group_inclusion_backtrace]).to match [ an_object_having_attributes( :shared_group_name => "some shared behavior", - :inclusion_location => a_string_including("#{__FILE__}:#{line}") + :inclusion_location => a_string_including("#{Metadata.relative_path __FILE__}:#{line}") ) ] end end @@ -239,11 +239,11 @@ def metadata_for(*args) expect(meta[:shared_group_inclusion_backtrace]).to match [ an_object_having_attributes( :shared_group_name => "inner", - :inclusion_location => a_string_including("#{__FILE__}:#{inner_line}") + :inclusion_location => a_string_including("#{Metadata.relative_path __FILE__}:#{inner_line}") ), an_object_having_attributes( :shared_group_name => "outer", - :inclusion_location => a_string_including("#{__FILE__}:#{outer_line}") + :inclusion_location => a_string_including("#{Metadata.relative_path __FILE__}:#{outer_line}") ), ] end