eight_ball 3.3.3 → 3.4.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 +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +6 -0
- data/lib/eight_ball/conditions/list.rb +18 -4
- data/lib/eight_ball/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f7013714e1fab00bbf56af0703c7212800aa3d664ebf34f6f296353c9f5e2c42
|
|
4
|
+
data.tar.gz: d670e0a056df163ad933f1afa757fb80ba2640bd728349ec830103f40ef921a9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b86c9cd885352a5e60b6e1b699edfb476654eed89c21a1900f6220b45d2ce7bbd541062eab89599140de35c003770a8aacfe17f37180b56262321b4b1cb94f1
|
|
7
|
+
data.tar.gz: cd12202dda5daa1d284e501c9c4a3a5a214f5fd0dd6908aacc521e69e67713eb82494f62418141715b4cd8b953182a721dd705064baaf120a0a81319aee0a600
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.4.0]
|
|
4
|
+
|
|
5
|
+
- Add an opt-in `coerce` boolean to the `list` condition. When `true`, values and the tested input are compared as strings, so a list authored with integers matches a string caller (and vice versa). Defaults to exact-type matching, so existing definitions are unchanged; the flag is serialized only when enabled.
|
|
6
|
+
|
|
3
7
|
## [3.3.3]
|
|
4
8
|
|
|
5
9
|
- Add `.compact` before each `.map(&:to_wire)` so stray nil conditions are
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -83,6 +83,12 @@ A Condition must either be `true` or `false`. It describes when a Feature is ena
|
|
|
83
83
|
- [Range](lib/eight_ball/conditions/range.rb): This condition is satisfied if the given value is within the specified range (inclusive).
|
|
84
84
|
- [Percentage](lib/eight_ball/conditions/percentage.rb): This condition is satisfied for a deterministic, sticky subset of subjects sized to `percentage` percent. Bucketing is salted by the flag name so a subject is decorrelated across flags. Wire form: `{"type":"percentage","parameter":"account_id","percentage":<0..100>}`.
|
|
85
85
|
|
|
86
|
+
#### List value coercion
|
|
87
|
+
|
|
88
|
+
By default a `list` matches by exact type, so an integer value never matches a string (and vice versa). Set `coerce: true` on a list to compare both sides as strings, so an integer-authored list matches a string caller. The default stays exact, and the field is serialized only when enabled. Wire form: `{"type":"list","parameter":"account_id","values":[2,3],"coerce":true}`.
|
|
89
|
+
|
|
90
|
+
Coercion is exact string comparison (`value.to_s`), not numeric or fuzzy: `1.0` does not match a `[1]` list, and `nil`/`""` share a string form. It is intended for scalar id/name lists. Cross-version note: a reader on a pre-`coerce` gem ignores the field and matches exactly, so a `coerce:true` flag can evaluate differently across gem versions until every reader is upgraded.
|
|
91
|
+
|
|
86
92
|
#### Sticky percentage bucketing
|
|
87
93
|
|
|
88
94
|
The `percentage` condition buckets a subject deterministically:
|
|
@@ -4,7 +4,7 @@ module EightBall::Conditions
|
|
|
4
4
|
# The List Condition describes a list of acceptable values.
|
|
5
5
|
# These can be strings, integers, etc.
|
|
6
6
|
class List < Base
|
|
7
|
-
attr_reader :values
|
|
7
|
+
attr_reader :values, :coerce
|
|
8
8
|
|
|
9
9
|
# Creates a new instance of a List Condition.
|
|
10
10
|
#
|
|
@@ -16,30 +16,44 @@ module EightBall::Conditions
|
|
|
16
16
|
# The name of the parameter this Condition was created for (eg. "account_id").
|
|
17
17
|
# This value is only used by calling classes as a way to know what to pass
|
|
18
18
|
# into {satisfied?}.
|
|
19
|
+
# @option options [Boolean] :coerce
|
|
20
|
+
# When true, compare values and the tested input as strings so that, eg.,
|
|
21
|
+
# an integer list matches a string caller. Defaults to exact-type matching.
|
|
19
22
|
def initialize(options = {})
|
|
20
23
|
options ||= {}
|
|
21
24
|
|
|
22
25
|
@values = Array(options[:values])
|
|
26
|
+
# Store a canonical true/nil so the wire never carries a stray non-boolean.
|
|
27
|
+
@coerce = options[:coerce] ? true : nil
|
|
23
28
|
self.parameter = options[:parameter]
|
|
24
29
|
end
|
|
25
30
|
|
|
26
31
|
# @example
|
|
27
|
-
# condition =
|
|
32
|
+
# condition = EightBall::Conditions::List.new(values: [1, 'a'])
|
|
28
33
|
# condition.satisfied? 1 => true
|
|
29
34
|
# condition.satisfied? 2 => false
|
|
30
35
|
# condition.satisfied? 'a' => true
|
|
31
36
|
def satisfied?(value)
|
|
37
|
+
if @coerce
|
|
38
|
+
string_value = value.to_s
|
|
39
|
+
return values.any? { |v| v.to_s == string_value }
|
|
40
|
+
end
|
|
41
|
+
|
|
32
42
|
values.include? value
|
|
33
43
|
end
|
|
34
44
|
|
|
35
45
|
def wire_fields
|
|
36
|
-
|
|
46
|
+
# coerce before parameter so the wire key order matches the eight-ball-ts
|
|
47
|
+
# port (whose parameter is always emitted last), keeping the two byte-identical.
|
|
48
|
+
%i[values coerce parameter]
|
|
37
49
|
end
|
|
38
50
|
|
|
39
51
|
protected
|
|
40
52
|
|
|
41
53
|
def state
|
|
42
|
-
|
|
54
|
+
# sort_by(&:to_s) so a mixed-type list (eg. the int/string values coerce
|
|
55
|
+
# is built for) does not raise ArgumentError in ==/hash.
|
|
56
|
+
super + [@values.sort_by(&:to_s), @coerce]
|
|
43
57
|
end
|
|
44
58
|
end
|
|
45
59
|
end
|
data/lib/eight_ball/version.rb
CHANGED