Creating a module for raising class-specific errors

六眼飞鱼酱① 提交于 2019-12-23 01:41:38

问题


In my rails projects, I often use this sort of behavior in my classes and models:

class Whatever

  class WhateverError < StandardError; end

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

The trouble is, this is both hugely repetitive and fairly verbose. I'd love it if I could just do this whenever I need to raise a class-specific error:

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

I'm having major trouble creating such a module. My sad early attempts have tended to look something like the below, but I'm pretty confused about what's available within the scope of the module, how to dynamically create classes (within methods?) or whether I have straightforward access to the "calling" class at all.

My basic requirements are that error be both a class method and an instance method, that it be "namespaced" to the class calling it, and that it have a default message. Any thoughts/help? Is this even possible?

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:


How about something like this (written in pure Ruby; it could be refactored to use some Rails-specific features like .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


来源:https://stackoverflow.com/questions/20674714/creating-a-module-for-raising-class-specific-errors

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!