ruby - 跨 GEMS 的 Ruby 灵活配置
问题描述
如果 Ruby 应用程序包含附加但可选的子 GEMS,您将如何构建可以自动扩展的单个 GEM 配置。
我正在寻找可以为我正在构建的应用程序提供可扩展配置系统的 Code Pattern 或现有 GEM。
设想
假设您有一个可以发送/接收消息的通信应用程序,它使用一些通用配置。
gem 'communication-app'
您可以安装任意数量的可以通过不同平台发送/接收的提供程序。
gem 'communication-app-facebook'
gem 'communication-app-twitter'
gem 'communication-app-sms'
gem 'communication-app-email'
每个提供者都需要自己的自定义配置。这些应该挂起主配置,并且可以有一个自定义配置图,但只有在安装插件时才可用。
默认配置用法
CommsApp.configure do |config|
config.some_setting2 = 'customised setting'
end
puts CommsApp.configuration.some_setting1
puts CommsApp.configuration.some_setting2
# --> some default value 1
# --> customised setting
示例代码
module CommsApp
class << self
attr_writer :configuration
def configuration
@configuration ||= Configuration.new
end
def configure
yield(configuration)
end
end
class Configuration < BaseConfiguration
attr_accessor :some_setting1
attr_accessor :some_setting2
def initialize
super
@some_setting1 = 'some default value 1'
@some_setting2 = 'some default value 2'
end
end
end
如果我尝试访问未安装的子 GEM 的配置,我预计会看到某种错误。例如。
puts CommsApp.configuration.twitter.access_token
# raises NoMethodError, "unknown method :twitter"
我已经在基本配置上试验了一个类方法,它允许我为新的配置类附加子配置属性。
module CommsApp
class BaseConfiguration
class << self
# Attach a child configuration with it's own settings to a parent configuration
#
# @param [Class] klass_child what class would you like as the child
# @param [Class] klass_parent what class would you like to extend with a new child configuration
# @param [Symbol] accessor_name what is the name of the accessor that you are adding
def attach_to(klass_child, klass_parent, accessor_name)
# Create a memoized getter to an instance of the attaching class (:klass_child)
#
# def third_party
# @third_party ||= ThirdPartyGem::Configuration.new
# end
klass_parent.send(:define_method, accessor_name) do
return instance_variable_get("@#{accessor_name}") if instance_variable_defined?("@#{accessor_name}")
instance_variable_set("@#{accessor_name}", klass_child.new)
end
end
end
end
end
扩展配置使用
这就是可以使用扩展配置的方式。
class ApplicationConfig < CommsApp::Configuration
attach_to(CommsApp::TwitterProvider::Configuration, self, :twitter)
attach_to(CommsApp::FacebookProvider::Configuration, self, :fb)
end
CommsApp.configuration = ApplicationConfig.new
CommsApp.configure do |config|
config.some_setting2 = 'customized setting'
config.twitter.access_token = '123'
config.fb.user_name = 'xmen'
config.fb.account_id = 'xmen123'
end
这种技术工作正常,但它确实需要创建和配置一个自定义类,我希望这在(且仅当)提供者 GEM 存在时自动发生。
我知道我可以弄清楚如何做到这一点,但我想知道是否已经有一种模式或 GEM 可以解决这个特定问题。
解决方案
推荐阅读
- c - 将小数转换为二进制后,我的输出显示的小数位数不超过 6 位。我需要小数点后 12 位
- string - Lua:返回“{foo}{bar}”的内容
- javascript - Highcharts - 实时更新柱形图
- excel - 对应单元格中所有值的总和,针对特定日历月和公司
- node.js - 在 mongo 数据库中创建动态模式
- php - 未捕获的错误:找不到类“PhpAmqpLib\Connection\AMQPStreamConnection”
- html - 在我的 html 模板中以 Angular 6 显示而不是空格
- docker - Kubernetes 从单个节点引用 docker 映像并在任何节点中创建容器
- swift - 为什么我的 DateFormatter .date(from: String) 返回 nil
- pascalscript - 我如何获得 shift+insert 的 ascii 代码