Ruby custom error classes: inheritance of the message attribute
我似乎找不到关于自定义异常类的很多信息。
我所知道的
您可以声明您的自定义错误类并让它从
1 2 | class MyCustomError < StandardError end |
这允许您使用以下方法提升它:
1 | raise MyCustomError,"A message" |
稍后,在救援时得到这个信息
1 2 | rescue MyCustomError => e puts e.message # =>"A message" |
我不知道的
我想给我的异常一些自定义字段,但我想从父类继承
有人能告诉我更多细节吗?如何使用
1 2 3 4 5 6 7 | class MyCustomError < StandardError attr_reader :object def initialize(message, object) super(message) @object = object end end |
然后:
1 | raise MyCustomError.new(anObject),"A message" |
得到:
1 2 3 | rescue MyCustomError => e puts e.message # =>"A message" puts e.object # => anObject |
它能工作吗?如果能,这是正确的做事方式吗?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
我已经用
考虑到
Returns the result of invoking exception.to_s. Normally this returns
the exception’s message or name. By supplying a to_str method,
exceptions are agreeing to be used where Strings are expected.
http://ruby doc.org/core-1.9.3/exception.html method-i-message
我会选择重新定义
注意:下面的第二个策略使用rails-pretty-string方法,例如
凌驾于战略之上,而不是凌驾于战略之上,它的工作方式不同
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
控制台输出
1 2 3 4 5 6 7 8 9 10 11 | 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中使用的实现的策略。如上所述,它使用
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
控制台输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 |
演示工具
这是一个演示,演示上述实现的救援和消息传递。引发异常的类是对Cloudinary的一个伪API。只需将上述策略之一转储到Rails控制台中,然后执行此操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | 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 |
你的想法是对的,但你称之为错误的方式。应该是
1 | raise MyCustomError.new(an_object,"A message") |
我想做类似的事情。我想将一个对象传递给新对象,并根据传递对象的某些处理设置消息。以下工作。
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
请注意,如果您不申报