Class: Axn::Configurable::Setting
- Inherits:
-
Struct
- Object
- Struct
- Axn::Configurable::Setting
- Defined in:
- lib/axn/configurable.rb
Instance Attribute Summary collapse
-
#default ⇒ Object
Returns the value of attribute default.
-
#name ⇒ Object
Returns the value of attribute name.
-
#one_of ⇒ Object
Returns the value of attribute one_of.
-
#overridable ⇒ Object
Returns the value of attribute overridable.
-
#validate ⇒ Object
Returns the value of attribute validate.
Instance Method Summary collapse
-
#dup_default ⇒ Object
A fresh copy of the default, so mutable defaults (e.g. []) aren't shared across instances.
-
#dynamic_default? ⇒ Boolean
A Proc default is DYNAMIC: re-derived on every read while the setting is unset, and never stored.
-
#validate!(value) ⇒ Object
Raises ArgumentError if the assigned value is not permitted.
Instance Attribute Details
#default ⇒ Object
Returns the value of attribute default
86 87 88 |
# File 'lib/axn/configurable.rb', line 86 def default @default end |
#name ⇒ Object
Returns the value of attribute name
86 87 88 |
# File 'lib/axn/configurable.rb', line 86 def name @name end |
#one_of ⇒ Object
Returns the value of attribute one_of
86 87 88 |
# File 'lib/axn/configurable.rb', line 86 def one_of @one_of end |
#overridable ⇒ Object
Returns the value of attribute overridable
86 87 88 |
# File 'lib/axn/configurable.rb', line 86 def overridable @overridable end |
#validate ⇒ Object
Returns the value of attribute validate
86 87 88 |
# File 'lib/axn/configurable.rb', line 86 def validate @validate end |
Instance Method Details
#dup_default ⇒ Object
A fresh copy of the default, so mutable defaults (e.g. []) aren't shared across instances. dup is a no-op for nil/true/false/Symbol/Integer.
130 131 132 |
# File 'lib/axn/configurable.rb', line 130 def dup_default default.dup end |
#dynamic_default? ⇒ Boolean
A Proc default is DYNAMIC: re-derived on every read while the setting is unset, and never stored. Settings whose default depends on the host app's boot state (a tracer that OpenTelemetry may register after axn loads, a Rails.env-derived flag) would otherwise cache an answer taken before that state existed.
126 |
# File 'lib/axn/configurable.rb', line 126 def dynamic_default? = Axn::Internal::Identity.kind?(default, Proc) |
#validate!(value) ⇒ Object
Raises ArgumentError if the assigned value is not permitted. A validate: lambda may return
a String instead of true to say WHY the value was rejected — worth it for a setting whose
value is an object the app supplies, where "invalid" alone doesn't hint at the contract.
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 |
# File 'lib/axn/configurable.rb', line 90 def validate!(value) # `describe` for the rejected value, plain `inspect` for the allowlist: the allowlist is what the # library author declared, while the value is whatever a caller assigned — and only the latter # can take down the error being raised about it. if one_of && !one_of.include?(value) raise ArgumentError, "#{name} must be one of #{one_of.map(&:inspect).join(', ')}; " \ "got #{Axn::Internal::Identity.describe(value)}" end return unless validate.respond_to?(:call) outcome = validate.call(value) # `String === outcome`, not `outcome.is_a?(String)`: the value comes back from a caller's # lambda, and Module#=== settles the type without dispatching anything to it. return if outcome && !Axn::Internal::Identity.kind?(outcome, String) # A blank reason is no reason: fall back to the plain form below rather than raising with a # dangling " — " and nothing after it. Checked without ActiveSupport's blank extensions, since # this file is loadable on its own and must not depend on them being present. # Rendered to UTF-8 before it is joined: a reason in an incompatible encoding would otherwise # raise Encoding::CompatibilityError out of the interpolation, replacing the ArgumentError this # method promises with one about encodings. # Rendered BEFORE the blank test, not after. `blank_string?` runs `strip`, which raises # Encoding::CompatibilityError on invalid UTF-8 — so testing the raw reason first reintroduced # the very failure the rendering exists to prevent, one step earlier. rendered = Axn::Internal::Identity.utf8_string(outcome) if Axn::Internal::Identity.kind?(outcome, String) detail = rendered unless Axn::Internal::Identity.nil_value?(rendered) || Axn::Internal::Identity.blank_string?(rendered) raise ArgumentError, ["#{name} got invalid value: #{Axn::Internal::Identity.describe(value)}", detail].compact.join(" — ") end |