我正在编写我的第一个gem,但对于典型的配置块如何工作有点困惑。为了说明,我想要的是编写类似
的功能MyGem.configure do |c|
c.property1 = 1
c.property2 = 'some string'
end
我的ruby知识不够深入,所以虽然我很高兴使用块,但我不确定如何编写期望块的代码。
如何以这种方式编写要配置的“MyGem”类(可能是通过实例变量)?
答案 0 :(得分:3)
这可能是实现您的示例的可能方式:
class MyGem
Config = Struct.new :property1, :property2 # => MyGem::Config
def self.configure(&config_block)
config_block.call config # => "some string"
end # => :configure
def self.config
@config ||= Config.new # => #<struct MyGem::Config property1=nil, property2=nil>, #<struct MyGem::Config property1=1, property2="some string">
end # => :config
end # => :config
MyGem.configure do |c| # => MyGem
c.property1 = 1 # => 1
c.property2 = 'some string' # => "some string"
end # => "some string"
MyGem.config # => #<struct MyGem::Config property1=1, property2="some string">
但我还提倡在实例上存储状态而不是类:
class MyGem
Config = Struct.new :property1, :property2 # => MyGem::Config
def initialize(&config_block)
config_block.call config # => "some string"
end # => :initialize
def config
@config ||= Config.new # => #<struct MyGem::Config property1=nil, property2=nil>, #<struct MyGem::Config property1=1, property2="some string">
end # => :config
end # => :config
instance = MyGem.new do |c| # => MyGem
c.property1 = 1 # => 1
c.property2 = 'some string' # => "some string"
end # => #<MyGem:0x007fc1691ecb20 @config=#<struct MyGem::Config property1=1, property2="some string">>
instance.config # => #<struct MyGem::Config property1=1, property2="some string">
如果你这样做,你就没有全局状态。请注意,我们可以有多种不同的配置(例如,每个客户端都有自己的配置,或者您想要编写多个测试,但现在每个客户都有可能破坏其他配置)。我写了一篇关于我想到的实现单例模式的方法的博客,以及为什么你不应该这样做:http://blog.8thlight.com/josh-cheek/2012/10/20/implementing-and-testing-the-singleton-pattern-in-ruby.html