मॉड्यूल (और कक्षाएं) नेस्टेड होने के लिए हैं। कोड के टुकड़े जैसे ActiveRecord::RecordNotFound
इतने सामान्य हैं कि हम उनके बारे में दो बार नहीं सोचते। लेकिन रूबी के घोंसले के कार्यान्वयन के भीतर दफन - और रेल 'ऑटोलैड सिस्टम - कुछ जाल हैं जो आपके कोड को अजीब और अद्भुत तरीकों से विफल कर सकते हैं। इस पोस्ट में, हम इन जालों की उत्पत्ति और आप इनसे कैसे बच सकते हैं, इस पर चर्चा करेंगे।
एक स्थिरांक क्या है?
यह पोस्ट मॉड्यूल के बारे में है, लेकिन उन्हें समझने के लिए हमें स्थिरांक को समझने की जरूरत है। अधिकांश भाषाओं में, स्थिरांक का उपयोग केवल थोड़े से डेटा को संग्रहीत करने के लिए किया जाता है, जैसे नीचे दिए गए उदाहरण में:
# These are simple constants
MAX_RETRIES = 5
DEFAULT_LANGUAGE = "en"
लेकिन रूबी में, कक्षाएं और मॉड्यूल भी स्थिरांक हैं। मैंने इसे प्रदर्शित करने के लिए एक छोटा सा उदाहरण लिखा है। नीचे मॉड्यूल में तीन स्थिरांक हैं:एक संख्या, एक वर्ग और एक नेस्टेड मॉड्यूल। जब आप किसी नेस्टेड क्लास या मॉड्यूल को एक्सेस करते हैं, तो माणिक इसे उन्हीं नियमों का उपयोग करके ढूंढता है, जिनका उपयोग वह एक साधारण संख्यात्मक स्थिरांक के साथ करेगा।
module MyModule
MY_FAVORITE_NUMBER = 7
# Classes are constants
class MyClass
end
# So are modules
module MyEmbeddedModule
end
end
puts MyModule.constants.inspect # => [:MY_FAVORITE_NUMBER, :MyClass, :MyEmbeddedModule]
अक्सर, मॉड्यूल के पास अपने माता-पिता में परिभाषित स्थिरांक तक पहुंच होती है। इसलिए आप इस तरह कोड लिख सकते हैं:
module X
MARCO = "polo"
module Y
def self.n
puts MARCO
end
end
end
X::Y.n() # => "polo"
लेकिन आप गलत होंगे यदि आपको लगता है कि यह माता-पिता/बच्चे का संबंध था जो Y को X के निरंतर MARCO तक पहुंचने की अनुमति देता है।
एक आम समस्या
यदि हम ऊपर दिए गए कोड को थोड़ा अलग तरीके से फिर से लिखते हैं, तो कुछ आश्चर्यजनक होता है। Y अब X::MARCO तक नहीं पहुंच सकता। यहाँ क्या हो रहा है?
module A
MARCO = "polo"
end
module A::B
def self.n
puts MARCO # => uninitialized constant A::B::MARCO (NameError)
end
end
A::B.n()
यह पता चला है कि बच्चे द्वारा माता-पिता के स्थिरांक की "विरासत" माता-पिता/बाल संबंधों के कारण नहीं है। यह शाब्दिक है। इसका मतलब है कि यह आपके कोड की संरचना पर आधारित है, न कि आपके कोड द्वारा बनाए जा रहे ऑब्जेक्ट की संरचना पर।
नेस्टिंग की जांच करना
यदि आप इस बात की गहरी समझ प्राप्त करना चाहते हैं कि रूबी नेस्टेड स्थिरांक की खोज कैसे करती है, तो यह Module.nesting
को देखने लायक है। समारोह।
यह फ़ंक्शन ऑब्जेक्ट्स की एक सरणी देता है जो किसी दिए गए दायरे में स्थिरांक के लिए "खोज पथ" बनाते हैं। आइए अपने पिछले उदाहरणों के लिए नेस्टिंग की जांच करें।
हमारे पहले उदाहरण में, हम देखते हैं कि नेस्टिंग [A::B, A]
. है . इसका मतलब यह है कि यदि हम निरंतर मार्को का उपयोग करते हैं, तो रूबी इसे पहले A::B
में ढूंढेगी। , और फिर A
. में ।
module A
MARCO = "polo"
module B
def self.n
puts Module.nesting.inspect # => [A::B, A]
puts MARCO # => "polo"
end
end
end
दूसरे उदाहरण में, हम देखते हैं कि नेस्टिंग में केवल A::B
. शामिल है , नहीं A
. भले ही B A
. का "बच्चा" है , जिस तरह से मैंने कोड लिखा है वह उन्हें नेस्टेड के रूप में नहीं दिखाता है, इसलिए इस उद्देश्य के लिए वे भी नहीं हो सकते हैं।
module A
MARCO = "polo"
end
module A::B
def self.n
puts Module.nesting.inspect # => [A::B]
puts MARCO # => uninitialized constant A::B::MARCO (NameError)
end
end
रेल ऑटोलोड जटिलताएं
क्या आपने कभी गौर किया है कि जब आप रेल का उपयोग करते हैं तो आपको फाइलों को शामिल करने की आवश्यकता नहीं होती है? यदि आप किसी मॉडल का उपयोग करना चाहते हैं, तो आप बस उसका उपयोग करें।
यह संभव है क्योंकि रेल एक ऑटोलोड सिस्टम लागू करता है। यह Module.const_missing
. का उपयोग करता है यह पता लगाने के लिए कि जब आप एक स्थिरांक को संदर्भित करने का प्रयास करते हैं जिसे लोड नहीं किया गया है। इसके बाद यह उन फ़ाइलों को लोड करता है जो मानते हैं कि इसमें स्थिरांक होना चाहिए। यह ज्यादातर समय काम करता है, लेकिन एक पकड़ है।
रेल मानता है कि एक मॉड्यूल में हमेशा सबसे बड़ा संभव घोंसला होता है। यह मानता है कि मॉड्यूल A::B::C में [A::B::C, A::B, A]
का नेस्टिंग होगा। . अगर ऐसा नहीं होता है तो आपको अप्रत्याशित व्यवहार मिलेगा।
नीचे दिए गए कोड में, मॉड्यूल बी A::MARCO
. तक पहुंचने में सक्षम नहीं होना चाहिए . सामान्य रूबी में, यह सक्षम नहीं होगा क्योंकि इसका घोंसला [ए ::बी] है। तो आपको अपवाद मिलना चाहिए। लेकिन रेल 'ऑटोलैड अपवाद नहीं फेंकता है। इसके बजाय, यह A::MARCO
. लौटाता है ।
# a.rb
module A
MARCO = "polo"
end
# a/b.rb
module A::B
def self.n
puts MARCO # => "polo"
end
end
# some_controller.rb
A::B.n()
निष्कर्ष?
यह सब बहुत सोचने वाली बात है। जहां संभव हो मैं सोचने से बचना पसंद करता हूं, इसलिए मैं मॉड्यूल से दूर रहने की कोशिश करता हूं A::B
वाक्य - विन्यास। मैं ऐसे मामले के बारे में नहीं सोच सकता जहां मैं जानबूझकर मॉड्यूल घोंसले में हेरफेर करना चाहता हूं। यदि आप किसी के बारे में जानते हैं, तो मुझे उनके बारे में सुनना अच्छा लगेगा!