2013-12-19 53 views
1

在我的軌道項目的一個模塊,我經常使用這樣的行爲在我的課和模型:創建籌集類特定的錯誤

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感到困惑。

我的基本要求是,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 

回答

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