80

मुझे कस्टम अपवाद कक्षाओं के बारे में अधिक जानकारी नहीं मिल रही है।रूबी कस्टम त्रुटि वर्ग: संदेश विशेषता का विरासत

मुझे क्या मालूम

आप अपने कस्टम त्रुटि वर्ग घोषित करने और इसे StandardError से विरासत दे सकते हैं, तो यह हो सकता है rescue घ:

class MyCustomError < StandardError 
end 

यह आप का उपयोग कर यह बढ़ाने के लिए अनुमति देता है:

raise MyCustomError, "A message" 

और बाद में, उस संदेश जब

01 बचाव मिलता है
rescue MyCustomError => e 
    puts e.message # => "A message" 

मैं जानता हूँ कि क्या नहीं

मैं अपने अपवाद कुछ कस्टम फ़ील्ड देना चाहता हूँ, लेकिन मैं माता पिता के वर्ग से message विशेषता इनहेरिट करना चाहते हैं। मुझे on this topic पढ़ने में पता चला कि @message अपवाद वर्ग का एक उदाहरण चर नहीं है, इसलिए मुझे चिंता है कि मेरी विरासत काम नहीं करेगी।

क्या कोई मुझे इस बारे में अधिक जानकारी दे सकता है? मैं एक कस्टम त्रुटि वर्ग को object विशेषता के साथ कैसे कार्यान्वित करूं? सही पीछा कर रहा है:

class MyCustomError < StandardError 
    attr_reader :object 
    def initialize(message, object) 
    super(message) 
    @object = object 
    end 
end 

और फिर:

raise MyCustomError.new(anObject), "A message" 

पाने के लिए:

rescue MyCustomError => e 
    puts e.message # => "A message" 
    puts e.object # => anObject 

यह काम करेंगे, और अगर यह होता है, यह काम करने का सही तरीका है?

+3

'अपवाद => ई' बचाव न करें। यह डिफ़ॉल्ट 'बचाव => ई' से व्यापक है जो 'मानक त्रुटि' से फैला हुआ है, और Ctrl + C सहित सबकुछ पकड़ता है। मैं 'MyCustomError => e' बचाव' करूंगा। –

+1

@RyanTaylor मैंने अपने प्रश्न को और अधिक उचित दृष्टिकोण के लिए संपादित किया। – MarioDS

उत्तर

106

raise पहले से ही संदेश सेट ताकि आप निर्माता के लिए इसे पारित करने की जरूरत नहीं है:

class MyCustomError < StandardError 
    attr_reader :object 

    def initialize(object) 
    @object = object 
    end 
end 

begin 
    raise MyCustomError.new("an object"), "a message" 
rescue MyCustomError => e 
    puts e.message # => "a message" 
    puts e.object # => "an object" 
end 

मैं rescue MyCustomError साथ rescue Exception बदल दिया है, Why is it a bad style to `rescue Exception => e` in Ruby? देखते हैं।

+0

मैं आपका जवाब स्वीकार करूंगा क्योंकि आपने मुझे संपूर्ण वाक्यविन्यास दिखाया है। धन्यवाद! – MarioDS

+1

यहां हम 'बचाव अपवाद' कर रहे हैं, लेकिन क्यों नहीं 'MyCustomError' को बचाएं? – Dfr

+0

@Dfr मैंने कोड – Stefan

6

आपका विचार सही है, लेकिन जिस तरह से आप इसे कॉल करते हैं वह गलत है। यह होना चाहिए

raise MyCustomError.new(an_object, "A message") 
+0

ठीक है, मैंने सोचा था कि आपके द्वारा दिया गया संदेश 'raise' कीवर्ड या कुछ के लिए दूसरा पैरामीटर था। – MarioDS

+0

आपने दो तर्क लेने के लिए 'प्रारंभिक' को फिर से परिभाषित किया है। 'नया' तर्क 'प्रारंभिक' करने के लिए तर्क पास करता है। – sawa

+0

या, आप कोष्ठक छोड़ सकते हैं। – sawa

2

मैं कुछ ऐसा करना चाहता था। मैं किसी ऑब्जेक्ट को # नया पर पास करना चाहता था और पास ऑब्जेक्ट की कुछ प्रोसेसिंग के आधार पर संदेश सेट करना चाहता था। निम्नलिखित काम करता है।

class FooError < StandardError 
    attr_accessor :message # this is critical! 
    def initialize(stuff) 
    @message = stuff.reverse 
    end 
end 

begin 
    raise FooError.new("!dlroW olleH") 
rescue FooError => e 
    puts e.message #=> Hello World! 
end 

ध्यान दें कि यह काम नहीं करेगा अगर आप attr_accessor :message तो नहीं घोषित करते हैं। ओपी के मुद्दे को संबोधित करते हुए, आप संदेश को एक अतिरिक्त तर्क के रूप में पास कर सकते हैं और अपनी पसंद की किसी भी चीज़ को स्टोर कर सकते हैं। महत्वपूर्ण हिस्सा # संदेश को ओवरराइड करना प्रतीत होता है।

6

को देखते हुए क्या Exception के गहरे लाल रंग का मूल प्रलेखन, जिसमें से सभी अन्य त्रुटियों के वारिस, के बारे में #message

exception.to_s लागू का परिणाम देता है कहा गया है। आम तौर पर यह अपवाद का संदेश या नाम देता है। एक to_str विधि की आपूर्ति करके, अपवादों का उपयोग करने के लिए सहमत हैं जहां स्ट्रिंग्स की अपेक्षा की जाती है।

http://ruby-doc.org/core-1.9.3/Exception.html#method-i-message

मैं to_s/to_str या प्रारंभकर्ता को पुनर्परिभाषित करने के लिए चुनते हैं। यहां एक उदाहरण दिया गया है जहां हम जानना चाहते हैं, ज्यादातर मानवीय पठनीय तरीके से, जब कोई बाहरी सेवा कुछ करने में विफल रही है।

नोट: नीचे दी गई दूसरी रणनीति रेलों की सुंदर स्ट्रिंग विधियों का उपयोग करती है, जैसे कि demodualize, जो थोड़ा जटिल हो सकता है और इसलिए अपवाद में संभावित रूप से मूर्खतापूर्ण हो सकता है। आप विधि हस्ताक्षर में और तर्क भी जोड़ सकते हैं, आपको चाहिए।

अधिभावी #to_s रणनीति#to_str नहीं, इसे दूसरे तरीके से काम करता है

module ExternalService 

    class FailedCRUDError < ::StandardError 
    def to_s 
     'failed to crud with external service' 
    end 
    end 

    class FailedToCreateError < FailedCRUDError; end 
    class FailedToReadError < FailedCRUDError; end 
    class FailedToUpdateError < FailedCRUDError; end 
    class FailedToDeleteError < FailedCRUDError; end 
end 

कंसोल आउटपुट

begin; raise ExternalService::FailedToCreateError; rescue => e; e.message; end 
# => "failed to crud with external service" 

begin; raise ExternalService::FailedToCreateError, 'custom message'; rescue => e; e.message; end 
# => "failed to crud with external service" 

begin; raise ExternalService::FailedToCreateError.new('custom message'); rescue => e; e.message; end 
# => "failed to crud with external service" 

raise ExternalService::FailedToCreateError 
# ExternalService::FailedToCreateError: failed to crud with external service 

अधिभावी #initialize रणनीति

यह रेलवे में उपयोग किए गए कार्यान्वयन के निकटतम रणनीति है। जैसा ऊपर बताया गया है, यह demodualize, underscore, और humanizeActiveSupport विधियों का उपयोग करता है। लेकिन पिछली रणनीति में, इसे आसानी से हटाया जा सकता है।

module ExternalService 
    class FailedCRUDError < ::StandardError 
    def initialize(service_model=nil) 
     super("#{self.class.name.demodulize.underscore.humanize} using #{service_model.class}") 
    end 
    end 

    class FailedToCreateError < FailedCRUDError; end 
    class FailedToReadError < FailedCRUDError; end 
    class FailedToUpdateError < FailedCRUDError; end 
    class FailedToDeleteError < FailedCRUDError; end 
end 

कंसोल आउटपुट

begin; raise ExternalService::FailedToCreateError; rescue => e; e.message; end 
# => "Failed to create error using NilClass" 

begin; raise ExternalService::FailedToCreateError, Object.new; rescue => e; e.message; end 
# => "Failed to create error using Object" 

begin; raise ExternalService::FailedToCreateError.new(Object.new); rescue => e; e.message; end 
# => "Failed to create error using Object" 

raise ExternalService::FailedCRUDError 
# ExternalService::FailedCRUDError: Failed crud error using NilClass 

raise ExternalService::FailedCRUDError.new(Object.new) 
# RuntimeError: ExternalService::FailedCRUDError using Object 

डेमो उपकरण

यह बचाव और इसके बाद के संस्करण कार्यान्वयन की मैसेजिंग को दिखाने के लिए एक डेमो है। अपवाद को बढ़ाने वाला वर्ग क्लाउडिनरी के लिए एक नकली एपीआई है। उपरोक्त रणनीतियों में से एक को अपने रेल कंसोल में बस डंप करें, इसके बाद।

require 'rails' # only needed for second strategy 

module ExternalService 
    class FailedCRUDError < ::StandardError 
    def initialize(service_model=nil) 
     @service_model = service_model 
     super("#{self.class.name.demodulize.underscore.humanize} using #{@service_model.class}") 
    end 
    end 

    class FailedToCreateError < FailedCRUDError; end 
    class FailedToReadError < FailedCRUDError; end 
    class FailedToUpdateError < FailedCRUDError; end 
    class FailedToDeleteError < FailedCRUDError; end 
end 

# Stub service representing 3rd party cloud storage 
class Cloudinary 

    def initialize(*error_args) 
    @error_args = error_args.flatten 
    end 

    def create_read_update_or_delete 
    begin 
     try_and_fail 
    rescue ExternalService::FailedCRUDError => e 
     e.message 
    end 
    end 

    private def try_and_fail 
    raise *@error_args 
    end 
end 

errors_map = [ 
    # Without an arg 
    ExternalService::FailedCRUDError, 
    ExternalService::FailedToCreateError, 
    ExternalService::FailedToReadError, 
    ExternalService::FailedToUpdateError, 
    ExternalService::FailedToDeleteError, 
    # Instantiated without an arg 
    ExternalService::FailedCRUDError.new, 
    ExternalService::FailedToCreateError.new, 
    ExternalService::FailedToReadError.new, 
    ExternalService::FailedToUpdateError.new, 
    ExternalService::FailedToDeleteError.new, 
    # With an arg 
    [ExternalService::FailedCRUDError, Object.new], 
    [ExternalService::FailedToCreateError, Object.new], 
    [ExternalService::FailedToReadError, Object.new], 
    [ExternalService::FailedToUpdateError, Object.new], 
    [ExternalService::FailedToDeleteError, Object.new], 
    # Instantiated with an arg 
    ExternalService::FailedCRUDError.new(Object.new), 
    ExternalService::FailedToCreateError.new(Object.new), 
    ExternalService::FailedToReadError.new(Object.new), 
    ExternalService::FailedToUpdateError.new(Object.new), 
    ExternalService::FailedToDeleteError.new(Object.new), 
].inject({}) do |errors, args| 
    begin 
    errors.merge!(args => Cloudinary.new(args).create_read_update_or_delete) 
    rescue => e 
    binding.pry 
    end 
end 

if defined?(pp) || require('pp') 
    pp errors_map 
else 
    errors_map.each{ |set| puts set.inspect } 
end 
संबंधित मुद्दे