बंदर पैचिंग। जब आप पहली बार रूबी को आजमाते हैं, तो यह आश्चर्यजनक होता है। आप मूल कक्षाओं में विधियाँ जोड़ सकते हैं! आपको Time.now.advance(days: -1)
. पर कॉल करने की आवश्यकता नहीं है , आप 1.day.ago
write लिख सकते हैं ! यह रूबी को पढ़ने और लिखने में खुशी देता है। तक...
आपने अजीब बग मारा क्योंकि एक पैच बदल गया 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
इस तरह, आप संबंधित मंकी पैच को एक साथ व्यवस्थित कर सकते हैं। जब कोई त्रुटि होती है, तो यह स्पष्ट होता है कि समस्या कोड कहां से आया है। और आप उन्हें एक समय में एक समूह में शामिल कर सकते हैं:
# Actually monkey-patch DateTime
DateTime.include CoreExtensions::DateTime::BusinessDays
यदि आप अब और पैच नहीं चाहते हैं, तो बस उस पंक्ति पर टिप्पणी करें।
उन्हें एक साथ रखें
जब आप कोर क्लास को बंदर करते हैं, तो आप कोर रूबी एपीआई में जोड़ते हैं। कोर पैच वाला हर ऐप थोड़ा अलग लगता है। इसलिए जब आप एक नए कोडबेस में कूदते हैं तो आपके पास उन परिवर्तनों को तुरंत सीखने का एक तरीका होना चाहिए। आपको यह जानना होगा कि आपके बंदर कहाँ रहते हैं।
मैं ज्यादातर रेल के बंदर-पैचिंग सम्मेलन का पालन करता हूं। पैच 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
... ओह.
जब आप मंकी क्लास को पैच करते हैं, तो आप आमतौर पर एक ऐसी चीज़ के बारे में सोचते हैं जिसे आप आसान बनाना चाहते हैं। आप संख्याओं के योग की गणना करना चाहते हैं, लेकिन यह भूल जाएं कि Arrays में अन्य चीज़ें हो सकती हैं।
अभी, यह समझ में आता है। आप करेंगे हैश के समूह के औसत की गणना करने का प्रयास कभी न करें। लेकिन जब आप किसी ऐसी वस्तु से विधियाँ जोड़ते हैं जो कभी-कभी कॉल करने पर बिल्कुल विफल हो जाती है, तो आप बाद में खुद को भ्रमित कर लेंगे।
आप इससे कुछ तरीकों से निपट सकते हैं। सबसे अच्छे से बुरे की ओर:
-
अप्रत्याशित इनपुट को उचित रूप से संभालें।
यह अच्छी तरह से काम करता है अगर आपका पैच स्ट्रिंग्स के साथ काम करता है। यदि आप
to_s
. को कॉल करते हैं, तो आप लगभग किसी भी चीज़ से कुछ उचित प्राप्त कर सकते हैं उस पर पहले। और कॉन्फिडेंट रूबी आपको विभिन्न प्रकार के इनपुट से निपटने के कई तरीके सिखाएगी। -
त्रुटि को अधिक स्पष्ट तरीके से संभालें।
यह एक
ArgumentError
फेंकने जितना आसान हो सकता है एक अच्छे संदेश के साथ जब आप वह इनपुट देखते हैं जिसकी आप अपेक्षा नहीं कर रहे होते हैं। यादृच्छिकNoMethodError
को समझने वाले किसी और पर निर्भर न रहें एस. -
टिप्पणी में आप जिस प्रकार के इनपुट की अपेक्षा करते हैं उसका दस्तावेजीकरण करें।
अन्य दो विकल्प बेहतर हैं, यदि आप उनका उपयोग कर सकते हैं। लेकिन अगर आप अपने पैच के अंदर किनारे के मामलों की जांच नहीं कर सकते हैं, तो कम से कम उन्हें दस्तावेज करें। इस तरह, एक बार जब आपके कॉलर को पता चल जाएगा कि यह आपका पैच है जो उनकी समस्या पैदा कर रहा है, तो उन्हें पता चल जाएगा कि आप क्या करने की कोशिश कर रहे थे।
मेरा अब तक का सबसे पसंदीदा मंकी पैच
अंत में, मैं आपको अपने सर्वकालिक पसंदीदा मंकी पैच के साथ छोड़ना चाहता हूं: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 कक्षाओं को संलग्न करता है तो बहुत अच्छा।
समझदार बंदर पैचिंग
बंदर-पैचिंग कोर क्लास सभी खराब नहीं हैं। जब आप इसे अच्छी तरह से करते हैं, तो यह आपके कोड को रूबी की तरह महसूस कराता है। लेकिन रूबी के किसी भी तेज किनारों की तरह, आपको उनका उपयोग करते समय अतिरिक्त सावधानी बरतनी होगी।
यदि आप अपने पैच एक साथ रखते हैं, उन्हें मॉड्यूल में समूहित करते हैं, और अप्रत्याशित को संभालते हैं, तो आपके बंदर पैच उतने ही सुरक्षित रहेंगे जितने वे हो सकते हैं।
सबसे अच्छा बंदर पैच क्या है आपके पास कभी लिखा (या देखा)? एक टिप्पणी छोड़ें और मुझे इसके बारे में बताएं!