রুবি কাস্টম ত্রুটি শ্রেণি: বার্তার বৈশিষ্ট্যের উত্তরাধিকার


95

আমি কাস্টম ব্যতিক্রম ক্লাস সম্পর্কে অনেক তথ্য খুঁজে পেতে পারে না।

আমি কি জানি

আপনি আপনার কাস্টম ত্রুটি শ্রেণি ঘোষণা করতে পারেন এবং এটির উত্তরাধিকার সূত্রে StandardErrorতা ছেড়ে দিতে পারেন, তাই এটি rescueডি হতে পারে :

class MyCustomError < StandardError
end

এটি আপনাকে এটি ব্যবহার করে এটি বাড়ানোর অনুমতি দেয়:

raise MyCustomError, "A message"

এবং পরে, উদ্ধার করার সময় সেই বার্তাটি পান

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

আমি কি জানি না

আমি আমার ব্যতিক্রম কিছু কাস্টম ক্ষেত্র দিতে চাই, তবে আমি messageপিতাম শ্রেণীর কাছ থেকে বৈশিষ্ট্যটি উত্তরাধিকারী করতে চাই । আমি এই বিষয়টি পড়তে পেরেছি @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

এটি কি কাজ করবে, এবং যদি তা করে তবে এটি কি কাজ করার সঠিক পদ্ধতি?


4
না rescue Exception => e। এটি ডিফল্টের চেয়ে rescue => eবিস্তৃত যা প্রসারিত StandardErrorএবং Ctrl + C সহ সমস্ত কিছুই ধরে ফেলে। আমি করতে চাই rescue MyCustomError => e
রায়ান টেইলর

4
@ রায়ানটায়লর আমি আরও সঠিক পদ্ধতির জন্য আমার প্রশ্নটি সম্পাদনা করেছি।
মারিওডিএস

উত্তর:


122

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 Exceptionসাথে প্রতিস্থাপন করেছি rescue MyCustomError, দেখুন কেন রুবিতে `উদ্ধার ব্যতিক্রম => ই` এর পক্ষে খারাপ স্টাইল?


আমি আপনার উত্তরটি গ্রহণ করব কারণ আপনি আমাকে পুরো বাক্য গঠনটি দেখিয়েছিলেন। ধন্যবাদ!
মারিওডিডিএস

4
এখানে আমরা করছি rescue Exception, তবে কেন নয় rescue MyCustomError?
Dfr

এফওয়াইআই, যদি প্রথম আর্গুমেন্ট, অবজেক্টটি কোনও বিকল্প হয় এবং raise MyCustomError, "a message"ছাড়া new, "বার্তা" সেট করা হবে না।
হিরোশি

আমাদের কাস্টম ব্যতিক্রম শ্রেণিতে উত্থাপিত বার্তাটি কোনওভাবে পাওয়ার কী উপায় আছে?
সাইবারমিউ

@ সাইবারমাইও আপনার কি অর্থ? আপনি কি করতে চান?
স্টিফান

10

রুবি কোর ডকুমেন্টেশন কী দেওয়া হয়েছে Exception, যা থেকে অন্যান্য সমস্ত ত্রুটিগুলি উত্তরাধিকার সূত্রে লিখিত হয়েছে#message

চাওয়া ব্যতিক্রমের ফলাফল.ট_সগুলি প্রদান করে Return সাধারণত এটি ব্যতিক্রমের বার্তা বা নামটি দেয়। একটি টো_সেটর সরবরাহ করে, ব্যতিক্রমগুলি যেখানে স্ট্রিংস প্রত্যাশিত সেখানে ব্যবহৃত হতে সম্মত হচ্ছে।

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

আমি পুনরায় সংজ্ঞা to_s/ to_strবা আরম্ভকারীটিকে বেছে নেব । এখানে একটি উদাহরণ যেখানে আমরা জানতে চাই, বেশিরভাগ মানুষের পাঠযোগ্য উপায়ে, যখন কোনও বাহ্যিক পরিষেবা কোনও কাজ করতে ব্যর্থ হয়।

দ্রষ্টব্য: নীচের দ্বিতীয় কৌশলটিতে রেলগুলি সুন্দর স্ট্রিং পদ্ধতিগুলি ব্যবহার করে, যেমন demodualize, কিছুটা জটিল এবং তাই কোনও ব্যতিক্রম করার জন্য এটি সম্ভবত বুদ্ধিমান। আপনি প্রয়োজন হলে পদ্ধতি স্বাক্ষরে আরও যুক্তি যুক্ত করতে পারেন।

ওভাররাইডিং # থেকে_স কৌশল নয় ওভাররাইডিং, এটি ভিন্নভাবে কাজ করে

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এবংhumanize ActiveSupport পদ্ধতি। তবে এটি আগের কৌশল হিসাবে সহজেই সরানো যেতে পারে।

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

6

আপনার ধারণাটি সঠিক, তবে আপনি যেভাবে এটি কল করবেন তা ভুল। এটা করা উচিত

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

ঠিক আছে, আমি ভেবেছিলাম আপনি যে বার্তাটি দিয়েছিলেন সেটি raiseকীওয়ার্ড বা অন্য কোনও কিছুর দ্বিতীয় প্যারামিটার ।
মারিওডিডিএস

আপনি initializeদুটি যুক্তি নিতে নতুন সংজ্ঞা দিয়েছেন। newআর্গুমেন্ট পাস initialize
সাওয়া

অথবা, আপনি প্রথম বন্ধনী বাদ দিতে পারেন।
সাওয়া

আমি যে বিট বুঝি, কিন্তু বিষয় আমার প্রশ্ন আমি লিঙ্ক এর পোস্টার ভালো এটা আছে: raise(BillRowError.new(:roamingcalls, @index), "Roaming Calls field missing")। সুতরাং তিনি raiseদুটি পরামিতি সহ কল করেছেন: একটি নতুন BillRowErrorঅবজেক্ট এবং তার বার্তা। আমি কেবল সিনট্যাক্স দ্বারা বিভ্রান্ত ... অন্য টিউটোরিয়ালে আমি সর্বদা এটির মতো দেখতে পাই:raise Error, message
মারিওডিডিএস

4
সমস্যাটি আপনি কতটা যুক্তি দিয়ে পাস করেছেন তা নয় raise; এটা বেশ নমনীয়। সমস্যাটি হ'ল আপনি initializeদুটি যুক্তি নিতে সংজ্ঞায়িত করেছেন এবং কেবল একটি দিয়েছেন gave আপনার উদাহরণ দেখুন। BillRowError.new(:roamingcalls, @index)দুটি যুক্তি দেওয়া হয়।
সাওয়া

5

আমি অনুরূপ কিছু করতে চেয়েছিলেন। আমি একটি নতুন বস্তুকে # নতুন করে পাস করতে এবং পাস করা অবজেক্টের কিছু প্রক্রিয়াজাতকরণের ভিত্তিতে বার্তা সেট করতে চেয়েছিলাম। নিম্নলিখিত কাজ করে।

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তবে এটি কার্যকর হবে না। ওপি-র ইস্যুটি সম্বোধন করে আপনি বার্তাটি অতিরিক্ত যুক্তি হিসাবেও পাস করতে পারেন এবং আপনার পছন্দসই কিছু সংরক্ষণ করতে পারেন। গুরুত্বপূর্ণ অংশটি # ম্যাসেজকে ওভাররাইড করে বলে মনে হচ্ছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.