Module: KineticCafe::ErrorDSL
- Defined in:
- lib/kinetic_cafe/error_dsl.rb
Overview
Make defining new children of KineticCafe::Error easy. Adds the #define_error method.
If using when Rack is present, useful variant methodss are provided matching Rack status symbol codes. These set the default status to the Rack status.
conflict class: :user # => UserConflict, status: :conflict
not_found class: :post # => PostNotFound, status: :not_found
Class Method Summary collapse
-
.camelize(name) ⇒ Object
Convert this_name to ThisName.
-
.demodulize(name) ⇒ Object
Demodulizes This::Name to just Name.
-
.namify(name) ⇒ Object
Demodulizes and underscores the provided name.
-
.underscore(name) ⇒ Object
Convert ThisName to this_name.
Instance Method Summary collapse
-
#define_error(options) ⇒ Object
Define a new error as a subclass of the exception hosting ErrorDSL.
Class Method Details
.camelize(name) ⇒ Object
Convert this_name to ThisName. Uses #camelize if name
responds to it, or a naïve version otherwise.
44 45 46 47 48 49 50 51 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 44 def self.camelize(name) name = name.to_s if name.respond_to?(:camelize) name.camelize.freeze else "_#{name}".gsub(/_([a-z])/i) { $1.upcase }.freeze end end |
.demodulize(name) ⇒ Object
Demodulizes This::Name to just Name. Uses name#demodulize if it is available, or a naïve version otherwise.
28 29 30 31 32 33 34 35 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 28 def self.demodulize(name) name = name.to_s if name.respond_to?(:demodulize) name.demodulize.freeze else name.split(/::/)[-1].freeze end end |
.namify(name) ⇒ Object
Demodulizes and underscores the provided name.
38 39 40 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 38 def self.namify(name) underscore(demodulize(name.to_s)) end |
.underscore(name) ⇒ Object
Convert ThisName to this_name. Uses #underscore if name
responds to it. Otherwise, it uses a super naïve version.
14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 14 def self.underscore(name) name = name.to_s if name.respond_to?(:underscore) name.underscore.freeze else name.dup.tap { |n| n.gsub!(/[[:upper:]]/) { "_#$&".downcase } n.sub!(/^_/, '') }.freeze end end |
Instance Method Details
#define_error(options) ⇒ Object
Define a new error as a subclass of the exception hosting ErrorDSL. Options is a Hash supporting the following values:
status
-
A number or Ruby symbol representing the HTTP status code associated with this error. If not provided, defaults to :bad_request. Must be provided if
class
is provided. HTTP status codes are defined in Rack::Utils. key
-
The name of the error class to be created. Provide as a snake_case value that will be turned into a camelized class name. Mutually exclusive with
class
. class
-
The name of the class the error is for. If present,
status
must be provided to create a complete error class. That is,define_error class: :object, status: :not_found
will create an
ObjectNotFound
error class. header
-
Indicates that when this is caught, it should not be returned with full details, but should instead be treated as a header-only API response. Also available as
header_only
. internal
-
Generates a response that indicates to clients that the error should not be shown to users.
i18n_params
-
An array of parameter names that are expected to be provided for translation. This helps document the expected translations.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 77 def define_error() fail ArgumentError, 'invalid options' unless .kind_of?(Hash) fail ArgumentError, 'define what error?' if .empty? = .dup status = [:status] klass = .delete(:class) if klass if .key?(:key) fail ArgumentError, ":key conflicts with class:#{klass}" end key = if status.kind_of?(Symbol) || status.kind_of?(String) "#{klass}_#{KineticCafe::ErrorDSL.namify(status)}" else "#{klass}_#{KineticCafe::ErrorDSL.namify(name)}" end else key = .fetch(:key) { fail ArgumentError, 'one of :key or :class must be provided' }.to_s end key.tap do |k| k.squeeze!('_') k.gsub!(/^_+/, '') k.gsub!(/_+$/, '') k.freeze end error_name = KineticCafe::ErrorDSL.camelize(key) i18n_key_base = respond_to?(:i18n_key_base) && self.i18n_key_base || 'kcerrors'.freeze i18n_key = "#{i18n_key_base}.#{key}".freeze if const_defined?(error_name) = "key:#{key} already exists as #{error_name}" << " with class:#{klass}" if klass fail ArgumentError, end error = Class.new(self) error.send :define_method, :name, -> { key } error.send :define_method, :i18n_key, -> { i18n_key } error.send :define_singleton_method, :i18n_key, -> { i18n_key } if [:header] || [:header_only] error.send :define_method, :header?, -> { true } error.send :alias_method, :header_only?, :header? end error.send :define_method, :internal?, -> { true } if [:internal] i18n_params = [:i18n_params] if i18n_params || !error.respond_to?(:i18n_params) i18n_params = Array(i18n_params).freeze error.send :define_singleton_method, :i18n_params, -> { i18n_params } end status ||= defined?(Rack::Utils) && :bad_request || 400 status.freeze error.send :define_method, :default_status, -> { status } if status error.send :private, :default_status const_set(error_name, error) end |