Home > Software design >  Reload class with include
Reload class with include

Time:01-19

In the following situation, where include_class is a preference, can I somehow dynamically change the value of include_class and reload Image such that it instead includes the new value of 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?

Context

I am trying to test whether a configuration option (that is normally set by an initializer) has the correct effects on the application. Because this is part of a test suite the the modules and classes might be loaded before and all configuration changes need to be reset after the test.

CodePudding user response:

I'd suggest to use refinements instead, in this case class will be reset after the test (on any other stuff). I implemented an example without active_concern, but the idea should be clear. This example can be executed with plain ruby as a single script.

# 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
  •  Tags:  
  • Related