मंकी पैचिंग। जब आप पहली बार रूबी आज़माते हैं, तो यह अद्भुत है। आप कोर क्लासेस में मेथड्स जोड़ सकते हैं! आपको Time.now.advance(days: -1) कॉल करने की ज़रूरत नहीं है, आप 1.day.ago लिख सकते हैं! यह रूबी को पढ़ने और लिखने का आनंद बनाता है। जब तक…
आप अजीब बग्स से टकराते हैं क्योंकि एक पैच ने Hash बदल दिया।
आप इस बारे में भ्रमित हो जाते हैं कि वास्तव में कौन सा कोड चला, इसलिए जब यह टूटता है तो आप इसे डीबग नहीं कर सकते।
और आप अंततः पता लगाते हैं कि आपकी सभी समस्याएं छह महीने पहले हुई थीं, जब आपने एक लाइन को पांच वर्ण छोटा करने के लिए Enumerable को मंकी-पैच किया था।
लेकिन विकल्प क्या है? कोई सुविधा बिल्कुल नहीं? कोड जो GroupableArray.new([1, 2, 3, 4]).in_groups_of(2) जैसा दिखता है? blank? के कोर रूबी में आने का इंतजार करें इससे पहले कि आपको अच्छा यूजर इनपुट हैंडलिंग की अनुमति दी जाए?
आप मंकी पैच को पूरी तरह से छोड़ना नहीं चाहते। लेकिन आप मंकी पैच कैसे लिख सकते हैं जो नहीं आपको अगली बार उन्हें देखने पर अक्षमता के लिए खुद को निकाल देना चाहेंगे?
उन्हें एक मॉड्यूल में रखें
जब आप किसी क्लास को मंकी-पैच करते हैं, तो क्लास को फिर से न खोलें और अपना पैच इसमें न डालें:
class DateTime
def weekday?
!sunday? && !saturday?
end
end
क्यों नहीं?
-
यदि दो लाइब्रेरीज एक ही मेथड को मंकी-पैच करती हैं, तो आप यह नहीं बता पाएंगे।
पहला मंकी-पैच ओवरराइट हो जाएगा और हमेशा के लिए गायब हो जाएगा।
-
यदि कोई त्रुटि होती है, तो ऐसा लगेगा जैसे त्रुटि
DateTimeके अंदर हुई।तकनीकी रूप से सच है, लेकिन यह इतना मददगार नहीं है।
-
अपने मंकी पैच को बंद करना कठिन है।
आपको या तो अपने पूरे पैच को कमेंट आउट करना होगा, या अपनी मंकी पैच फाइल को रिक्वायर करना छोड़ना होगा यदि आप इसके बिना कोड चलाना चाहते हैं।
-
यदि आप, कहते हैं, इस मंकी पैच को चलाने से पहले
require 'date'करना भूल गए, तो आप गलती सेDateTimeको पुनर्परिभाषित कर देंगे बजाय इसे पैच करने के।
इसके बजाय, अपने मंकी पैच को एक मॉड्यूल में रखें:
module CoreExtensions
module DateTime
module BusinessDays
def weekday?
!sunday? && !saturday?
end
end
end
end
इस तरह, आप संबंधित मंकी पैच को एक साथ व्यवस्थित कर सकते हैं। जब कोई त्रुटि होती है, तो यह बिल्कुल स्पष्ट होता है कि समस्या कोड कहां से आया। और आप उन्हें एक बार में एक समूह शामिल कर सकते हैं:
# वास्तव में DateTime को मंकी-पैच करें
DateTime.include CoreExtensions::DateTime::BusinessDays
यदि आप अब पैच नहीं चाहते हैं, तो बस उस लाइन को कमेंट आउट करें।
उन्हें एक साथ रखें
जब आप कोर क्लासेस को मंकी-पैच करते हैं, तो आप कोर रूबी APIs में जोड़ते हैं। कोर पैच वाला हर ऐप थोड़ा अलग महसूस होता है। इसलिए जब आप एक नए कोडबेस में कूदते हैं तो उन परिवर्तनों को जल्दी से सीखने का एक तरीका होना चाहिए। आपको पता होना चाहिए कि आपके मंकी पैच कहां रहते हैं।
मैं ज्यादातर रेल्स के मंकी-पैचिंग कन्वेंशन का पालन करता हूं। पैच lib/core_extensions/class_name/group.rb में जाते हैं। तो यह पैच:
module CoreExtensions
module DateTime
module BusinessDays
def weekday?
!sunday? && !saturday?
end
end
end
end
lib/core_extensions/date_time/business_days.rb में जाएगा।
कोई भी नया डेवलपर lib/core_extensions में रूबी फाइलों को ब्राउज़ कर सकता है और सीख सकता है कि आपने रूबी में क्या जोड़ा। और वे वास्तव में उन सुविधाजनक नए मेथड्स का उपयोग करेंगे जो आपने लिखे हैं, बजाय उन मेथड्स के केवल रास्ते में आने के।
एज केसेज के बारे में सोचें
मुझे नहीं पता कि Enumerable में sum मेथड क्यों नहीं है। अक्सर, मैं चाहता हूं कि मैं [1, 2, 3].sum, या ["a", "b", "c"].sum, या [Article.new, Article.new, Article.new].sum लिख सकूं… ओह।
जब आप किसी क्लास को मंकी-पैच करते हैं, तो आप आमतौर पर एक चीज के बारे में सोच रहे होते हैं जिसे आप आसान बनाना चाहते हैं। आप संख्याओं का योग 계산 करना चाहते हैं, लेकिन भूल जाते हैं कि एरे अन्य चीजें भी रख सकते हैं।
अभी, यह समझ में आता है। आप कभी भी हैश के समूह का औसत निकालने की कोशिश नहीं करेंगे। लेकिन जब आप किसी ऑब्जेक्ट से मेथड्स जोड़ते हैं जो उन्हें कॉल करने पर कभी-कभी सादे तौर पर विफल हो जाते हैं, तो आप बाद में खुद को भ्रमित करेंगे।
आप इससे कुछ तरीकों से निपट सकते हैं। सर्वश्रेष्ठ से सबसे खराब:
-
अप्रत्याशित इनपुट को उचित तरीके से संभालें।
यह अच्छा काम करता है यदि आपका पैच स्ट्रिंग्स के साथ काम करता है। आप लगभग किसी भी चीज़ से कुछ उचित प्राप्त कर सकते हैं यदि आप पहले उस पर
to_sकॉल करते हैं। और Confident Ruby आपको विभिन्न प्रकार के इनपुट से निपटने के ढेर सारे तरीके सिखाएगा। -
त्रुटि को स्पष्ट तरीके से संभालें।
यह उतना ही आसान हो सकता है जितना कि जब आप अप्रत्याशित इनपुट देखते हैं तो एक अच्छे संदेश के साथ
ArgumentErrorफेंकना। किसी और के यादृच्छिकNoMethodErrors को समझने पर निर्भर न रहें। -
एक टिप्पणी में आपके द्वारा अपेक्षित इनपुट के प्रकार को दस्तावेज़ करें।
यदि आप उनका उपयोग कर सकते हैं तो अन्य दो विकल्प बेहतर हैं। लेकिन यदि आप अपने पैच के अंदर एज केस की जांच नहीं कर सकते, तो कम से कम उन्हें दस्तावेज़ करें। इस तरह, एक बार जब आपका कॉलर यह पता लगा लेता है कि यह आपका पैच है जो उनकी समस्या पैदा कर रहा है, तो उन्हें इस बात का अंदाजा होगा कि आप क्या करने की कोशिश कर रहे थे।
मेरा अब तक का पसंदीदा मंकी पैच
अंत में, मैं आपको अपने अब तक के पसंदीदा मंकी पैच के साथ छोड़ना चाहता हूं: Hash#string_merge:
module CoreExtensions
module Hash
module Merging
def string_merge(other_hash, separator = " ")
merge(other_hash) {|key, old, new| old.to_s + separator + new.to_s}
end
end
end
end
{}.string_merge({:class => "btn"}) # => {:class=>"btn"}
h = {:class => "btn"} # => {:class=>"btn"}
h.string_merge({:class => "btn-primary"}) # => {:class=>"btn btn-primary"}
यह HTML एलिमेंट्स में CSS क्लासेस जोड़ने को इतना बेहतर बनाता है।
समझदार मंकी पैचिंग
कोर क्लासेस को मंकी-पैच करना सब बुरा नहीं है। जब आप इसे अच्छी तरह से करते हैं, तो यह आपके कोड को अधिक रूबी जैसा महसूस कराता है। लेकिन रूबी के किसी भी तेज किनारे की तरह, आपको उनका उपयोग करते समय अतिरिक्त सावधानी बरतनी होगी।
यदि आप अपने पैच को एक साथ रखते हैं, उन्हें मॉड्यूल में ग्रुप करते हैं, और अप्रत्याशित को संभालते हैं, तो आपके मंकी पैच उतने ही सुरक्षित होंगे जितने वे हो सकते हैं।
आपने अब तक का सबसे अच्छा मंकी पैच आपने कभी लिखा (या देखा)? एक कमेंट छोड़ें और मुझे इसके बारे में बताएं!