14

我正在编写一个我想在有或没有 Rails 环境的情况下使用的 gem。

我有一个Configuration允许配置 gem 的类:

module NameChecker
  class Configuration
    attr_accessor :api_key, :log_level

    def initialize
      self.api_key = nil
      self.log_level = 'info'
    end
  end

  class << self
    attr_accessor :configuration
  end

  def self.configure
    self.configuration ||= Configuration.new
    yield(configuration) if block_given?
  end
end

现在可以这样使用:

NameChecker.configure do |config|
  config.api_key = 'dfskljkf'
end

但是,我似乎无法从我的 gem 中的其他类中访问我的配置变量。例如,当我spec_helper.rb像这样配置 gem 时:

# spec/spec_helper.rb
require "name_checker"

NameChecker.configure do |config|
  config.api_key = 'dfskljkf'
end

并从我的代码中引用配置:

# lib/name_checker/net_checker.rb
module NameChecker
  class NetChecker
    p NameChecker.configuration.api_key
  end
end

我得到一个未定义的方法错误:

`<class:NetChecker>': undefined method `api_key' for nil:NilClass (NoMethodError)

我的代码有什么问题?

4

2 回答 2

18

尝试重构为:

def self.configuration
  @configuration ||=  Configuration.new
end

def self.configure
  yield(configuration) if block_given?
end
于 2012-11-20T04:30:11.847 回答
-2

主要问题是您应用了太多间接性。你为什么不做

module NameChecker
  class << self
    attr_accessor :api_key, :log_level
  end
end

并完成它?您还可以在之后立即覆盖两个生成的阅读器,以确保它们存在您需要的环境......

module NameChecker
  class << self
    attr_accessor :api_key, :log_level

    def api_key
      raise "NameChecker really needs is't api_key set to work" unless @api_key
      @api_key
    end

    DEFAULT_LOG_LEVEL = 'info'

    def log_level
      @log_level || DEFAULT_LOG_LEVEL
    end

  end
end

现在,实际(技术)问题是您正在定义一个名为的类NetChecker,并且在定义它时您试图api_key在假定的Configuration对象上打印调用的返回值(因此您在这里违反了得墨忒耳定律)。这失败了,因为您NetChecker在任何人真正有时间定义任何配置之前进行定义。所以你实际上是在调用方法api_key之前请求的,所以它在它的ivar 中。configureNameCheckernilconfiguration

我的建议是删除过度工程并重试;-)

于 2012-05-14T14:40:44.820 回答