सभी त्रुटियां घातक नहीं हैं। कुछ बस संकेत देते हैं कि आपको पुनः प्रयास करने की आवश्यकता है। सौभाग्य से, रूबी कुछ दिलचस्प तंत्र प्रदान करता है जो "फिर से प्रयास करना" आसान बनाता है - हालांकि उनमें से सभी स्पष्ट या प्रसिद्ध नहीं हैं। इस पोस्ट में हम इन तंत्रों और वे वास्तविक दुनिया में कैसे काम करते हैं, इस पर एक नज़र डालेंगे।
पेश है retry
ठीक है - यह एक तरह का स्पष्ट है, लेकिन केवल अगर आप जानते हैं कि यह मौजूद है। व्यक्तिगत रूप से, मैं अपने रूबी करियर में अच्छी तरह से था, इससे पहले कि मैं रमणीय "पुन:प्रयास करें" कीवर्ड के बारे में सीखता।
रूबी के अपवाद बचाव प्रणाली में पुन:प्रयास बनाया गया है। यह काफी सरल है। यदि आप अपने बचाव ब्लॉक में "पुन:प्रयास करें" का उपयोग करते हैं, तो यह कोड के उस भाग को फिर से चलाने के लिए कारण बनता है जिसे बचाया गया था। आइए एक उदाहरण देखें।
begin
retries ||= 0
puts "try ##{ retries }"
raise "the roof"
rescue
retry if (retries += 1) < 3
end
# ... outputs the following:
# try #0
# try #1
# try #2
यहाँ ध्यान देने योग्य कुछ बातें हैं:
-
जब पुन:प्रयास कहा जाता है, सभी प्रारंभ और बचाव के बीच में कोड फिर से चलाया जाता है। यह निश्चित रूप से करता है नहीं "जहां से छोड़ा था वहां से उठाएं" या ऐसा ही कुछ।
-
यदि आप पुनर्प्रयासों को सीमित करने के लिए कुछ तंत्र प्रदान नहीं करते हैं, तो आप एक अनंत लूप के साथ समाप्त हो जाएंगे।
-
प्रारंभ और बचाव दोनों ब्लॉकों में कोड पैरेंट दायरे में समान पुनर्प्रयास चर का उपयोग करने में सक्षम हैं।
समस्या के साथ retry
जबकि पुनः प्रयास बहुत अच्छा है, इसकी कुछ सीमाएँ हैं। मुख्य बात यह है कि पूरे स्टार्ट ब्लॉक को फिर से चलाया जाता है। लेकिन कभी-कभी यह आदर्श नहीं होता।
उदाहरण के लिए, कल्पना करें कि आप एक रत्न का उपयोग कर रहे हैं जो आपको ट्विटर, फेसबुक और कई अन्य साइटों पर एक ही विधि कॉल का उपयोग करके स्थिति अपडेट पोस्ट करने देता है। यह कुछ इस तरह दिख सकता है।
SocialMedia.post_to_all("Zomg! I just ate the biggest hamburger")
# ...posts to Twitter API
# ...posts to Facebook API
# ...etc
यदि एपीआई में से कोई एक प्रतिक्रिया देने में विफल रहता है, तो मणि सोशलमीडिया ::टाइमआउट एरर उठाता है और बंद हो जाता है। यदि हम इस अपवाद को पकड़कर पुनः प्रयास करते हैं, तो हम डुप्लिकेट पोस्ट के साथ समाप्त हो जाएंगे क्योंकि पुनः प्रयास शुरू से ही शुरू हो जाएगा।
begin
SocialMedia.post_to_all("Zomg! I just ate the biggest hamburger")
rescue SocialMedia::TimeoutError
retry
end
# ...posts to Twitter API
# facebook error
# ...posts to Twitter API
# facebook error
# ...posts to Twitter API
# and so on
क्या यह अच्छा नहीं होगा यदि हम रत्न को "बस फेसबुक छोड़ें, और पोस्ट करने के लिए एपीआई की सूची में नीचे जाते रहें।"
सौभाग्य से हमारे लिए, रूबी हमें ठीक वैसा ही करने देती है।
नोट:बेशक इस समस्या का असली समाधान सोशल मीडिया लाइब्रेरी को फिर से तैयार करना है। लेकिन यह उन तकनीकों के लिए एकमात्र उपयोग-मामले से बहुत दूर है जो मैं आपको दिखाने जा रहा हूं।
बचाव के लिए निरंतरता
निरंतरता लोगों को डराती है। लेकिन यह सिर्फ इसलिए है क्योंकि उनका बहुत बार उपयोग नहीं किया जाता है और वे थोड़े अजीब लगते हैं। लेकिन एक बार जब आप मूल बातें समझ लेते हैं तो वे वास्तव में काफी सरल हो जाती हैं।
एक निरंतरता आपके कोड में एक "सेव पॉइंट" की तरह होती है, ठीक वैसे ही जैसे किसी वीडियो गेम में होती है। आप जा सकते हैं और अन्य काम कर सकते हैं, फिर सेव पॉइंट पर वापस जा सकते हैं और सब कुछ वैसा ही होगा जैसा आपने छोड़ा था।
... ठीक है, तो यह एक पूर्ण सादृश्य नहीं है, लेकिन यह काम करता है। आइए कुछ कोड देखें:
require "continuation"
counter = 0
continuation = callcc { |c| c } # define our savepoint
puts(counter += 1)
continuation.call(continuation) if counter < 5 # jump back to our savepoint
आपने कुछ अजीबोगरीब बातों पर गौर किया होगा। आइए उनके माध्यम से चलते हैं:
-
कंटिन्यूएशन ऑब्जेक्ट बनाने के लिए हम कॉलसीसी विधि का उपयोग करते हैं। इसके लिए कोई साफ OO सिंटैक्स नहीं है।
-
पहली बार
continuation
वैरिएबल असाइन किया गया है, यहcallcc
. के रिटर्न वैल्यू पर सेट है का ब्लॉक। इसलिए ब्लॉक होना चाहिए। -
हर बार जब हम सेवपॉइंट पर वापस जाते हैं,
continuation
वेरिएबल असाइन किया गया है जो भी तर्क हम पास करते हैंcall
तरीका। इसलिए हम अजीब दिखने वालेcontinuation.call(continuation)
. का इस्तेमाल करते हैं वाक्य रचना।
अपवादों में निरंतरता जोड़ना
हम एक skip
. जोड़ने के लिए निरंतरता का उपयोग करने जा रहे हैं सभी अपवादों के लिए विधि। नीचे दिया गया उदाहरण दिखाता है कि इसे कैसे काम करना चाहिए। जब भी मैं कोई अपवाद बचाता हूं तो मुझे skip
. पर कॉल करने में सक्षम होना चाहिए , जो अपवाद को उठाने वाले कोड को ऐसे कार्य करने के लिए प्रेरित करेगा जैसे ऐसा कभी नहीं हुआ।
begin
raise "the roof"
puts "The exception was ignored"
rescue => e
e.skip
end
# ...outputs "The exception was ignored"
ऐसा करने के लिए मुझे कुछ पाप करने होंगे। Exception
सिर्फ एक वर्ग है। इसका मतलब है कि मैं skip
. जोड़ने के लिए इसे moonekypatch कर सकता हूं विधि।
class Exception
attr_accessor :continuation
def skip
continuation.call
end
end
अब हमें continuation
. सेट करने की आवश्यकता है प्रत्येक अपवाद के लिए विशेषता। यह पता चला है कि raise
सिर्फ एक तरीका है, जिसे हम ओवरराइड कर सकते हैं।
BTW, नीचे दिए गए कोड को अदवी के उत्कृष्ट स्लाइड डेक से लगभग शब्दशः लिया गया है जो आप अपवादों के बारे में नहीं जानते थे। मैं इसे लागू करने का इससे बेहतर तरीका नहीं सोच सकता था:
require 'continuation'
module StoreContinuationOnRaise
def raise(*args)
callcc do |continuation|
begin
super
rescue Exception => e
e.continuation = continuation
super(e)
end
end
end
end
class Object
include StoreContinuationOnRaise
end
अब मैं कॉल कर सकता हूं skip
किसी भी अपवाद के लिए विधि और यह ऐसा होगा जैसे अपवाद कभी नहीं हुआ।