14

Rails環境の有無にかかわらず作業したいgemを書いています。

私はConfiguration宝石の設定を許可するクラスを持っています:

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ようになります。

# 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

そしてそれで終わりですか?生成された 2 つのリーダーをすぐにオーバーライドして、必要な環境が確実に存在するようにすることもできます...

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の戻り値を出力しようとしていることです(したがって、ここでデメテルの法則に違反しています)。誰もが実際に構成を定義する時間がなくなる前に定義しているため、これは失敗します。したがって、実際には、メソッドが on で呼び出される前にリクエストしているため、ivarに含まれています。api_keyConfigurationNetCheckerapi_keyconfigureNameCheckernilconfiguration

私のアドバイスは、オーバーエンジニアリングを取り除き、もう一度やり直すことです;-)

于 2012-05-14T14:40:44.820 に答える