rspec / rspec-core

RSpec runner and formatters
http://rspec.info
MIT License
1.23k stars 763 forks source link

include of module in example group does not include module constants #2748

Closed dmlary closed 4 years ago

dmlary commented 4 years ago

Subject of the issue

When including a module into an example group, the constants defined within that module are not included in the example group class. This is effectively a duplicate of #41, but I'm reopening because it's not clear from the comments why include in an example group behaves differently from include in ruby.

The examples are running in an instance of their own example group class, the module is listed as an ancestor of the class, but none of the constants are defined. What is preventing the constants from being defined, and is there a workaround?

This matters because I'm working with constants from multiple deeply nested namespaces within a spec.

Your environment

Steps to reproduce

Updated the toy example from #41:

module MyModule
  MyConstant = 1

  def my_method
    2
  end
end

RSpec.describe "including modules" do
  include MyModule

  it "works" do
    expect(my_method).to eq(2)
    expect(MyModule::MyConstant).to eq(1)
  end

  it "doesn't work, but should" do
    expect(MyConstant).to eq(1)
  end
end

Expected behavior

I would expect the MyConstant constant to be defined for the second example.

Actual behavior

Test fails with NameError: uninitialized constant MyConstant

dmlary commented 4 years ago

Yea, I kept digging and I came to the realization that it is ruby's scoping of constant lookups within blocks, nothing to do with rspec or include. What is interesting is that the method calls work, but the constant lookups do not:

class Test
  Value = 3

  def blah
    pp :called
  end
end

t = Test.new
t.instance_eval { blah; pp value: Value }

output:

:called
Traceback (most recent call last):
    2: from constant-problems.rb:31:in `<main>'
    1: from constant-problems.rb:31:in `instance_eval'
constant-problems.rb:31:in `block in <main>': uninitialized constant Value (NameError)

I've seen old posts about constants being lexical scope, but that changing to the Module.nesting followed by ancestors lookup. It does not appear that is the case for closures.

I'll close this issue.