quonfig 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +25 -5
- data/lib/quonfig/bound_client.rb +5 -0
- data/lib/quonfig/client.rb +72 -22
- data/lib/quonfig/evaluation_details.rb +16 -5
- data/lib/quonfig/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7fb6a1cbb69335648d8e68194ef6c177360f575248942a145b214fae2e3a0bf6
|
|
4
|
+
data.tar.gz: 7782d66fe639d2b690932d7d3c7ed2becb793c0a18252ddd7988424eaf29fec5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3ff89f7539988b7a95527fcc93b8fd2b1662ed52c664c87e9855c7f9e926877d4240c04c8703e62d93f93e81c3e28ce5540c27682bfcc65e306942d3985084aa
|
|
7
|
+
data.tar.gz: 8ea638dc75cadf24d41bfc6030748cf03116c359e69a3f8c03a72dea26496f01fe64395502a3f6dafd437c929f07ab81121b84c66cdafeb1feff38f58ba6a875
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.2.0 - 2026-10-29
|
|
4
|
+
|
|
5
|
+
- **Changed (edge case): the `*_details` getters and `evaluate_details` report a value that cannot be parsed as `error_code: "PARSE_ERROR"` (qfg-wg1n).** A malformed ENV_VAR value (an int config whose env var is `"twelve"`, a duration env var `"PT5S garbage"`) and, on the typed getters, a malformed stored int, double or duration (`"twelve"`, `"abc"`, `"PT0.5H"`) were reported as `TYPE_MISMATCH`; they are now `PARSE_ERROR`, the code OpenFeature uses for this case, with the same `reason: "ERROR"`, nil value, variant and `flag_metadata` as before. A value of another type (`get_int_details` on a string config) is still `TYPE_MISMATCH`. The new constant is `Quonfig::EvaluationDetails::ERROR_PARSE_ERROR`. Only the error code on these failure paths changes: the plain getters, `get_or_raise` and the raised errors (`EnvVarParseError`, `TypeMismatchError`) are unchanged, and `evaluate_details` still returns a malformed stored value as stored with a success reason. Code that compared `error_code` to `TYPE_MISMATCH` to detect a malformed value should also accept `PARSE_ERROR`. quonfig-openfeature 2.3.0 already passes `PARSE_ERROR` straight through. Tests: `test/test_parse_error_details.rb`.
|
|
6
|
+
|
|
7
|
+
## 2.1.0 - 2026-10-29
|
|
8
|
+
|
|
9
|
+
- **Added: `evaluate_details(key, context:)`, an untyped details read (qfg-177f).** It returns a `Quonfig::EvaluationDetails` whose `value` is the config's resolved value as stored, after ENV_VAR provision and decryption, with no type check or conversion: a duration comes back as its ISO 8601 text exactly as stored (`"PT90S"`, not milliseconds), a `string_list` as an Array, JSON as stored. The new `value_type` attribute names the stored type (`"duration"`, `"int"`, ...; `nil` when nothing resolved). Reason, variant, `flag_metadata`, error codes and telemetry are the same as the typed `*_details` getters, and it never raises. A malformed stored value (a duration `"30s"`) is returned as-is with a success reason; an unset or unparseable ENV_VAR is still `reason: "ERROR"`, as in the typed getters. Available on the client and on a `with_context` bound client. It matches sdk-go's `Client.EvaluateDetails` and is meant for OpenFeature providers and other callers that do their own typing. Existing getters are unchanged. Tests: `test/test_evaluate_details.rb`.
|
|
10
|
+
- **Fixed: `connection_state` no longer answers `:connected` before the SSE stream's first frame (qfg-fi1s).** On a network client with SSE on, the init fetch installs an envelope before the stream has delivered anything, and `connection_state` read that install as `:connected`. It now reports `:initializing` until the stream's first frame arrives (the connected edge), as the supervisor contract says ("after 200 headers, no frame" is initializing) and as sdk-go, sdk-java, sdk-net and sdk-python already do. Datadir clients and clients with `enable_sse: false` still read `:connected` once config is installed. Tests: `test/test_health_primitives.rb`, `test/test_sse_first_frame.rb` (Test 9a/9b now assert on the public getter).
|
|
11
|
+
|
|
3
12
|
## 2.0.0 - 2026-10-26
|
|
4
13
|
|
|
5
14
|
The typed-getter contract (qfg-zvyy), shared by every Quonfig SDK and pinned by
|
data/README.md
CHANGED
|
@@ -480,10 +480,28 @@ default only covers a missing key). For a typed read that raises, call the
|
|
|
480
480
|
typed getter with no `default:` under `on_no_default: :raise`.
|
|
481
481
|
|
|
482
482
|
The `*_details` getters (`get_int_details(key, context:)` and so on) never
|
|
483
|
-
raise. They return `Quonfig::EvaluationDetails`; a
|
|
484
|
-
|
|
483
|
+
raise. They return `Quonfig::EvaluationDetails`; a value of another type is
|
|
484
|
+
`reason: "ERROR"` with `error_code: "TYPE_MISMATCH"`, and a value that cannot
|
|
485
|
+
be parsed as its declared type (a malformed ENV_VAR value, or a malformed
|
|
486
|
+
stored int, double or duration) is `reason: "ERROR"` with
|
|
487
|
+
`error_code: "PARSE_ERROR"`.
|
|
485
488
|
`get_duration_details` carries the duration in integer milliseconds.
|
|
486
489
|
|
|
490
|
+
To read a value without a type, use `evaluate_details(key, context:)`. It
|
|
491
|
+
returns the value as stored, with `value_type` naming its type, and the same
|
|
492
|
+
`reason`, `variant` and `flag_metadata` as the typed details getters. A
|
|
493
|
+
duration comes back as its ISO 8601 text:
|
|
494
|
+
|
|
495
|
+
```ruby
|
|
496
|
+
details = client.evaluate_details('http.timeout', context: { user: { key: 'u1' } })
|
|
497
|
+
details.value # => "PT90S"
|
|
498
|
+
details.value_type # => "duration"
|
|
499
|
+
details.reason # => "STATIC"
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
It does no type check and never raises; a missing key is `reason: "ERROR"`
|
|
503
|
+
with `error_code: "FLAG_NOT_FOUND"`.
|
|
504
|
+
|
|
487
505
|
## Dynamic log levels (SemanticLogger)
|
|
488
506
|
|
|
489
507
|
Quonfig can drive per-class log levels at runtime. Set config keys like
|
|
@@ -607,8 +625,8 @@ Caveats:
|
|
|
607
625
|
threads race the first request.
|
|
608
626
|
- **`connection_state` never triggers the re-initialization** — a diagnostic
|
|
609
627
|
must not open a socket. A child that has not used the client yet answers
|
|
610
|
-
`:initializing`, which is exactly what it is; it flips to `:connected`
|
|
611
|
-
first use.
|
|
628
|
+
`:initializing`, which is exactly what it is; it flips to `:connected`
|
|
629
|
+
after its first use, once the stream delivers its first frame.
|
|
612
630
|
- The child's telemetry aggregators start empty. The parent flushes the data
|
|
613
631
|
it collected before the fork; the child reports only its own.
|
|
614
632
|
- **Per-job forking pays per job.** A Resque-style worker that forks a child
|
|
@@ -757,7 +775,9 @@ reuse the parent's client object in a child process without it.
|
|
|
757
775
|
envelope install (any source: datadir, initial HTTP fetch, SSE, or fallback
|
|
758
776
|
polling). Returns `nil` before the first install. Preserved across `stop`.
|
|
759
777
|
- `client.connection_state` — a `Symbol` describing the aggregate state:
|
|
760
|
-
`:initializing`, `:connected`, `:disconnected`, or `:falling_back`.
|
|
778
|
+
`:initializing`, `:connected`, `:disconnected`, or `:falling_back`. With
|
|
779
|
+
SSE on, the client reads `:initializing` until the stream delivers its
|
|
780
|
+
first frame, even after the initial fetch has installed config.
|
|
761
781
|
- `client.callback_errors_total(callback: 'on_config_update')` — how many
|
|
762
782
|
times your `on_update` block raised. The SDK catches the error, logs it at
|
|
763
783
|
ERROR with its stack, and keeps delivering updates; a raise is not a worker
|
data/lib/quonfig/bound_client.rb
CHANGED
|
@@ -74,6 +74,11 @@ module Quonfig
|
|
|
74
74
|
@client.get_duration_details(key, context: @context)
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
+
# See Quonfig::Client#evaluate_details.
|
|
78
|
+
def evaluate_details(key)
|
|
79
|
+
@client.evaluate_details(key, context: @context)
|
|
80
|
+
end
|
|
81
|
+
|
|
77
82
|
def enabled?(feature_name)
|
|
78
83
|
@client.enabled?(feature_name, @context)
|
|
79
84
|
end
|
data/lib/quonfig/client.rb
CHANGED
|
@@ -282,37 +282,54 @@ module Quonfig
|
|
|
282
282
|
# carrying the OpenFeature-aligned resolution +reason+ ("STATIC",
|
|
283
283
|
# "TARGETING_MATCH", "SPLIT", "DEFAULT", or "ERROR") plus an
|
|
284
284
|
# +error_code+/+error_message+ on the error path. These methods never
|
|
285
|
-
# raise — exceptions are caught and rendered as ERROR details.
|
|
285
|
+
# raise — exceptions are caught and rendered as ERROR details. A value of
|
|
286
|
+
# another type is error_code TYPE_MISMATCH; a value that cannot be parsed
|
|
287
|
+
# as its declared type (a malformed ENV_VAR value, a malformed stored
|
|
288
|
+
# int, double or duration) is PARSE_ERROR.
|
|
286
289
|
|
|
287
290
|
def get_bool_details(key, context: NO_DEFAULT_PROVIDED)
|
|
288
|
-
|
|
291
|
+
build_details(key, :bool, context)
|
|
289
292
|
end
|
|
290
293
|
|
|
291
294
|
def get_string_details(key, context: NO_DEFAULT_PROVIDED)
|
|
292
|
-
|
|
295
|
+
build_details(key, String, context)
|
|
293
296
|
end
|
|
294
297
|
|
|
295
298
|
def get_int_details(key, context: NO_DEFAULT_PROVIDED)
|
|
296
|
-
|
|
299
|
+
build_details(key, Integer, context)
|
|
297
300
|
end
|
|
298
301
|
|
|
299
302
|
def get_float_details(key, context: NO_DEFAULT_PROVIDED)
|
|
300
|
-
|
|
303
|
+
build_details(key, Float, context)
|
|
301
304
|
end
|
|
302
305
|
|
|
303
306
|
def get_string_list_details(key, context: NO_DEFAULT_PROVIDED)
|
|
304
|
-
|
|
307
|
+
build_details(key, :string_list, context)
|
|
305
308
|
end
|
|
306
309
|
|
|
307
310
|
def get_json_details(key, context: NO_DEFAULT_PROVIDED)
|
|
308
|
-
|
|
311
|
+
build_details(key, :json, context)
|
|
309
312
|
end
|
|
310
313
|
|
|
311
314
|
# Integer milliseconds in +value+ (qfg-2agi.27). A config whose valueType
|
|
312
315
|
# is not duration is ERROR / TYPE_MISMATCH; a malformed value (stored or
|
|
313
|
-
# ENV_VAR) is ERROR with a nil value.
|
|
316
|
+
# ENV_VAR) is ERROR / PARSE_ERROR with a nil value.
|
|
314
317
|
def get_duration_details(key, context: NO_DEFAULT_PROVIDED)
|
|
315
|
-
|
|
318
|
+
build_details(key, :duration, context)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
# Untyped details read (matches sdk-go Client.EvaluateDetails). +value+
|
|
322
|
+
# is the resolved value in its stored form, after ENV_VAR provision and
|
|
323
|
+
# decryption, with no type check, coercion or parse validation: a
|
|
324
|
+
# duration is its ISO 8601 text exactly as stored ("PT90S"), a
|
|
325
|
+
# string_list an Array, a json value as stored. +value_type+ is the
|
|
326
|
+
# stored value type ('string', 'int', 'double', 'bool', 'string_list',
|
|
327
|
+
# 'duration', 'json', ...; nil when nothing resolved). Reason, variant,
|
|
328
|
+
# error_code and telemetry are the same as the typed *_details getters,
|
|
329
|
+
# and like them it never raises. Meant for OpenFeature providers and
|
|
330
|
+
# other callers that do their own typing.
|
|
331
|
+
def evaluate_details(key, context: NO_DEFAULT_PROVIDED)
|
|
332
|
+
build_details(key, nil, context)
|
|
316
333
|
end
|
|
317
334
|
|
|
318
335
|
# True only when the flag resolves to the bool +true+. Never raises
|
|
@@ -650,7 +667,8 @@ module Quonfig
|
|
|
650
667
|
# Aggregate connection state. Returns one of:
|
|
651
668
|
#
|
|
652
669
|
# - +:initializing+ — no envelope has been installed and SSE is not yet
|
|
653
|
-
# connected
|
|
670
|
+
# connected, or (SSE clients) the stream has not delivered its first
|
|
671
|
+
# frame yet, even if the init fetch already installed an envelope.
|
|
654
672
|
# - +:connected+ — SSE is live, or the SDK is delivering configs from a
|
|
655
673
|
# loaded envelope (datadir mode or post-initial-fetch with no SSE).
|
|
656
674
|
# - +:disconnected+ — +stop+ was called, or SSE errored and no fallback
|
|
@@ -681,9 +699,14 @@ module Quonfig
|
|
|
681
699
|
next :disconnected if sse_channel_expected? && !sse_worker_alive?
|
|
682
700
|
next :connected if @sse_state == :connected
|
|
683
701
|
next :disconnected if @sse_state == :error
|
|
702
|
+
# First-frame rule (qfg-fi1s): a client that is supposed to hold an
|
|
703
|
+
# SSE stream is not :connected until that stream delivers its first
|
|
704
|
+
# frame. The init fetch's install alone does not make it connected;
|
|
705
|
+
# "after 200 headers, no frame" is :initializing (contract Test 6).
|
|
706
|
+
next :initializing if sse_channel_expected? && !@sse_ever_connected
|
|
684
707
|
|
|
685
708
|
# No SSE state change yet: state is driven by whether any envelope
|
|
686
|
-
# has been installed (datadir / initial fetch).
|
|
709
|
+
# has been installed (datadir / SSE disabled / initial fetch).
|
|
687
710
|
@last_successful_refresh.nil? ? :initializing : :connected
|
|
688
711
|
end
|
|
689
712
|
end
|
|
@@ -958,7 +981,7 @@ module Quonfig
|
|
|
958
981
|
end
|
|
959
982
|
|
|
960
983
|
# Lazy post-fork re-initialization. Called from every read entry point
|
|
961
|
-
# (+get+, +evaluate_details
|
|
984
|
+
# (+get+, +evaluate_details+ / the +*_details+ getters, +defined?+, +keys+) — the flag read is a
|
|
962
985
|
# plain boolean, so the steady-state cost is one comparison per lookup.
|
|
963
986
|
#
|
|
964
987
|
# The first caller in the child does what +Client.new+ does: its own
|
|
@@ -2185,9 +2208,11 @@ module Quonfig
|
|
|
2185
2208
|
end
|
|
2186
2209
|
|
|
2187
2210
|
# Build a Quonfig::EvaluationDetails for +key+, evaluated against the
|
|
2188
|
-
# caller's context, after coercing/checking +expected_type+.
|
|
2189
|
-
#
|
|
2190
|
-
|
|
2211
|
+
# caller's context, after coercing/checking +expected_type+. A nil
|
|
2212
|
+
# +expected_type+ is the untyped #evaluate_details read: the stored value
|
|
2213
|
+
# with no type check, plus +value_type+. Never raises; all
|
|
2214
|
+
# exceptions become ERROR details.
|
|
2215
|
+
def build_details(key, expected_type, context)
|
|
2191
2216
|
ensure_initialized_after_fork
|
|
2192
2217
|
jit = context == NO_DEFAULT_PROVIDED ? nil : context
|
|
2193
2218
|
ctx = build_context(jit)
|
|
@@ -2208,11 +2233,11 @@ module Quonfig
|
|
|
2208
2233
|
)
|
|
2209
2234
|
rescue Quonfig::Errors::EnvVarParseError => e
|
|
2210
2235
|
# An ENV_VAR value that does not parse as the config's type is
|
|
2211
|
-
#
|
|
2236
|
+
# PARSE_ERROR, like a malformed stored value (qfg-wg1n).
|
|
2212
2237
|
return Quonfig::EvaluationDetails.new(
|
|
2213
2238
|
value: nil,
|
|
2214
2239
|
reason: Quonfig::EvaluationDetails::REASON_ERROR,
|
|
2215
|
-
error_code: Quonfig::EvaluationDetails::
|
|
2240
|
+
error_code: Quonfig::EvaluationDetails::ERROR_PARSE_ERROR,
|
|
2216
2241
|
error_message: e.message,
|
|
2217
2242
|
variant: build_variant(Quonfig::EvaluationDetails::REASON_ERROR, nil, nil),
|
|
2218
2243
|
flag_metadata: build_flag_metadata(nil, nil, nil, nil, nil)
|
|
@@ -2234,14 +2259,14 @@ module Quonfig
|
|
|
2234
2259
|
config_type = result.config&.dig('type') || result.config&.dig(:type)
|
|
2235
2260
|
|
|
2236
2261
|
begin
|
|
2237
|
-
coerced = typed_value(key, result, expected_type)
|
|
2262
|
+
coerced = expected_type.nil? ? stored_value(result) : typed_value(key, result, expected_type)
|
|
2238
2263
|
rescue Quonfig::Errors::TypeMismatchError, Quonfig::Errors::EnvVarParseError => e
|
|
2239
|
-
# A
|
|
2240
|
-
#
|
|
2264
|
+
# A value of another type is TYPE_MISMATCH; a malformed one (a stored
|
|
2265
|
+
# int "twelve", a duration "30s") is PARSE_ERROR (qfg-wg1n).
|
|
2241
2266
|
return Quonfig::EvaluationDetails.new(
|
|
2242
2267
|
value: nil,
|
|
2243
2268
|
reason: Quonfig::EvaluationDetails::REASON_ERROR,
|
|
2244
|
-
error_code:
|
|
2269
|
+
error_code: details_error_code(e),
|
|
2245
2270
|
error_message: e.message,
|
|
2246
2271
|
variant: build_variant(Quonfig::EvaluationDetails::REASON_ERROR, nil, nil),
|
|
2247
2272
|
flag_metadata: build_flag_metadata(config_id, config_type, nil, nil, nil)
|
|
@@ -2257,7 +2282,8 @@ module Quonfig
|
|
|
2257
2282
|
value: coerced,
|
|
2258
2283
|
reason: reason,
|
|
2259
2284
|
variant: build_variant(reason, result.rule_index, result.weighted_value_index),
|
|
2260
|
-
flag_metadata: flag_metadata
|
|
2285
|
+
flag_metadata: flag_metadata,
|
|
2286
|
+
value_type: expected_type.nil? ? stored_value_type(result) : nil
|
|
2261
2287
|
)
|
|
2262
2288
|
rescue StandardError => e
|
|
2263
2289
|
Quonfig::EvaluationDetails.new(
|
|
@@ -2270,6 +2296,30 @@ module Quonfig
|
|
|
2270
2296
|
)
|
|
2271
2297
|
end
|
|
2272
2298
|
|
|
2299
|
+
def details_error_code(error)
|
|
2300
|
+
if error.is_a?(Quonfig::Errors::EnvVarParseError)
|
|
2301
|
+
Quonfig::EvaluationDetails::ERROR_PARSE_ERROR
|
|
2302
|
+
else
|
|
2303
|
+
Quonfig::EvaluationDetails::ERROR_TYPE_MISMATCH
|
|
2304
|
+
end
|
|
2305
|
+
end
|
|
2306
|
+
|
|
2307
|
+
# +result+'s resolved value in stored form (after ENV_VAR provision and
|
|
2308
|
+
# decryption) with no coercion or parse validation: a duration is its
|
|
2309
|
+
# ISO 8601 text as stored. Hashes and Arrays are copied so a caller
|
|
2310
|
+
# mutating the result cannot rewrite the cached config.
|
|
2311
|
+
def stored_value(result)
|
|
2312
|
+
copy_containers(result.raw_value)
|
|
2313
|
+
end
|
|
2314
|
+
|
|
2315
|
+
def copy_containers(value)
|
|
2316
|
+
case value
|
|
2317
|
+
when Hash then value.to_h { |k, v| [k, copy_containers(v)] }
|
|
2318
|
+
when Array then value.map { |v| copy_containers(v) }
|
|
2319
|
+
else value
|
|
2320
|
+
end
|
|
2321
|
+
end
|
|
2322
|
+
|
|
2273
2323
|
# Build the variant string per the cross-SDK spec
|
|
2274
2324
|
# (project/plans/openfeature-resolution-details.md §2).
|
|
2275
2325
|
def build_variant(reason, rule_index, weighted_value_index)
|
|
@@ -15,10 +15,17 @@ module Quonfig
|
|
|
15
15
|
#
|
|
16
16
|
# +error_code+ (only when reason == "ERROR") is one of:
|
|
17
17
|
# "FLAG_NOT_FOUND" — the key was unknown to the store
|
|
18
|
-
# "TYPE_MISMATCH" — the resolved value
|
|
18
|
+
# "TYPE_MISMATCH" — the resolved value is of another type than the getter's
|
|
19
|
+
# "PARSE_ERROR" — the value cannot be parsed as its declared type: a
|
|
20
|
+
# malformed ENV_VAR value, or a malformed stored int,
|
|
21
|
+
# double or duration (qfg-wg1n)
|
|
19
22
|
# "PROVIDER_NOT_READY" — the client has no config yet (init continued
|
|
20
23
|
# on code defaults, or a caught init failure)
|
|
21
24
|
# "GENERAL" — any other failure
|
|
25
|
+
#
|
|
26
|
+
# +value_type+ is set only by Client#evaluate_details: the stored value
|
|
27
|
+
# type ("string", "int", "double", "bool", "string_list", "duration",
|
|
28
|
+
# "json", ...), or nil when nothing resolved. The typed getters leave it nil.
|
|
22
29
|
class EvaluationDetails
|
|
23
30
|
REASON_STATIC = 'STATIC'
|
|
24
31
|
REASON_TARGETING_MATCH = 'TARGETING_MATCH'
|
|
@@ -28,19 +35,21 @@ module Quonfig
|
|
|
28
35
|
|
|
29
36
|
ERROR_FLAG_NOT_FOUND = 'FLAG_NOT_FOUND'
|
|
30
37
|
ERROR_TYPE_MISMATCH = 'TYPE_MISMATCH'
|
|
38
|
+
ERROR_PARSE_ERROR = 'PARSE_ERROR'
|
|
31
39
|
ERROR_GENERAL = 'GENERAL'
|
|
32
40
|
ERROR_PROVIDER_NOT_READY = 'PROVIDER_NOT_READY'
|
|
33
41
|
|
|
34
|
-
attr_reader :value, :reason, :error_code, :error_message, :variant, :flag_metadata
|
|
42
|
+
attr_reader :value, :reason, :error_code, :error_message, :variant, :flag_metadata, :value_type
|
|
35
43
|
|
|
36
44
|
def initialize(value:, reason:, error_code: nil, error_message: nil,
|
|
37
|
-
variant: nil, flag_metadata: nil)
|
|
45
|
+
variant: nil, flag_metadata: nil, value_type: nil)
|
|
38
46
|
@value = value
|
|
39
47
|
@reason = reason
|
|
40
48
|
@error_code = error_code
|
|
41
49
|
@error_message = error_message
|
|
42
50
|
@variant = variant
|
|
43
51
|
@flag_metadata = flag_metadata
|
|
52
|
+
@value_type = value_type
|
|
44
53
|
end
|
|
45
54
|
|
|
46
55
|
def ==(other)
|
|
@@ -50,12 +59,13 @@ module Quonfig
|
|
|
50
59
|
other.error_code == @error_code &&
|
|
51
60
|
other.error_message == @error_message &&
|
|
52
61
|
other.variant == @variant &&
|
|
53
|
-
other.flag_metadata == @flag_metadata
|
|
62
|
+
other.flag_metadata == @flag_metadata &&
|
|
63
|
+
other.value_type == @value_type
|
|
54
64
|
end
|
|
55
65
|
alias eql? ==
|
|
56
66
|
|
|
57
67
|
def hash
|
|
58
|
-
[@value, @reason, @error_code, @error_message, @variant, @flag_metadata].hash
|
|
68
|
+
[@value, @reason, @error_code, @error_message, @variant, @flag_metadata, @value_type].hash
|
|
59
69
|
end
|
|
60
70
|
|
|
61
71
|
def inspect
|
|
@@ -64,6 +74,7 @@ module Quonfig
|
|
|
64
74
|
parts << "error_message=#{@error_message.inspect}" if @error_message
|
|
65
75
|
parts << "variant=#{@variant.inspect}" if @variant
|
|
66
76
|
parts << "flag_metadata=#{@flag_metadata.inspect}" if @flag_metadata
|
|
77
|
+
parts << "value_type=#{@value_type.inspect}" if @value_type
|
|
67
78
|
"#<Quonfig::EvaluationDetails #{parts.join(' ')}>"
|
|
68
79
|
end
|
|
69
80
|
end
|
data/lib/quonfig/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: quonfig
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeff Dwyer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|