使用 include 重新加载 class

Reload class with include

在以下情况下,include_class 是首选项,我能否以某种方式动态更改 include_class 的值并重新加载 Image,使其包含新值 include_class?

module Foo
  included do
    @test_var = :foo
  end
end

module Bar
  included do
    @test_var = :bar
  end
end

Config.include_class = Foo

class Image
  include Config.include_class
end

# ... run tests with default configuration for Image, where Image.test_var = :foo

Config.include_class = OtherClass

# ... how can I reload or re-evaluate Image such that Image.test_var = :bar?

上下文

我正在尝试测试配置选项(通常由初始化程序设置)是否对应用程序有正确的影响。因为这是测试套件的一部分,模块和 类 可能会在之前加载,并且所有配置更改都需要在测试后重置。

我建议改用 refinements,在这种情况下 class 将在测试后重置(在任何其他内容上)。我实现了一个没有active_concern的例子,但是思路应该很清晰。这个例子可以用普通的 ruby 作为一个脚本来执行。

# This part is just to keep close to your example
class Config
  def self.include_class=(klass)
    @@include_class = klass
  end

  def self.include_class
    @@include_class ||= nil
  end
end

# Assuming Bar is a default module and Foo will be used in tests
module Bar
  def print_something
    puts 'I am Bar'
  end
end

module Foo
  def print_something
    puts 'I am Foo'
  end
end

# Setting default module
Config.include_class = Bar

# Defining Image class
class Image
  include Config.include_class
end

#Changing config
Config.include_class = Foo

# This is a refinement
module ImagePatch
  # It will include current Config.include_class
  # Note that methods from Bar that are not present in Foo will not be removed
  refine Image do
    include Config.include_class
  end
end

# Here we will create module where refinement is activated
module TestEnv
  # Activating the patch
  using ImagePatch
  Image.new.print_something #=>I am Foo
end

#Outside of the TestEnv module we enjoy the default Image class
Image.new.print_something #=>I am Bar