Ruby 사용자 정의 오류 클래스 : 메시지 속성 상속
사용자 지정 예외 클래스에 대한 정보를 많이 찾을 수없는 것 같습니다.
내가 아는 것
사용자 정의 오류 클래스를 선언하고에서 상속 StandardError
하도록 할 수 있으므로 rescue
d 가 될 수 있습니다 .
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
작동 할 것인가, 작동한다면 이것이 올바른 일을하는 방법인가?
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
, 참조 는`구조 예외 => e` 루비에 나쁜 스타일 왜? .
Exception
다른 모든 오류가 상속 하는의 루비 코어 문서 에서 다음과 같이 설명합니다.#message
예외를 호출 한 결과를 반환합니다. 일반적으로 이것은 예외의 메시지 또는 이름을 반환합니다. to_str 메소드를 제공하면 예외가 문자열이 예상되는 곳에 사용되는 데 동의합니다.
http://ruby-doc.org/core-1.9.3/Exception.html#method-i-message
재정의 to_s
/ to_str
또는 이니셜 라이저를 선택합니다. 다음은 외부 서비스가 어떤 작업을 수행하지 못했을 때 대부분 사람이 읽을 수있는 방식으로 알고 싶은 예입니다.
참고 : 아래의 두 번째 전략 demodualize
은 약간 복잡 할 수 있으므로 예외에서 수행하는 것이 현명하지 않을 수있는 과 같은 rails pretty string 메서드를 사용합니다 . 필요한 경우 메서드 서명에 더 많은 인수를 추가 할 수도 있습니다.
#to_str이 아닌 #to_s 전략을 재정의하면 다르게 작동합니다.
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
데모 도구
This is a demo to show rescuing and messaging of the above implementation. The class raising the exceptions is a fake API to Cloudinary. Just dump one of the above strategies into your rails console, followed by this.
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
Your idea is right, but the way you call it is wrong. It should be
raise MyCustomError.new(an_object, "A message")
I wanted to do something similar. I wanted to pass an object to #new and have the message set based on some processing of the passed object. The following works.
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
Note that if you don't declare attr_accessor :message
then it will not work. Addressing the OP's issue, you could also pass the message as an additional argument and store anything you like. The crucial part appears to be overriding #message.
'Programing' 카테고리의 다른 글
Pandas로 무작위 정수의 DataFrame을 만드는 방법은 무엇입니까? (0) | 2020.09.01 |
---|---|
Django 프로파일 링 (0) | 2020.09.01 |
유형을 DB에 저장할 때 최대 MIMEType 길이 (0) | 2020.09.01 |
git 저장소와 같은 github 위키를 체크 아웃 할 수 있습니까? (0) | 2020.09.01 |
.gitignore 파일의 반대? (0) | 2020.09.01 |