एक DRY फैशन में रूबी के बचाव खंड के लिए कई त्रुटि कक्षाएं पास करना


101

मेरे पास कुछ कोड हैं जो रूबी में कई प्रकार के अपवादों से बचाव करते हैं:

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue FooException, BarException
  puts "rescued!"
end

मैं जो करना चाहता हूं वह किसी तरह अपवाद सूची की सूची को स्टोर करना है जिसे मैं कहीं और बचाव करना चाहता हूं और उन प्रकारों को बचाव खंड में पास करना चाहता हूं:

EXCEPTIONS = [FooException, BarException]

और फिर:

rescue EXCEPTIONS

क्या यह भी संभव है, और क्या यह वास्तव में हैक-वाई कॉल के बिना संभव है eval? मुझे उम्मीद नहीं है कि TypeError: class or module required for rescue clauseजब मैं ऊपर का प्रयास कर रहा हूं तो मैं देख रहा हूं ।


2
बचाव के बारे में क्या * अपवाद?
रोमन

जवाबों:


199

आप splat ऑपरेटर के साथ एक सरणी का उपयोग कर सकते हैं *

EXCEPTIONS = [FooException, BarException]

begin
  a = rand
  if a > 0.5
    raise FooException
  else
    raise BarException
  end
rescue *EXCEPTIONS
  puts "rescued!"
end

यदि आप ऊपर दिए गए (के साथ EXCEPTIONS) के लिए एक स्थिरांक का उपयोग करने जा रहे हैं , तो ध्यान दें कि आप इसे परिभाषा के भीतर परिभाषित नहीं कर सकते हैं, और यह भी कि यदि आप इसे किसी अन्य वर्ग में परिभाषित करते हैं, तो आपको इसके नाम स्थान के साथ इसे संदर्भित करना होगा। असल में, यह एक स्थिर होना नहीं है।


फलैट संचालक

स्पैट ऑपरेटर *अपनी स्थिति में एक सरणी "अनपैक" करता है ताकि

rescue *EXCEPTIONS

के रूप में ही मतलब है

rescue FooException, BarException

आप इसे एक सरणी शाब्दिक के रूप में भी उपयोग कर सकते हैं

[BazException, *EXCEPTIONS, BangExcepion]

जो जैसा है वैसा है

[BazException, FooException, BarException, BangExcepion]

या तर्क की स्थिति में

method(BazException, *EXCEPTIONS, BangExcepion)

जिसका मतलब है

method(BazException, FooException, BarException, BangExcepion)

[] ख़ालीपन का विस्तार:

[a, *[], b] # => [a, b]

रूबी 1.8 और रूबी 1.9 के बीच एक अंतर है nil

[a, *nil, b] # => [a, b]       (ruby 1.9)
[a, *nil, b] # => [a, nil, b]  (ruby 1.8)

उन वस्तुओं से सावधान रहें जिन to_aपर परिभाषित किया गया है, जैसा to_aकि ऐसे मामलों में लागू किया जाएगा:

[a, *{k: :v}, b] # => [a, [:k, :v], b]

अन्य प्रकार की वस्तुओं के साथ, यह स्वयं लौटता है।

[1, *2, 3] # => [1, 2, 3]

2
यह रूबी 1.8.7 में भी काम करता प्रतीत होता है। EXCEPTIONSइस मामले में '*' वर्ण का उपयोग करने के लिए क्या शब्द है ? थोड़ा और सीखना चाहेंगे।
एपीबी

2
@ और इसे स्पैट कहा जाता है। यह आमतौर पर एक सरणी को अल्पविराम से अलग की गई वस्तुओं में विघटित करने का प्रभाव रखता है। जब एक विधि परिभाषा की स्थिति प्राप्त करने वाले तर्क में उपयोग किया जाता है, तो यह दूसरा तरीका करता है: तर्कों को एक सरणी में रखें। यह विभिन्न अवसरों में काफी उपयोगी है। यह जानकर अच्छा लगा कि यह 1.8.7 के साथ काम करता है। मैंने उसी के अनुसार अपना उत्तर संपादित किया।
आरा

20
ध्यान दें कि यदि आप अपवाद उदाहरण का उपयोग करना चाहते हैं, तो इस सिंटैक्स का उपयोग करें: rescue InvalidRequestError, CardError => e( mikeferrier.com/2012/05/19/… देखें )
पीटर

1
यह सिंटैक्स ठीक काम करता है: rescue *EXCEPTIONS => eजहां EXCEPTIONSअपवाद वर्ग नामों की एक सरणी है।
अक्स

3

जबकि @sawa द्वारा दिया गया उत्तर तकनीकी रूप से सही है, मुझे लगता है कि यह रूबी के अपवाद संचालन तंत्र का दुरुपयोग करता है।

जैसा कि पीटर एर्लिच की टिप्पणी से पता चलता है ( माइक फेरियर द्वारा एक पुराने ब्लॉग पोस्ट की ओर इशारा करते हुए ), रूबी पहले से ही DRY अपवाद हैंडलर तंत्र से सुसज्जित है:

puts 'starting up'
begin
  case rand(3)
  when 0
    ([] + '')
  when 1
    (foo)
  when 2
    (3 / 0)
  end
rescue TypeError, NameError => e
  puts "oops: #{e.message}"
rescue Exception => e
  puts "ouch, #{e}"
end
puts 'done'

इस तकनीक का उपयोग करके, हम अपवाद ऑब्जेक्ट तक पहुंच सकते हैं, जिसमें आमतौर पर इसमें कुछ मूल्यवान जानकारी होती है।


1

मैं बस इस मुद्दे में भाग गया और एक वैकल्पिक समाधान पाया। मामले में आपके FooExceptionऔर BarExceptionसभी कस्टम अपवाद वर्ग होने जा रहे हैं और विशेष रूप से यदि वे सभी विषयगत रूप से संबंधित हैं, तो आप अपने वंशानुक्रम पदानुक्रम की संरचना कर सकते हैं जैसे कि वे सभी एक ही मूल वर्ग से विरासत में मिलेंगे और फिर केवल मूल वर्ग को बचाएंगे।

उदाहरण के लिए मैं तीन अपवाद था: FileNamesMissingError, InputFileMissingError, और OutputDirectoryErrorहै कि मैं एक बयान के साथ बचाव करना चाहता था। मैंने एक और अपवाद वर्ग बुलाया FileLoadErrorऔर फिर उसमें से तीन अपवादों की स्थापना की। मैंने तब ही बचाया था FileLoadError

ऐशे ही:

class FileLoadError < StandardError
end

class FileNamesMissingError < FileLoadError
end

class InputFileMissingError < FileLoadError
end

class OutputDirectoryError < FileLoadError
end

[FileNamesMissingError,
 InputFileMissingError,
 OutputDirectoryError].each do |error| 
   begin  
     raise error
   rescue FileLoadError => e
     puts "Rescuing #{e.class}."
   end 
end
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.