Skip to content

Get rid of the code poking around RSpec's internals #2365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 3, 2020
Merged

Conversation

pirj
Copy link
Member

@pirj pirj commented Jul 27, 2020

Problem

We used to access and replace RSpec.configuration and RSpec.world in several places.
This was prone to error, since those two can run out of sync, e.g.:

with_isolated_config do
  RSpec::Core::ExampleGroup.describe('a view') { it { } }
  RSpec.configuration.world.example_groups # => []
end

This case specifically is due to in RSpec::Core::ExampleGroup.describe:

RSpec.world.example_groups

Also, we were using this:

  config.around(:example) do |example|
    real_world = RSpec.world
    RSpec.instance_variable_set(:@world, RSpec::Core::World.new)
    example.run
    RSpec.instance_variable_set(:@world, real_world)
  end

RSpec::Core::Configuration.new gets its own world:

  def with_isolated_config
    original_config = RSpec.configuration
    RSpec.configuration = RSpec::Core::Configuration.new

which is an RSpec::Core::World::Null.

I have strong doubts if it would make sense to change the Core to:

- RSpec.world.example_groups
+ RSpec.configuration.world.example_groups

Not to say that those hooks and helpers dig too deep into RSpec's internals.

Solution

It's our lucky day! RSpec provides sandboxing out of the box.

@pirj pirj self-assigned this Jul 27, 2020
@pirj pirj requested a review from JonRowe July 27, 2020 22:14
@JonRowe
Copy link
Member

JonRowe commented Jul 28, 2020

So we shouldn't be doing this:

config.around(:example) do |example|
  real_world = RSpec.world
  RSpec.instance_variable_set(:@world, RSpec::Core::World.new)
  example.run
  RSpec.instance_variable_set(:@world, real_world)
end

We're reaching into RSpec's internals and this gem is no longer supposed to be doing that.

I would like us to eliminate this, and if that requires refactoring the world to not be so global, thats a good thing.

@pirj
Copy link
Member Author

pirj commented Jul 28, 2020

I think I've found a better solution.

@pirj pirj changed the title Set the world for an isolated config Get rid of access to RSpec's internals Jul 28, 2020
@pirj pirj changed the title Get rid of access to RSpec's internals Get rid of the code poking around RSpec's internals Jul 28, 2020
@pirj pirj requested a review from benoittgt July 28, 2020 20:39
@pirj
Copy link
Member Author

pirj commented Jul 28, 2020

end

config.include RSpec::Rails::FeatureCheck
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was included in Helpers that didn't hesitate to include itself in RSpec.configuration.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean does it have any effect? It can't have been used very often...

Copy link
Member Author

@pirj pirj Jul 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

36 failures, 100% in generator specs, all undefined method 'type_metatag'.
Besides type_metatag, generator specs use no methods from FeatureCheck.

I'll include this module exclusively to generator specs.

Frankly, I don't see a good reason for this method to exist:

      def type_metatag(type)
        "type: :#{type}"
      end

but I'd prefer to avoid this unrelated refactoring here.

end

config.include RSpec::Rails::FeatureCheck
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean does it have any effect? It can't have been used very often...

end

config.include RSpec::Rails::FeatureCheck, type: :generator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not just include this where it's used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can, but type_metatag is used in every one of them except for install generator spec.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intended to get rid of this method altogether, replacing all usages to type: :some_type, and this include as well.
Ok to keep it here and remove in a follow-up?
Or keep type_metatag and inline includes into generator specs?
Or keep this include as is and leave type_metatag alone?
I don't have a preference here, up to you.

Copy link
Member

@JonRowe JonRowe Aug 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you can remove this from here, and add it here:

module RSpec
  module Rails
    module Specs
      module Generators
        module Macros
        # spec/support/generators.rb:18
        def self.included(klass)
          klass.extend(Macros)
          klass.include(RSpec::Rails::FeatureCheck)
        end

Which I think is neater until a later refactoring is done.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Done.

@JonRowe JonRowe changed the base branch from master to main August 2, 2020 02:13
@pirj pirj requested a review from JonRowe August 2, 2020 16:24
Our previous code was prone to out-of-sync worlds:

    with_isolated_config do
      RSpec::Core::ExampleGroup.describe('a view') { it { } }
      RSpec.configuration.world.example_groups # => []
    end
@JonRowe JonRowe merged commit 45492fd into main Aug 3, 2020
@JonRowe JonRowe deleted the sync-worlds branch August 3, 2020 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants