创建用于引发特定于类的错误的模块

在我的rails项目中,我经常在我的类和模型中使用这种行为:

class Whatever class WhateverError < StandardError; end def initialize(params={}) raise WhateverError.new("Bad params: #{params}") if condition # actual class code to follow end end 

麻烦的是,这是非常重复和相当冗长的。 如果我能在每次需要引发特定于类的错误时执行此操作,我会喜欢它:

 class ErrorRaiser include ClassErrors def initialize(params={}) error("Bad params: #{params}") if condition error if other_condition # has default message # actual class code to follow end def self.class_method error if third_condition # class method, behaves identically end end 

我在创建这样一个模块时遇到了很大的麻烦。 我悲伤的早期尝试往往看起来像下面这样,但我很困惑模块范围内的可用内容,如何动态创建类(在方法中?)或者我是否可以直接访问“调用”一点上课 。

我的基本要求是error既是类方法又是实例方法,它是对调用它的类“命名空间”,并且它有一个默认消息。 有什么想法/帮助吗? 这有可能吗?

 module ClassErrorable # This and the "extend" bit (theoretically) allow error to be a class method as well module ClassMethods def self.error(string=nil) ClassErrorable.new(string).error end end def self.included(base) set_error_class(base) base.extend ClassMethods end def self.set_error_class(base) # I'm shaky on the scoping. Do I refer to this with @ in a class method # but @@ in an instance method? Should I define it here with @ then? @@error_class = "##{base.class}Error".constantize end def self.actual_error # This obviously doesn't work, and in fact, # it raises a syntax error. How can I make my # constant a class inheriting from StandardError? @@actual_error = @@error_class < StandardError; end end def initialize(string) @string = string || "There's been an error!" end def error(string=nil) raise @@actual_error.new(string) end end 

这样的事情(用纯Ruby编写;它可以重构为使用一些特定于Rails的特性,如.constantize):

 module ClassErrorable module ClassMethods def error(message = nil) klass = Object::const_get(exception_class_name) raise klass.new(message || "There's been an error!") end def exception_class_name name + 'Error' end end def self.included(base) base.extend ClassMethods Object::const_set(base.exception_class_name, Class.new(Exception)) end def error(message = nil) self.class.error(message) end end