2012-05-14 17 views
14

लिखते समय कॉन्फ़िगरेशन सेटिंग्स सेट अप करना मैं एक मणि लिख रहा हूं जिसे मैं रेल पर्यावरण के साथ और बिना काम करना चाहता हूं।एक मणि

मैं मणि के विन्यास की अनुमति के लिए एक 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_helper.rb में मणि कॉन्फ़िगर करें:

# spec/spec_helper.rb 
require "name_checker" 

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

और मेरे कोड से विन्यास संदर्भ:

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

:

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

मैं एक अपरिभाषित विधि त्रुटि मिलती है मेरे कोड में क्या गलत है?

+1

यहाँ जो दूसरों दिलचस्पी हो सकती है के लिए जवाहरात को विन्यस्त पर एक लेख है // रोबोट .thoughtbot.com/mygem-config-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 

और इसके साथ क्यों नहीं किया जाए? आप यह भी सही बाद में दो उत्पन्न पाठकों को रद्द कर सकते हैं ताकि वे पर्यावरण कि आप की आवश्यकता की उपस्थिति सुनिश्चित ...

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 को परिभाषित कर रहे हैं। इसलिए आप वास्तव में से configure विधि NameChecker पर कॉल करने के लिए अनुरोध कर रहे हैं, इसलिए nil में configuration ivar में nil है।

मेरी सलाह overengineering निकालें और पुन: ;-)

+1

'कॉन्फ़िगरेशन' क्लास का बिंदु मणि को कॉन्फ़िगर ब्लॉक के साथ कॉन्फ़िगर करने की अनुमति देना है। मुझे लगता है कि यह रत्नों को कॉन्फ़िगर करने का मानक तरीका है। मुझे यह भी लगता है कि यह सामान्य रूप से एक अच्छा पैटर्न है। लेकिन हाँ, आप "(तकनीकी) समस्या" के बारे में क्या कहते हैं, इस बारे में समझ में आता है। आखिरकार, मेरी रक्षा में, प्रश्न ब्रेवटी के लिए डेमेटर उल्लंघन का उल्लंघन हुआ! –

+0

विन्यास ब्लॉक पैटर्न पूरी तरह से वैकल्पिक है और रेल से आता है, यह एक पैटर्न नहीं है जो हर कोई पालन करता है। यह सिर्फ इतना है कि रेलों में कुछ चीजें हैं जो कॉन्फ़िगरेशन ब्लॉक में होती हैं जब सबकुछ बूट हो जाता है, मुख्य रूप से रेल को बहुत अधिक कोड लोड करने से रोकने के लिए (यही कारण है कि वे इसे एक विशेष ब्लॉक में करते हैं)। – Julik

+0

यहां समस्या इंजीनियरिंग से अधिक नहीं है (या डेमेटर के कानून का उल्लंघन)। यह एक मुद्दा है कि कौन सा कोड पहले निष्पादित किया जा रहा है। यदि आप एक ही फाइल में सभी ओपी कोड चलाते हैं, तो यह ठीक काम करता है। बग तब होता है जब 'NameChecker.configuration।कॉन्फ़िगरेशन ऑब्जेक्ट पॉप्युलेट होने से पहले api_key' निष्पादित हो जाता है। – eremzeit

संबंधित मुद्दे