如何在不污染全局命名空间的情况下在规范中创建 类?

How to create classes in specs without polluting global namespace?

在规范上下文中定义 class 并且不污染全局命名空间的最佳方法是什么?其他文件如何访问该常量?

bowling_spec.rb

require "spec_helper"

describe Bowling do
  context "when validate is defined" do
    let(:dummy_class) {
      Class.new(described_class) do
        METRICS_NAMESPACE = "ExtendedClass.Metrics.namespace"
      end
    }

    it "does nothing" do
      dummy_class 
    end
  end
end

规格 - batting_spec.rb

require "spec_helper"

describe Batting do
  context do
    it "does weird thing" do
      expect { self.class.const_get(:METRICS_NAMESPACE) }.to raise_error(NameError)
    end
  end
end

如果您运行个人规范文件

rspec spec/batting_spec.rb
.

Finished in 0.00285 seconds (files took 0.12198 seconds to load)
1 example, 0 failures

如果您 运行 定义虚拟对象的规范 class

rspec spec/bowling_spec.rb spec/batting_spec.rb
.F

Failures:

  1) Batting  does weird thing
     Failure/Error: expect { self.class.const_get(:METRICS_NAMESPACE) }.to raise_error(NameError)
       expected NameError but nothing was raised
     # ./spec/batting_spec.rb:6:in `block (3 levels) in <top (required)>'

Finished in 0.01445 seconds (files took 0.12715 seconds to load)
2 examples, 1 failure

Failed examples:

rspec ./spec/batting_spec.rb:5 # Batting  does weird thing

重现错误:我创建了一个存储库:https://github.com/pratik60/rspec-pollution 并更新了自述文件

运行 rspec spec/batting_spec.rb spec/bowling_spec.rb

2 examples, 0 failures

运行 rspec spec/bowling_spec.rb spec/batting_spec.rb 给出你提到的错误。

使用binding.pry:

describe Batting do
  context do
    it "does weird thing" do
      require 'pry'
      binding.pry
      expect { self.class.const_get(:METRICS_NAMESPACE) }.to raise_error(NameError)
    end
  end
end

self.class.ancestors

[RSpec::ExampleGroups::Batting::Anonymous,
 RSpec::ExampleGroups::Batting::Anonymous::LetDefinitions,
 RSpec::ExampleGroups::Batting::Anonymous::NamedSubjectPreventSuper,
 RSpec::ExampleGroups::Batting,
 RSpec::ExampleGroups::Batting::LetDefinitions,
 RSpec::ExampleGroups::Batting::NamedSubjectPreventSuper,
 RSpec::Core::ExampleGroup,

沿着继承树往下走

RSpec::Core::ExampleGroup::METRICS_NAMESPACE
(pry):4: warning: toplevel constant METRICS_NAMESPACE referenced by RSpec::Core::ExampleGroup::METRICS_NAMESPACE
=> "ExtendedClass.Metrics.namespace"

检查链上的第一个对象

Object::METRICS_NAMESPACE

=>"ExtendedClass.Metrics.namespace"

更进一步

Class::METRICS_NAMESPACE
(pry):2: warning: toplevel constant METRICS_NAMESPACE referenced by Class::METRICS_NAMESPACE
=> "ExtendedClass.Metrics.namespace"

TL; DR

如您所说,当您执行 METRICS_NAMESPACE = "ExtendedClass.Metrics.namespace" 时,您创建了一个全局命名空间常量。 (也就是最上面的ruby里面的一个常量,Class)

只需这样做即可

Class.new(described_class) do
        self.const_set('METRICS_NAMESPACE', "ExtendedClass.Metrics.namespace")
      end

rspec spec/bowling_spec.rb spec/batting_spec.rb

Finished in 1.55 seconds (files took 0.08012 seconds to load)
2 examples, 0 failures