2012-01-29 19 views
21

के बिना ऑटोलोडिंग कक्षाएं मुझे the autoload functionality of Ruby पसंद है; हालांकि, यह going away in future versions of Ruby है क्योंकि यह कभी थ्रेड-सुरक्षित नहीं था।रुबी में अपने 'ऑटोलोड'

तो अभी मैं यह दिखाऊंगा कि यह पहले से ही चला गया है और इसके बिना अपना कोड लिखना है, आलसी लोडिंग तंत्र को स्वयं लागू करना। मैं इसे सबसे सरल तरीके से कार्यान्वित करना चाहता हूं (मुझे अभी थ्रेड-सुरक्षा की परवाह नहीं है)। रूबी हमें ऐसा करने की अनुमति देनी चाहिए।

class Dummy 
    def self.const_missing(const) 
    puts "const_missing(#{const.inspect})" 
    super(const) 
    end 
end 

रूबी इस विशेष विधि जब हम "डमी" गुम है, तो उदाहरण के लिए अगर हम संदर्भ के लिए "डमी कोशिश के तहत एक निरंतर संदर्भ के लिए कोशिश कॉल करेगा: एक वर्ग 'const_missing बढ़ाने से

आइए शुरू: : हैलो ", यह const_missing को प्रतीक :Hello के साथ कॉल करेगा। यह ठीक है कि हम क्या जरूरत है, तो चलो इसे आगे ले जाने: अब

class Dummy 
    def self.const_missing(const) 
    if :OAuth == const 
     require 'dummy/oauth' 
     const_get(const)  # warning: possible endless loop! 
    else 
     super(const) 
    end 
    end 
end 

अगर हम संदर्भ "डमी :: OAuth", यह "डमी/oauth.rb" फाइल जो परिभाषित "की उम्मीद है की आवश्यकता होगी डमी :: ओथ "निरंतर। जब हम const_get पर कॉल करते हैं तो अंतहीन पाश की संभावना होती है (क्योंकि यह आंतरिक रूप से const_missing पर कॉल कर सकती है), लेकिन इसके खिलाफ सुरक्षा इस प्रश्न के दायरे से बाहर है।

बड़ी समस्या है, इस पूरे समाधान अगर वहाँ शीर्ष स्तर के नाम स्थान में "OAuth" नामक एक मॉड्यूल मौजूद टूट जाती है। "डमी :: ओएथ" का संदर्भ देने से const_missing छोड़ दिया जाएगा और केवल शीर्ष स्तर से "ओथ" वापस कर दिया जाएगा। अधिकांश रूबी कार्यान्वयन भी इस बारे में एक चेतावनी देगा:

warning: toplevel constant OAuth referenced by Dummy::OAuth 

This was reported as a problem way back in 2003 लेकिन मैं सबूत नहीं मिला है कि रूबी कोर टीम कभी भी इस बारे में चिंतित था। आज, सबसे लोकप्रिय रूबी कार्यान्वयन एक ही व्यवहार लेते हैं।

समस्या यह है कि const_missing चुपचाप शीर्ष-स्तर के नामस्थान में निरंतर के पक्ष में छोड़ दिया गया है। यह तब नहीं होगा जब "डमी :: ओथ" रूबी के autoload कार्यक्षमता के साथ घोषित किया गया था। कोई विचार यह कैसे काम करता है?

+0

यह एक मूर्खतापूर्ण सुझाव की तरह लगता है, लेकिन आप 'autoload' की सी स्रोत देख सकते हैं? मुझे यकीन है कि आप इसे रूबी स्रोत में कहीं भी पा सकते हैं। यदि आप इसे सीधे रुबी में नहीं कर सकते हैं, तो सी एक्सटेंशन बनाने का विकल्प है (जिसमें दुभाषिया के निडरता तक पहुंच है)। – Linuxios

+0

यह एक विकल्प है। – mislav

+0

एक क्रूर बल की बात की तरह लगता है, लेकिन क्या आप शीर्ष-स्तर की कक्षा पर 'remove_const' नहीं कर सकते? – phoet

उत्तर

5

यह कुछ समय पहले रेल टिकट में उठाया गया था और जब मैंने इसकी जांच की तो वहां कोई रास्ता नहीं दिखाई दिया। समस्या यह है कि रुबी const_missing पर कॉल करने से पहले पूर्वजों की खोज करेगा और चूंकि सभी वर्गों में Object पूर्वजों के रूप में है तो किसी शीर्ष-स्तरीय स्थिरांक हमेशा पाए जाएंगे।

>> class A; end 
>> class B; end 
>> B::A 
(irb):3: warning: toplevel constant A referenced by B::A 

>> B.ancestors 
=> [B, Object, Kernel, BasicObject] 

>> module C; end 
>> module D; end 
>> D::C 
NameError: uninitialized constant D::C 

>> D.ancestors 
=> [D] 
+0

हाँ यह दुर्भाग्यपूर्ण है कि हम इसे कक्षाओं के साथ काम नहीं कर सकते हैं, हालांकि यह जानना अच्छा है कि कम से कम यह मॉड्यूल के साथ काम करता है। धन्यवाद! – mislav

0

मैं ree 1.8.7 (यदि आप एक विशेष संस्करण का उल्लेख नहीं है) अगर मैं const_getconst_missing अंदर उपयोग करते हैं, लेकिन अगर मैं :: का उपयोग नहीं पर आपकी समस्या को मिलता है। मैं eval का उपयोग करना पसंद नहीं है, लेकिन इसे यहाँ काम करता है:

class Dummy 
    def self.const_missing(const) 
    if :OAuth == const 
     require 'dummy/oauth' 
     eval "self::#{const}" 
    else 
     super(const) 
    end 
    end 
end 

module Hello 
end 

Dummy.const_get :Hello # => ::Hello 
Dummy::Hello   # => Dummy::Hello 

काश Module था एक :: विधि ताकि आप self.send :"::", const कर सकता है।

+0

विशिष्ट संस्करणों का उल्लेख नहीं करने के लिए खेद है। मेरी समस्या 1.8.7, 1.9.2, 1.9.3, रुबिनीस (स्थिर और किनारे दोनों) और अन्य में मौजूद है। मैं आपके सुझाव का प्रयास करूंगा, लेकिन मेरे परीक्षण में जो मिला वह मुझे 'const_missing' विधि बिल्कुल नहीं बुलाया गया था। इसलिए इससे कोई फर्क नहीं पड़ता कि मैं इसे कैसे कार्यान्वित करता हूं। – mislav

+0

यह इस बात पर निर्भर करता है कि आप 'const_missing' विधि * के बाहर' Dummy.const_get: Hello' या 'Dummy :: Hello' * का उपयोग करते हैं या नहीं। केवल ':: हैलो'' const_missing' को ट्रिगर करेगा - या कम से कम यह एक रूबी कार्यान्वयन पर मैंने सही किया है। –

0

लेज़ी लोड हो रहा है है एक बहुत ही आम डिजाइन पैटर्न, आप यह कई मायनों में लागू करने कर सकते हैं: आप उसके बाद ही नेमस्पेसिंग के लिए मॉड्यूल का उपयोग कर के बाद से वे Object एक पूर्वज के रूप में, उदाहरण के लिए नहीं है यह काम करेंगे करने के लिए अपने आप को सीमित कर सकते हैं, तो ।जैसे:

class Object 
    def bind(key, &block) 
    @hooks ||= Hash.new{|h,k|h[k]=[]} 
    @hooks[key.to_sym] << [self,block] 
    end 

    def trigger(key) 
    @hooks[key.to_sym].each { |context,block| block.call(context) } 
    end 
end 

तो आप कर सकते हैं

bind :json do 
    require 'json' 
end 

begin 
    JSON.parse("[1,2]") 
rescue 
    trigger :json 
    retry 
end