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 (
MAGIK_SOMETHING) 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, 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.
197 198 199 200 201 202 |
# File 'lib/magik.rb', line 197 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.
185 186 187 |
# File 'lib/magik.rb', line 185 def cause_text @cause_text end |
#code ⇒ String (readonly)
The stable, greppable error code.
177 178 179 |
# File 'lib/magik.rb', line 177 def code @code end |
#fix ⇒ String (readonly)
How to make it stop — a runnable command or a concrete edit.
189 190 191 |
# File 'lib/magik.rb', line 189 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.
126 127 128 129 130 |
# File 'lib/magik.rb', line 126 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.
137 138 139 140 141 |
# File 'lib/magik.rb', line 137 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.
158 159 160 161 |
# File 'lib/magik.rb', line 158 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.
210 211 212 |
# File 'lib/magik.rb', line 210 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.
147 148 149 150 151 152 |
# File 'lib/magik.rb', line 147 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.
167 168 169 170 171 172 |
# File 'lib/magik.rb', line 167 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.
217 218 219 |
# File 'lib/magik.rb', line 217 def to_h { code: code, cause: cause_text, fix: fix } end |