首页 > 解决方案 > ruby 中的可配置改进

问题描述

我想用配置对象修补现有库的一部分:

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应该有一些预定义的配置,并且Library::B应该有自己的配置。不幸的是,这会引发错误:

using Patch
Library::A.config
=> undefined method `config' for Library::A:Class (NoMethodError)

我想我不明白在这种情况下如何进行改进。但是有没有办法实现这样的目标?

标签: rubyrefinements

解决方案


这是我的解决方案,基本上include ConfigPatch为了能够在类级别定义配置,然后includePatch自身到精炼类(Library::A 和 Library::B),以便能够访问定义的配置。

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

然后

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"}

推荐阅读