【问题标题】:Creating a module for raising class-specific errors创建用于引发特定于类的错误的模块
【发布时间】:2013-12-19 06:22:43
【问题描述】:

在我的 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 感到很困惑。

我的基本要求是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-on-rails ruby ruby-on-rails-3 metaprogramming


    【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2012-11-24
      • 2018-07-03
      • 2010-11-29
      • 2015-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-09
      • 1970-01-01
      相关资源
      最近更新 更多