Ruby自定义错误类:inheritance消息属性

我似乎无法find有关自定义exception类的很多信息。

我所知道的

你可以声明你的自定义错误类,让它inheritance自StandardError ,所以可以rescue d:

 class MyCustomError < StandardError end 

这可以让你用下面的方法提高它:

 raise MyCustomError, "A message" 

之后,在救援时得到这个消息

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

我不知道

我想给我的例外一些自定义字段,但我想inheritance父类的message属性。 我发现读这个主题 @message不是一个exception类的实例variables,所以我担心我的inheritance将无法正常工作。

任何人都可以给我更多的细节呢? 我将如何实现具有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 MyCustomErrorreplace了rescue Exception ,请参阅为什么在Ruby中拯救exception=> e`这是一种糟糕的风格? 。

你的想法是对的,但是你说的方式是错误的。 它应该是

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

鉴于所有其他错误inheritance的Exception的ruby核心文档声明了#message

返callback用exception.to_s的结果。 通常这会返回exception的消息或名称。 通过提供一个to_str方法,exception同意在string被预期的地方使用。

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

我会select重新定义to_s / to_str或初始值设定项。 这里有一个例子,我们想用人类可读的方式知道外部服务何时未能做到。

注意:下面的第二个策略使用轨道相当string方法,如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 

重写#初始化策略

这是最接近我在rails中使用的实现的策略。 如上所述,它使用ActiveSupport方法的demodualizeunderscorehumanize 。 但是,这可以像以前的战略一样轻易地消除。

 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 

演示工具

这是一个演示,以显示上述实施的救援和消息传递。 引发exception的类是Cloudinary的虚拟API。 只需将以上策略之一转储到您的Rails控制台中,然后执行此操作。

 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 

我想做类似的事情。 我想传递一个对象到#new,并根据传递对象的一些处理来设置消息。 以下的作品。

 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则不起作用。 解决OP的问题,你也可以传递消息作为额外的参数,并存储你喜欢的任何东西。 至关重要的部分似乎是覆盖#message。