I'd like to patch parts of an existing library with a config object:
module Library
class A
end
class B
end
end
module Config
def config(&block)
@config ||= block&.call
end
end
module Patch
refine Library::A.singleton_class do
extend Config
config { "my for A" }
end
refine Library::B.singleton_class do
extend Config
config { "my for B" }
end
end
Library::A
should have some predefined config and Library::B
should have its own config. Unfortunately, this throws an error:
using Patch
Library::A.config
=> undefined method `config' for Library::A:Class (NoMethodError)
I guess I don't understand how refinements work in this case. But is there a way to achieve something like this?
here is my solution, basically i include Config
to the Patch
to be able to define configurations at class level, then include
the Patch
itself to the refined classes (Library::A and Library::B) to be able to access the defined configurations.
module Config
def self.included(base)
class << base
def refinement(clazz, patch=self, &block)
$predefined_configs ||= Hash.new
$predefined_configs[clazz] ||= Hash.new
block&.call($predefined_configs[clazz])
refine clazz.singleton_class do
include patch
end
end
end
end
def config
$predefined_configs[self].tap do |_config|
# reuse common configs
_config.merge!({
lang: "ruby"
})
end
end
end
then
module Library
class A; end
class B; end
end
module Patch
include Config
refinement(Library::A) do |_config|
_config[:name] = "my for A"
end
refinement(Library::B) do |_config|
_config[:name] = "my for B"
end
end
class LoadConfig
using Patch
puts Library::A.config # {:name=>"my for A", :lang=>"ruby"}
end
puts Library::A.config # error
using Patch
puts Library::B.config # {:name=>"my for B", :lang=>"ruby"}