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 and #severity block modifier.
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.
-
.extended(base) ⇒ Object
:nodoc:.
-
.included(_mod) ⇒ Object
:nodoc:.
-
.inheritors ⇒ Object
:nodoc:.
-
.namify(name) ⇒ Object
Demodulizes and underscores the provided name.
-
.underscore(name) ⇒ Object
Convert ThisName to this_name.
Instance Method Summary collapse
-
#define_error(options, &block) ⇒ Object
Define a new error as a subclass of the exception hosting ErrorDSL.
-
#inherited(subclass) ⇒ Object
Keep track of subclasses of errors using ErrorDSL.
-
#severity(value, &block) ⇒ Object
Temporarily override the default severity with
value
for errors defined in the providedblock
.
Class Method Details
.camelize(name) ⇒ Object
Convert this_name to ThisName. Uses #camelize if name
responds to it, or a naïve version otherwise.
47 48 49 50 51 52 53 54 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 47 def self.camelize(name) name = name.to_s if name.respond_to?(:camelize) name.camelize.freeze else "_#{name}".gsub(/_([a-z])/i) { Regexp.last_match(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.
31 32 33 34 35 36 37 38 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 31 def self.demodulize(name) name = name.to_s if name.respond_to?(:demodulize) name.demodulize.freeze else name.split(/::/)[-1].freeze end end |
.extended(base) ⇒ Object
:nodoc:
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 190 def self.extended(base) # :nodoc: unless base < ::StandardError fail "#{self} cannot extend #{base} (not a StandardError)" end inheritors << base rack_status = base.__rack_status if base.respond_to?(:__rack_status) case rack_status when Hash rack_status = { methods: true, errors: true }.merge(rack_status) when true, nil rack_status = {}.freeze when false rack_status = { methods: false, errors: false }.freeze end if defined?(Rack::Utils) && rack_status Rack::Utils::SYMBOL_TO_STATUS_CODE.each_key do |name| # Make the Rack names safe to use name = name.to_s.gsub(/[^[:word:]]/, '_').squeeze('_').to_sym if rack_status.fetch(:methods, true) base.singleton_class.send :define_method, name do | = {}, &block| define_error(.merge(status: name), &block) end end if rack_status.fetch(:errors, true) base.send :define_error, status: name, key: name end end end end |
.included(_mod) ⇒ Object
:nodoc:
186 187 188 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 186 def self.included(_mod) # :nodoc: fail "#{self} cannot be included" end |
.inheritors ⇒ Object
:nodoc:
225 226 227 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 225 def self.inheritors # :nodoc: @inheritors ||= [] end |
.namify(name) ⇒ Object
Demodulizes and underscores the provided name.
41 42 43 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 41 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.
17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 17 def self.underscore(name) name = name.to_s if name.respond_to?(:underscore) name.underscore.freeze else name.dup.tap { |n| n.gsub!(/[[:upper:]]/) do "_#{$&}".downcase end n.sub!(/^_/, '') }.freeze end end |
Instance Method Details
#define_error(options, &block) ⇒ 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. severity
-
A Ruby symbol representing the severity level associated with this error. If not provided, defaults to :error. Error severity levels are defined in Logger::Severity.
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.
If a block
is provided, errors may be defined as subclasses of the error defined here.
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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 86 def define_error(, &block) fail ArgumentError, 'invalid options' unless .kind_of?(Hash) fail ArgumentError, 'define what error?' if .empty? = .dup status = [:status] severity = [:severity] klass = .delete(:class) if klass fail ArgumentError, ":key conflicts with class:#{klass}" if .key?(:key) key = if status.kind_of?(Symbol) || status.kind_of?(String) "#{klass}_#{KineticCafe::ErrorDSL.namify(status)}" else "#{klass}_#{KineticCafe::ErrorDSL.namify(name)}" end key = String.new(key) else key = .fetch(:key) { fail ArgumentError, 'one of :key or :class must be provided' }.to_s end key.tap do |k| k.gsub!(/[^[:word:]]/, '_') 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' i18n_key = "#{i18n_key_base}.#{key}" if const_defined?(error_name) = String.new("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 if status error.send :define_method, :default_status, -> { status } error.send :private, :default_status error.send :define_singleton_method, :default_status, -> { status } end severity ||= @severity || :error severity.freeze if severity error.send :define_method, :default_severity, -> { severity } error.send :define_singleton_method, :default_severity, -> { severity } end error.instance_exec(&block) if block const_set(error_name, error) end |
#inherited(subclass) ⇒ Object
Keep track of subclasses of errors using ErrorDSL.
181 182 183 184 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 181 def inherited(subclass) #:nodoc: super KineticCafe::ErrorDSL.inheritors << subclass end |
#severity(value, &block) ⇒ Object
Temporarily override the default severity with value
for errors defined in the provided block
.
172 173 174 175 176 177 178 |
# File 'lib/kinetic_cafe/error_dsl.rb', line 172 def severity(value, &block) old_severity, @severity = @severity, value fail 'Severity must have a block' unless block instance_exec(&block) ensure @severity = old_severity end |