我正在构建一个Ruby on Rails单例类,我希望能够在应用程序初始化时配置这个类。
我关注了这篇文章:
http://brandonhilkert.com/blog/ruby-gem-configuration-patterns/https://robots.thoughtbot.com/mygem-configure-block
我所做的更改:
我没有创建 gem 文件,我在加载应用程序时通过将类文件路径添加到 config.autoload_paths
来加载我的单例类
我在"初始值设定项"目录中添加了一个文件,如下所示。
MYClass.configure do |config|
config.api_key = APP_CONFIG['key']
config.api_secret_key = APP_CONFIG['secret_key']
config.base_url ='https://api.domain.com'
config.api_version = 'v2'
end
我的类看起来像这样:
module MYClass
class << self
attr_writer :configuration
#do something just simulate a call to the configuration class
def get_api_config
configuration.api_key
end
end
def self.configuration
@configuration ||= Configuration.new
end
def self.configure
yield(configuration)
end
class Configuration
attr_accessor :api_key, :api_secret_key, :base_url, :api_version
def initialize
@api_key = nil
@api_secret_key = nil
@base_url = 'https://api.domain.com'
@api_version = 'v2'
end
end
end
一切都很好,直到我有例外。
之后,我的配置对象在下一次调用中再次分配MyClass.get_api_config和api_key,api_secret_key are equals to nil
如何使用 extend self
使其成为真正的单例。通常,配置不需要实例化,因为它是整个应用程序中可用的自由浮动单例。试试这个,看看它是如何为你工作的
module MyClass
class << self
def get_api_config
Configuration.api_key
end
def configure
block_given? ? yield(Configuration) : Configuration
end
def configuration
Configuration
end
end
module Configuration
extend self
attr_accessor :api_key, :api_secret_key, :base_url, :api_version
def base_url
@base_url ||= 'https://api.domain.com'
end
def api_version
@api_version ||= 'v2'
end
def config(&block)
instance_eval(&block)
end
end
end
我添加了您使用的所有方法,尽管我认为不需要其中一些。我还为您设置了默认值,而无需为 Configuration
初始化一个类,因为您似乎不需要超过 1 个实例。
现在你可以做这样的事情
MyClass.configure do |config|
config.api_key = "Test KEY"
config.api_secret_key = "Secret"
end
MyClass::Configuration.api_secret_key
#=> "Secret"
MyClass::Configuration.base_url
#=> "https://api.domain.com"
MyClass.configuration.api_version
#=> 'v2'
MyClass.get_api_config
#=> "Test KEY"
MyClass::Configuration.singleton_methods
#=>[:api_key, :api_key=, :api_secret_key, :api_secret_key=,
:base_url, :base_url=, :api_version, :api_version=, :config]
在这种情况下,所有对 MyClass::Configuration 的引用将始终返回相同的内容,无论它们在应用程序中的哪个位置调用。