2012-05-14 16 views
14

私はRails環境で、またRails環境なしで作業したい宝石を書いています。宝石を書くときの設定を設定する

私は宝石の設定を可能にする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 

しかし、私がアクセスできるようには思えません私の構成変数は私の宝石の他のクラスとの関係からです。

# spec/spec_helper.rb 
require "name_checker" 

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

と私のコードから設定を参照します:私はそうのように私のspec_helper.rbに宝石を設定するとき例えば、

# 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) 

私のコードで何が間違っていますか?

+1

ここで興味がある可能性があり、他人のために宝石を設定に関する記事があります.thoughtbot.com/mygem-configure-block – Rimian

答えて

17

を試みることのようになります。http://ロボット

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

def self.configure 
    yield(configuration) if block_given? 
end 
-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というクラスを定義しているということで、オーバーライドすることができますそれを定義している間に、Configurationオブジェクトのapi_keyコールの戻り値を印刷しようとしています(したがって、ここではDemeterの法律に違反しています)。誰も実際に設定を定義する前にNetCheckerを定義しているので、これは失敗します。だから、実際にはメソッドがNameCheckerで呼び出される前にapi_keyを要求しているので、nilconfiguration ivarになっています。

私のアドバイスは、過剰性能を除去するためにリファクタリングしてみ;-)もう一度

+1

'Configuration'クラスのポイントは、gemをconfigブロックで設定できるようにすることです。私はこれが宝石を構成する標準的な方法だと思います。私はそれが一般的にいいパターンだとも思っています。しかし、ええ、あなたが "(技術的な)問題"について何を言っているのかは、それで感謝しています。最後に、私の防衛の中で、デメテルの違反は簡潔さの問題のために考案されました! –

+0

configureブロックパターンは完全にオプションで、Railsに由来します。誰もが守っているパターンではありません。主に、Railsがあまりにも多くのコードをロードするのを防ぐために、すべてが起動されたときにconfigureブロック内で起こることがあることがRailsにあります(それが特別なブロックでそれを行う理由です)。 – Julik

+0

ここでの問題は、工学上(またはデメテルの法律に違反して)ではありません。これは、コードが最初に実行される問題です。すべてのOPコードを1つのファイルで実行するとうまく動作します。バグは 'NameChecker.configuration。api_key'は設定オブジェクトが設定される前に実行されます。 – eremzeit

関連する問題