在我的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
我在创建这样一个模块时遇到了很大的麻烦。我悲伤的早期尝试往往看起来像下面这样,但我很困惑模块范围内的可用内容,如何动态创建类(在方法中?)或者我是否有直截了当的access to the "calling" class at所有
我的基本要求是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
答案 0 :(得分:1)
这样的事情(用纯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