यदि आपने पहले कभी रिफाइनमेंट का उपयोग नहीं किया है, तो आप शायद आश्चर्य में होंगे। आपने सुना होगा कि रिफाइनमेंट को मंकी पैचिंग को बदलने के लिए पेश किया गया था। इसलिए आप उम्मीद कर सकते हैं कि आप एक्टिवसपोर्ट के hours मेथड जैसा कुछ लागू कर पाएंगे:
module TimeExtension refine Fixnum do def hours self * 60 end end end class MyFramework using TimeExtension end class MyApp < MyFramework def index 1.hours end end MyApp.new.index # undefined method `hours' for 1:Fixnum (NoMethodError)
यदि आप उपरोक्त कोड चलाते हैं, तो आप पाएंगे कि यह काम नहीं करता। तो क्या हुआ?
कई अन्य महान विचारों की तरह, रिफाइनमेंट की मूल अवधारणा को ठंडी कठोर वास्तविकता के साथ काम करने के लिए 조정 करना पड़ा।
उपरोक्त कोड में आश्चर्यजनक व्यवहार इन समायोजनों में से एक के कारण होता है। विशेष रूप से, वह नियम जो कहता है कि रिफाइनमेंट लेक्सिकली स्कोप्ड हैं।
लेक्सिकल स्कोपिंग क्या है?
जब हम कहते हैं कि कुछ लेक्सिकल है, तो इसका मतलब है कि इसका टेक्स्ट से लेना-देना है - स्क्रीन पर कोड के विपरीत कि वह कोड क्या मायने रखता है।
यदि दो लाइनें लेक्सिकली स्कोप्ड हैं, तो इसका सीधा सा मतलब है कि वे एक ही कोड ब्लॉक के भीतर होती हैं - चाहे वह कोड ब्लॉक किसी भी चीज़ का मूल्यांकन करे।
इसके बारे में बात करने की तुलना में एक उदाहरण देखना बहुत आसान है:
class B # x and y share the same lexical scope x = 1 y = 1 end class B # z has a different lexical scope from x and y, even though it's in the same class. z = 3 end
रिफाइनमेंट लेक्सिकली स्कोप्ड हैं
जब हम using कीवर्ड के साथ एक रिफाइनमेंट लागू करते हैं, तो रिफाइनमेंट केवल लेक्सिकल स्कोप के भीतर दिखाई देता है।
यहाँ एक उदाहरण है जो मेरा मतलब दिखाता है:
module TimeExtension refine Fixnum do def hours self * 60 end end end class MyApp using TimeExtension def index 1.hours end end class MyApp def show 2.hours end end MyApp.new.show # undefined method `hour' for 1:Fixnum (NoMethodError)
भले ही index और show मेथड दोनों एक ही क्लास का हिस्सा हैं, केवल index मेथड को रिफाइनमेंट तक पहुंच प्राप्त है, क्योंकि केवल यह using स्टेटमेंट के साथ लेक्सिकल स्कोप साझा करता है।
यह शायद थोड़ा अजीब लगता है, क्योंकि रूबी में लगभग बाकी सब कुछ डायनामिकली स्कोप्ड है। जब आप एक क्लास में एक मेथड जोड़ते हैं, तो मेथड वहां रहता है जब आप क्लास परिभाषा से बाहर निकलते हैं। लेकिन रिफाइनमेंट ऐसे काम नहीं करते।
इसके कई परिणाम हैं जो पहली नजर में स्पष्ट नहीं हो सकते।
आप रिफाइनमेंट मेथड को डायनामिकली आह्वान नहीं कर सकते
क्योंकि send मेथड उसी कोड ब्लॉक के भीतर परिभाषित नहीं है जिसमें आपका using स्टेटमेंट है, यह रिफाइनमेंट नहीं देख सकता।
तो यह काम नहीं करता:
class MyApp using TimeExtension def index 1.send(:hours) end end
आप रिफाइनमेंट मेथड के अस्तित्व को क्वेरी नहीं कर सकते
respond_to? मेथड भी उसी कोड ब्लॉक के भीतर नहीं है। इसलिए यह उसी कारण से काम नहीं करता जिस कारण send मेथड नहीं करता।
class MyApp using TimeExtension def index 1.respond_to?(:hours) end end
निष्कर्ष
मुझे आशा है कि यह रिफाइनमेंट के आसपास के कुछ भ्रम को दूर करता है जो मैंने लोगों को होते देखा है। वे निश्चित रूप से रूबी की एक संभावित उपयोगी विशेषता हैं, लेकिन यदि आपने कभी उनका उपयोग नहीं किया है तो वे थोड़े मुश्किल हो सकते हैं।