Exception: Magik::Error
- Inherits:
-
StandardError
- Object
- StandardError
- Magik::Error
- Defined in:
- lib/magik.rb
Overview
Base class for every error Magik raises.
Magik errors are not free-form strings. Each one carries three things, and all three are required:
- a stable code matching CODE_FORMAT, shaped
MAGIK_<SUBSYSTEM>_<CONDITION>, that is safe to grep for, link to, and match on in tests and CI; - a cause — one sentence saying what actually went wrong;
- a fix — a runnable command or a concrete edit, never "check your configuration".
The rendered message is deterministic:
MAGIK_LEDGER_UNBALANCED: entries for :Payouts do not balance (debits 1200, credits 900).
fix: run `magik check --ledger Payouts`
Subclasses declare their defaults with the Error.code and Error.fix class-level DSL, so a raise site only has to supply the cause.
Direct Known Subclasses
CommandNotImplementedError, Docs::AmbiguousPageError, Docs::MissingTermError, Docs::PageNotFoundError, Docs::UnavailableError, InvalidOptionError, UnknownCommandError
Constant Summary collapse
- CODE_FORMAT =
The shape every Magik error code must take:
MAGIK_followed by underscore-separated uppercase words. /\AMAGIK_[A-Z0-9]+(?:_[A-Z0-9]+)*\z/- DEFAULT_CODE =
Fallback code for Magik::Error itself.
"MAGIK_ERROR"- DEFAULT_FIX =
Fallback fix for Magik::Error itself.
"read the raised cause above, then see docs/idea/00-build-spec.md"
Instance Attribute Summary collapse
-
#cause_text ⇒ String
readonly
What went wrong, in one sentence.
-
#code ⇒ String
readonly
The stable, greppable error code.
-
#fix ⇒ String
readonly
How to make it stop — a runnable command or a concrete edit.
Class Method Summary collapse
-
.code(value = nil) ⇒ String
Get or set the default error code for this class and its subclasses.
-
.fix(value = nil) ⇒ String
Get or set the default fix line for this class and its subclasses.
-
.normalize_cause(value, klass) ⇒ String
private
A frozen, non-empty cause.
-
.render(code, cause_text, fix) ⇒ String
Render the canonical two-line message for an error triple.
-
.validate_code!(value) ⇒ String
private
The frozen, validated code.
-
.validate_fix!(value) ⇒ String
private
The frozen, validated fix.
Instance Method Summary collapse
-
#initialize(cause_text = nil, code: self.class.code, fix: self.class.fix) ⇒ Error
constructor
A new instance of Error.
-
#to_h ⇒ Hash{Symbol => String}
The error as plain data, ready for
--jsonoutput or a log line.
Constructor Details
#initialize(cause_text = nil, code: self.class.code, fix: self.class.fix) ⇒ Error
Returns a new instance of Error.
207 208 209 210 211 212 |
# File 'lib/magik.rb', line 207 def initialize(cause_text = nil, code: self.class.code, fix: self.class.fix) @code = Error.validate_code!(code) @cause_text = Error.normalize_cause(cause_text, self.class) @fix = Error.validate_fix!(fix) super(self.class.render(@code, @cause_text, @fix)) end |
Instance Attribute Details
#cause_text ⇒ String (readonly)
What went wrong, in one sentence.
Named cause_text because Exception#cause is reserved by Ruby for the
exception that was in flight when this one was raised.
195 196 197 |
# File 'lib/magik.rb', line 195 def cause_text @cause_text end |
#code ⇒ String (readonly)
The stable, greppable error code.
187 188 189 |
# File 'lib/magik.rb', line 187 def code @code end |
#fix ⇒ String (readonly)
How to make it stop — a runnable command or a concrete edit.
199 200 201 |
# File 'lib/magik.rb', line 199 def fix @fix end |
Class Method Details
.code(value = nil) ⇒ String
Get or set the default error code for this class and its subclasses.
Called with an argument it is a writer; called without, a reader that walks up the superclass chain.
136 137 138 139 140 |
# File 'lib/magik.rb', line 136 def code(value = nil) return @code = Error.validate_code!(value) unless value.nil? @code || (superclass.respond_to?(:code) ? superclass.code : DEFAULT_CODE) end |
.fix(value = nil) ⇒ String
Get or set the default fix line for this class and its subclasses.
147 148 149 150 151 |
# File 'lib/magik.rb', line 147 def fix(value = nil) return @fix = Error.validate_fix!(value) unless value.nil? @fix || (superclass.respond_to?(:fix) ? superclass.fix : DEFAULT_FIX) end |
.normalize_cause(value, klass) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a frozen, non-empty cause.
168 169 170 171 |
# File 'lib/magik.rb', line 168 def normalize_cause(value, klass) string = value.to_s (string.strip.empty? ? klass.name.to_s : string).freeze end |
.render(code, cause_text, fix) ⇒ String
Render the canonical two-line message for an error triple.
220 221 222 |
# File 'lib/magik.rb', line 220 def self.render(code, cause_text, fix) "#{code}: #{cause_text}\n fix: #{fix}" end |
.validate_code!(value) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the frozen, validated code.
157 158 159 160 161 162 |
# File 'lib/magik.rb', line 157 def validate_code!(value) string = value.to_s return string.freeze if CODE_FORMAT.match?(string) raise ArgumentError, "error code #{string.inspect} must match #{CODE_FORMAT.source}" end |
.validate_fix!(value) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the frozen, validated fix.
177 178 179 180 181 182 |
# File 'lib/magik.rb', line 177 def validate_fix!(value) string = value.to_s return string.freeze unless string.strip.empty? raise ArgumentError, "a Magik error needs a non-empty fix: line" end |
Instance Method Details
#to_h ⇒ Hash{Symbol => String}
The error as plain data, ready for --json output or a log line.
227 228 229 |
# File 'lib/magik.rb', line 227 def to_h { code: code, cause: cause_text, fix: fix } end |