splitclient-rb 4.3.0.canary.2 → 4.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.txt +2 -1
- data/Detailed-README.md +8 -0
- data/lib/splitclient-rb.rb +0 -1
- data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +8 -10
- data/lib/splitclient-rb/engine/matchers/between_matcher.rb +27 -22
- data/lib/splitclient-rb/engine/matchers/combiners.rb +3 -7
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +33 -44
- data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +9 -5
- data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +9 -5
- data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +16 -4
- data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +9 -5
- data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +12 -4
- data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +12 -4
- data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +26 -21
- data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +9 -5
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +25 -21
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +25 -21
- data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +12 -4
- data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +19 -13
- data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +9 -5
- data/lib/splitclient-rb/engine/matchers/set_matcher.rb +5 -1
- data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +12 -4
- data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +8 -7
- data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +25 -20
- data/lib/splitclient-rb/engine/parser/condition.rb +1 -1
- data/lib/splitclient-rb/engine/parser/evaluator.rb +14 -16
- data/lib/splitclient-rb/version.rb +1 -1
- metadata +4 -5
- data/lib/splitclient-rb/engine/matchers/attribute_matcher.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b62b60ce935de1b5345ec16107e6911321abf9c
|
4
|
+
data.tar.gz: 2ed5525256582608b165f9a42a056657fb6fc24c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 837b99afc42609f08b51eee920c0b9492da45fb93e3ddfe187f0edc454e36077684e1bef54312a3a31e529d7fba2b10730179cc7e82a88becc4dc4e9d2435acf
|
7
|
+
data.tar.gz: cb785d0b3152892b86fa24a7b3369247ee4d17ffd2a4e9d01452bdb3d4e7b7eedb7648793ce8eb5c9e51d3ce2911256ce1da5e9bea7ad285d90f1a6bee913708
|
data/CHANGES.txt
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
4.3.0 (
|
1
|
+
4.3.0 (Oct 13th, 2017)
|
2
2
|
- Add impression listener
|
3
3
|
- Add support for client shutdown (destroy())
|
4
4
|
- Add "time" to the routed impressions
|
5
5
|
- Add support to apply attribute matcher to the traffic type
|
6
|
+
- Add support for string matchers to match on matching keys
|
6
7
|
|
7
8
|
4.2.3 (August 4, 2017)
|
8
9
|
- Use ENV vars in producer
|
data/Detailed-README.md
CHANGED
@@ -480,6 +480,14 @@ end
|
|
480
480
|
|
481
481
|
By doing that SDK will recreate threads for each new worker, besides master.
|
482
482
|
|
483
|
+
## Proxy support
|
484
|
+
|
485
|
+
SDK respects http_proxy environment variable, all you need to do to use proxy is assign your proxy address to that variable in the format:
|
486
|
+
|
487
|
+
```
|
488
|
+
http_proxy=http://username:password@hostname:port
|
489
|
+
```
|
490
|
+
|
483
491
|
## Framework support
|
484
492
|
|
485
493
|
Currently SDK supports:
|
data/lib/splitclient-rb.rb
CHANGED
@@ -43,7 +43,6 @@ require 'splitclient-rb/engine/parser/condition'
|
|
43
43
|
require 'splitclient-rb/engine/parser/partition'
|
44
44
|
require 'splitclient-rb/engine/parser/split_adapter'
|
45
45
|
require 'splitclient-rb/engine/parser/evaluator'
|
46
|
-
require 'splitclient-rb/engine/matchers/attribute_matcher'
|
47
46
|
require 'splitclient-rb/engine/matchers/combiners'
|
48
47
|
require 'splitclient-rb/engine/matchers/combining_matcher'
|
49
48
|
require 'splitclient-rb/engine/matchers/all_keys_matcher'
|
@@ -2,20 +2,14 @@ module SplitIoClient
|
|
2
2
|
#
|
3
3
|
# class to implement the all keys matcher
|
4
4
|
#
|
5
|
-
class AllKeysMatcher
|
6
|
-
|
7
|
-
|
8
|
-
def initialize
|
9
|
-
@matcher_type = 'ALL_KEYS'
|
10
|
-
end
|
5
|
+
class AllKeysMatcher
|
6
|
+
MATCHER_TYPE = 'ALL_KEYS'.freeze
|
11
7
|
|
12
8
|
#
|
13
9
|
# evaluates if the key matches the matcher
|
14
10
|
#
|
15
|
-
# @param key [string] key value to be matched
|
16
|
-
#
|
17
11
|
# @return [boolean] true for all instances
|
18
|
-
def match?(
|
12
|
+
def match?(_args)
|
19
13
|
true
|
20
14
|
end
|
21
15
|
|
@@ -24,7 +18,7 @@ module SplitIoClient
|
|
24
18
|
#
|
25
19
|
# @param obj [object] object to be evaluated
|
26
20
|
#
|
27
|
-
# @
|
21
|
+
# @return [boolean] true if obj equals the matcher
|
28
22
|
def equals?(obj)
|
29
23
|
if obj.nil?
|
30
24
|
false
|
@@ -37,6 +31,10 @@ module SplitIoClient
|
|
37
31
|
end
|
38
32
|
end
|
39
33
|
|
34
|
+
def string_type?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
40
38
|
#
|
41
39
|
# function to print string value for this matcher
|
42
40
|
#
|
@@ -1,25 +1,25 @@
|
|
1
1
|
module SplitIoClient
|
2
|
+
class BetweenMatcher
|
3
|
+
MATCHER_TYPE = 'BETWEEN'.freeze
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
attr_reader :matcher_type
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute_hash)
|
8
|
-
@matcher_type = "BETWEEN"
|
9
8
|
@attribute = attribute_hash[:attribute]
|
10
9
|
@data_type = attribute_hash[:data_type]
|
11
|
-
@start_value =
|
12
|
-
@end_value =
|
10
|
+
@start_value = formatted_value(attribute_hash[:start_value], true)
|
11
|
+
@end_value = formatted_value(attribute_hash[:end_value], true)
|
13
12
|
end
|
14
13
|
|
15
|
-
def match?(
|
16
|
-
|
17
|
-
if
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
def match?(args)
|
15
|
+
return false if !args.key?(:attributes) && !args.key?(:value)
|
16
|
+
return false if args.key?(:value) && args[:value].nil?
|
17
|
+
return false if args.key?(:attributes) && args[:attributes].nil?
|
18
|
+
|
19
|
+
value = formatted_value(args[:value] || args[:attributes][@attribute.to_sym])
|
20
|
+
return false unless value.is_a?(Integer)
|
21
21
|
|
22
|
-
|
22
|
+
(@start_value..@end_value).include? value
|
23
23
|
end
|
24
24
|
|
25
25
|
def equals?(obj)
|
@@ -34,18 +34,23 @@ module SplitIoClient
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
def string_type?
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
37
41
|
private
|
38
|
-
|
42
|
+
|
43
|
+
def formatted_value(value, sdk_data = false)
|
39
44
|
case @data_type
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
45
|
+
when 'NUMBER'
|
46
|
+
value
|
47
|
+
when 'DATETIME'
|
48
|
+
value = value / 1000 if sdk_data
|
49
|
+
|
50
|
+
SplitIoClient::Utilities.to_milis_zero_out_from_seconds(value)
|
51
|
+
else
|
52
|
+
@logger.error('Invalid data type')
|
47
53
|
end
|
48
54
|
end
|
49
55
|
end
|
50
|
-
|
51
56
|
end
|
@@ -2,63 +2,59 @@ module SplitIoClient
|
|
2
2
|
#
|
3
3
|
# class to implement the combining matcher
|
4
4
|
#
|
5
|
-
class CombiningMatcher
|
5
|
+
class CombiningMatcher
|
6
|
+
MATCHER_TYPE = 'COMBINING_MATCHER'.freeze
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
@matcher_list = []
|
11
|
-
|
12
|
-
#
|
13
|
-
# combiner value
|
14
|
-
#
|
15
|
-
@combiner = ''
|
16
|
-
|
17
|
-
def initialize(combiner, delegates)
|
18
|
-
unless delegates.nil?
|
19
|
-
@matcher_list = delegates
|
20
|
-
end
|
21
|
-
unless combiner.nil?
|
22
|
-
@combiner = combiner
|
23
|
-
end
|
8
|
+
def initialize(combiner = '', matchers = [])
|
9
|
+
@combiner = combiner
|
10
|
+
@matchers = matchers
|
24
11
|
end
|
25
12
|
|
26
13
|
#
|
27
14
|
# evaluates if the key matches the matchers within the combiner
|
28
15
|
#
|
29
|
-
# @param
|
16
|
+
# @param matching_key [string] key value to be matched
|
17
|
+
# @param bucketing_key [string] bucketing key to be matched
|
18
|
+
# @param evaluator [instance of Evaluator class]
|
19
|
+
# @param attributes [hash]
|
30
20
|
#
|
31
|
-
# @return [boolean]
|
32
|
-
def match?(
|
33
|
-
if @
|
34
|
-
return false
|
35
|
-
end
|
21
|
+
# @return [boolean]
|
22
|
+
def match?(args)
|
23
|
+
return false if @matchers.empty?
|
36
24
|
|
37
25
|
case @combiner
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
return false
|
26
|
+
when Combiners::AND
|
27
|
+
return eval_and(args)
|
28
|
+
else
|
29
|
+
@logger.error('Invalid combiner type')
|
43
30
|
end
|
31
|
+
|
32
|
+
false
|
44
33
|
end
|
45
34
|
|
46
35
|
#
|
47
36
|
# auxiliary method to evaluate each of the matchers within the combiner
|
48
37
|
#
|
49
|
-
# @param
|
38
|
+
# @param matching_key [string] key value to be matched
|
39
|
+
# @param bucketing_key [string] bucketing key to be matched
|
50
40
|
# @param evaluator [Evaluator] used in dependency_matcher
|
51
41
|
# @param attributes [hash] attributes to pass to the treatment class
|
52
42
|
#
|
53
43
|
# @return [boolean] match value for combiner delegates
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
44
|
+
def eval_and(args)
|
45
|
+
# Convert all keys to symbols
|
46
|
+
args[:attributes] = args[:attributes].inject({}){ |memo, (k,v)| memo[k.to_sym] = v; memo } if args && args[:attributes]
|
47
|
+
@matchers.all? do |matcher|
|
48
|
+
if match_with_key?(matcher)
|
49
|
+
matcher.match?(value: args[:matching_key])
|
50
|
+
else
|
51
|
+
matcher.match?(args)
|
52
|
+
end
|
59
53
|
end
|
54
|
+
end
|
60
55
|
|
61
|
-
|
56
|
+
def match_with_key?(matcher)
|
57
|
+
matcher.respond_to?(:attribute) && matcher.attribute.nil? && matcher.string_type?
|
62
58
|
end
|
63
59
|
|
64
60
|
#
|
@@ -84,14 +80,7 @@ module SplitIoClient
|
|
84
80
|
#
|
85
81
|
# @reutrn [string] string value of this matcher
|
86
82
|
def to_s
|
87
|
-
|
88
|
-
@matcher_list.each_with_index do |matcher, i|
|
89
|
-
result += matcher.to_s
|
90
|
-
result += ' ' + @combiner if i != 0
|
91
|
-
end
|
92
|
-
result
|
83
|
+
@matcher_list.map(&:to_s).join("#{@combiner} ")
|
93
84
|
end
|
94
|
-
|
95
85
|
end
|
96
|
-
|
97
86
|
end
|
@@ -1,17 +1,21 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class ContainsAllMatcher < SetMatcher
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
MATCHER_TYPE = 'CONTAINS_ALL'.freeze
|
4
|
+
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute, remote_array)
|
8
8
|
super(attribute, remote_array)
|
9
9
|
end
|
10
10
|
|
11
|
-
def match?(
|
11
|
+
def match?(args)
|
12
12
|
return false if @remote_set.empty?
|
13
13
|
|
14
|
-
@remote_set.subset? local_set(
|
14
|
+
@remote_set.subset? local_set(args[:attributes], @attribute)
|
15
|
+
end
|
16
|
+
|
17
|
+
def string_type?
|
18
|
+
false
|
15
19
|
end
|
16
20
|
end
|
17
21
|
end
|
@@ -1,15 +1,19 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class ContainsAnyMatcher < SetMatcher
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
MATCHER_TYPE = 'CONTAINS_ANY'.freeze
|
4
|
+
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute, remote_array)
|
8
8
|
super(attribute, remote_array)
|
9
9
|
end
|
10
10
|
|
11
|
-
def match?(
|
12
|
-
local_set(
|
11
|
+
def match?(args)
|
12
|
+
local_set(args[:attributes], @attribute).intersect? @remote_set
|
13
|
+
end
|
14
|
+
|
15
|
+
def string_type?
|
16
|
+
false
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
@@ -1,18 +1,30 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class ContainsMatcher
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
MATCHER_TYPE = 'CONTAINS_WITH'.freeze
|
4
|
+
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute, substr_list)
|
8
8
|
@attribute = attribute
|
9
9
|
@substr_list = substr_list
|
10
10
|
end
|
11
11
|
|
12
|
-
def match?(
|
12
|
+
def match?(args)
|
13
|
+
return false if !args.key?(:attributes) && !args.key?(:value)
|
14
|
+
return false if args.key?(:value) && args[:value].nil?
|
15
|
+
return false if args.key?(:attributes) && args[:attributes].nil?
|
16
|
+
|
17
|
+
value = args[:value] || args[:attributes].fetch(@attribute) do |a|
|
18
|
+
args[:attributes][a.to_s] || args[:attributes][a.to_sym]
|
19
|
+
end
|
20
|
+
|
13
21
|
return false if @substr_list.empty?
|
14
22
|
|
15
23
|
@substr_list.any? { |substr| value.to_s.include? substr }
|
16
24
|
end
|
25
|
+
|
26
|
+
def string_type?
|
27
|
+
true
|
28
|
+
end
|
17
29
|
end
|
18
30
|
end
|
@@ -1,16 +1,20 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class DependencyMatcher
|
3
|
-
|
4
|
-
'IN_SPLIT_TREATMENT'.freeze
|
5
|
-
end
|
3
|
+
MATCHER_TYPE = 'IN_SPLIT_TREATMENT'.freeze
|
6
4
|
|
7
5
|
def initialize(split, treatments)
|
8
6
|
@split = split
|
9
7
|
@treatments = treatments
|
10
8
|
end
|
11
9
|
|
12
|
-
def match?(
|
13
|
-
|
10
|
+
def match?(args)
|
11
|
+
keys = { matching_key: args[:matching_key], bucketing_key: args[:bucketing_key] }
|
12
|
+
|
13
|
+
@treatments.include?(args[:evaluator].call(keys, @split, args[:attributes])[:treatment])
|
14
|
+
end
|
15
|
+
|
16
|
+
def string_type?
|
17
|
+
false
|
14
18
|
end
|
15
19
|
end
|
16
20
|
end
|
@@ -1,18 +1,26 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class EndsWithMatcher
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
MATCHER_TYPE = 'ENDS_WITH'.freeze
|
4
|
+
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute, suffix_list)
|
8
8
|
@attribute = attribute
|
9
9
|
@suffix_list = suffix_list
|
10
10
|
end
|
11
11
|
|
12
|
-
def match?(
|
12
|
+
def match?(args)
|
13
|
+
value = args[:value] || args[:attributes].fetch(@attribute) do |a|
|
14
|
+
args[:attributes][a.to_s] || args[:attributes][a.to_sym]
|
15
|
+
end
|
16
|
+
|
13
17
|
return false if @suffix_list.empty?
|
14
18
|
|
15
19
|
@suffix_list.any? { |suffix| value.to_s.end_with? suffix }
|
16
20
|
end
|
21
|
+
|
22
|
+
def string_type?
|
23
|
+
true
|
24
|
+
end
|
17
25
|
end
|
18
26
|
end
|
@@ -1,19 +1,27 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class EqualToBooleanMatcher
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
MATCHER_TYPE = 'EQUAL_TO_BOOLEAN'.freeze
|
4
|
+
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute, boolean)
|
8
8
|
@attribute = attribute
|
9
9
|
@boolean = boolean
|
10
10
|
end
|
11
11
|
|
12
|
-
def match?(
|
12
|
+
def match?(args)
|
13
|
+
value = args[:attributes].fetch(@attribute) do |a|
|
14
|
+
args[:attributes][a.to_s] || args[:attributes][a.to_sym]
|
15
|
+
end
|
16
|
+
|
13
17
|
value = false if value.to_s.downcase == 'false'
|
14
18
|
value = true if value.to_s.downcase == 'true'
|
15
19
|
|
16
20
|
value == @boolean
|
17
21
|
end
|
22
|
+
|
23
|
+
def string_type?
|
24
|
+
false
|
25
|
+
end
|
18
26
|
end
|
19
27
|
end
|
@@ -1,22 +1,23 @@
|
|
1
1
|
module SplitIoClient
|
2
|
+
class EqualToMatcher
|
3
|
+
MATCHER_TYPE = 'EQUAL_TO'.freeze
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
attr_reader :matcher_type
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute_hash)
|
8
|
-
@matcher_type = "EQUAL_TO"
|
9
8
|
@attribute = attribute_hash[:attribute]
|
10
9
|
@data_type = attribute_hash[:data_type]
|
11
|
-
@value =
|
10
|
+
@value = formatted_value(attribute_hash[:value], true)
|
12
11
|
end
|
13
12
|
|
14
|
-
def match?(
|
15
|
-
|
16
|
-
if
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
def match?(args)
|
14
|
+
return false if !args.key?(:attributes) && !args.key?(:value)
|
15
|
+
return false if args.key?(:value) && args[:value].nil?
|
16
|
+
return false if args.key?(:attributes) && args[:attributes].nil?
|
17
|
+
|
18
|
+
value = formatted_value(args[:value] || args[:attributes][@attribute.to_sym])
|
19
|
+
|
20
|
+
value.is_a?(Integer) ? (value == @value) : false
|
20
21
|
end
|
21
22
|
|
22
23
|
def equals?(obj)
|
@@ -31,19 +32,23 @@ module SplitIoClient
|
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
35
|
+
def string_type?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
34
39
|
private
|
35
|
-
|
40
|
+
|
41
|
+
def formatted_value(value, sdk_data = false)
|
36
42
|
case @data_type
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
when 'NUMBER'
|
44
|
+
value
|
45
|
+
when 'DATETIME'
|
46
|
+
value = value / 1000 if sdk_data
|
47
|
+
|
48
|
+
SplitIoClient::Utilities.to_milis_zero_out_from_hour value
|
49
|
+
else
|
50
|
+
@logger.error('Invalid data type')
|
44
51
|
end
|
45
52
|
end
|
46
|
-
|
47
53
|
end
|
48
|
-
|
49
54
|
end
|
@@ -1,15 +1,19 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class EqualToSetMatcher < SetMatcher
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
MATCHER_TYPE = 'EQUAL_TO_SET'.freeze
|
4
|
+
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute, remote_array)
|
8
8
|
super(attribute, remote_array)
|
9
9
|
end
|
10
10
|
|
11
|
-
def match?(
|
12
|
-
local_set(
|
11
|
+
def match?(args)
|
12
|
+
local_set(args[:attributes], @attribute) == @remote_set
|
13
|
+
end
|
14
|
+
|
15
|
+
def string_type?
|
16
|
+
false
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
@@ -1,22 +1,23 @@
|
|
1
1
|
module SplitIoClient
|
2
|
+
class GreaterThanOrEqualToMatcher
|
3
|
+
MATCHER_TYPE = 'GREATER_THAN_OR_EQUAL_TO'.freeze
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
attr_reader :matcher_type
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute_hash)
|
8
|
-
@matcher_type = "GREATER_THAN_OR_EQUAL_TO"
|
9
8
|
@attribute = attribute_hash[:attribute]
|
10
9
|
@data_type = attribute_hash[:data_type]
|
11
|
-
@value =
|
10
|
+
@value = formatted_value(attribute_hash[:value], true)
|
12
11
|
end
|
13
12
|
|
14
|
-
def match?(
|
15
|
-
|
16
|
-
if
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
def match?(args)
|
14
|
+
return false if !args.key?(:attributes) && !args.key?(:value)
|
15
|
+
return false if args.key?(:value) && args[:value].nil?
|
16
|
+
return false if args.key?(:attributes) && args[:attributes].nil?
|
17
|
+
|
18
|
+
value = formatted_value(args[:value] || args[:attributes][@attribute.to_sym])
|
19
|
+
|
20
|
+
value.is_a?(Integer) ? (value >= @value) : false
|
20
21
|
end
|
21
22
|
|
22
23
|
def equals?(obj)
|
@@ -31,19 +32,22 @@ module SplitIoClient
|
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
35
|
+
def string_type?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
34
39
|
private
|
35
|
-
|
40
|
+
|
41
|
+
def formatted_value(value, sdk_data = false)
|
36
42
|
case @data_type
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
when 'NUMBER'
|
44
|
+
return value
|
45
|
+
when 'DATETIME'
|
46
|
+
value = value / 1000 if sdk_data # sdk returns already miliseconds, turning to seconds to do a correct zero_our
|
47
|
+
return SplitIoClient::Utilities.to_milis_zero_out_from_seconds(value)
|
48
|
+
else
|
49
|
+
@logger.error('Invalid data type')
|
44
50
|
end
|
45
51
|
end
|
46
|
-
|
47
52
|
end
|
48
|
-
|
49
53
|
end
|
@@ -1,22 +1,23 @@
|
|
1
1
|
module SplitIoClient
|
2
|
+
class LessThanOrEqualToMatcher
|
3
|
+
MATCHER_TYPE = 'LESS_THAN_OR_EQUAL_TO'.freeze
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
attr_reader :matcher_type
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute_hash)
|
8
|
-
@matcher_type = "LESS_THAN_OR_EQUAL_TO"
|
9
8
|
@attribute = attribute_hash[:attribute]
|
10
9
|
@data_type = attribute_hash[:data_type]
|
11
|
-
@value =
|
10
|
+
@value = formatted_value(attribute_hash[:value], true)
|
12
11
|
end
|
13
12
|
|
14
|
-
def match?(
|
15
|
-
|
16
|
-
if
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
def match?(args)
|
14
|
+
return false if !args.key?(:attributes) && !args.key?(:value)
|
15
|
+
return false if args.key?(:value) && args[:value].nil?
|
16
|
+
return false if args.key?(:attributes) && args[:attributes].nil?
|
17
|
+
|
18
|
+
value = formatted_value(args[:value] || args[:attributes][@attribute.to_sym])
|
19
|
+
|
20
|
+
value.is_a?(Integer) ? (value <= @value) : false
|
20
21
|
end
|
21
22
|
|
22
23
|
def equals?(obj)
|
@@ -31,19 +32,22 @@ module SplitIoClient
|
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
35
|
+
def string_type?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
34
39
|
private
|
35
|
-
|
40
|
+
|
41
|
+
def formatted_value(value, sdk_data = false)
|
36
42
|
case @data_type
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
when 'NUMBER'
|
44
|
+
return value
|
45
|
+
when 'DATETIME'
|
46
|
+
value = value / 1000 if sdk_data # sdk returns already miliseconds, turning to seconds to do a correct zero_our
|
47
|
+
return SplitIoClient::Utilities.to_milis_zero_out_from_seconds(value)
|
48
|
+
else
|
49
|
+
@logger.error('Invalid data type')
|
44
50
|
end
|
45
51
|
end
|
46
|
-
|
47
52
|
end
|
48
|
-
|
49
53
|
end
|
@@ -1,16 +1,24 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class MatchesStringMatcher
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
MATCHER_TYPE = 'MATCHES_STRING'.freeze
|
4
|
+
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute, regexp_string)
|
8
8
|
@attribute = attribute
|
9
9
|
@regexp_string = @regexp_string.is_a?(Regexp) ? regexp_string : Regexp.new(regexp_string)
|
10
10
|
end
|
11
11
|
|
12
|
-
def match?(
|
12
|
+
def match?(args)
|
13
|
+
value = args[:value] || args[:attributes].fetch(@attribute) do |a|
|
14
|
+
args[:attributes][a.to_s] || args[:attributes][a.to_sym]
|
15
|
+
end
|
16
|
+
|
13
17
|
(value =~ @regexp_string) != nil
|
14
18
|
end
|
19
|
+
|
20
|
+
def string_type?
|
21
|
+
true
|
22
|
+
end
|
15
23
|
end
|
16
24
|
end
|
@@ -1,16 +1,12 @@
|
|
1
1
|
module SplitIoClient
|
2
|
-
|
3
2
|
#
|
4
3
|
# class to implement the negation of a matcher
|
5
4
|
#
|
6
|
-
class NegationMatcher
|
7
|
-
|
8
|
-
@matcher = nil
|
5
|
+
class NegationMatcher
|
6
|
+
MATCHER_TYPE = 'NEGATION_MATCHER'.freeze
|
9
7
|
|
10
|
-
def initialize(matcher)
|
11
|
-
|
12
|
-
@matcher = matcher
|
13
|
-
end
|
8
|
+
def initialize(matcher = nil)
|
9
|
+
@matcher = matcher
|
14
10
|
end
|
15
11
|
|
16
12
|
#
|
@@ -19,8 +15,20 @@ module SplitIoClient
|
|
19
15
|
# @param key [string] key value to be matched
|
20
16
|
#
|
21
17
|
# @return [boolean] evaluation of the negation matcher
|
22
|
-
def match?(
|
23
|
-
!@matcher.match?(
|
18
|
+
def match?(args)
|
19
|
+
!@matcher.match?(args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond_to?(method)
|
23
|
+
@matcher.respond_to? method
|
24
|
+
end
|
25
|
+
|
26
|
+
def attribute
|
27
|
+
@matcher.attribute
|
28
|
+
end
|
29
|
+
|
30
|
+
def string_type?
|
31
|
+
@matcher.string_type?
|
24
32
|
end
|
25
33
|
|
26
34
|
#
|
@@ -46,9 +54,7 @@ module SplitIoClient
|
|
46
54
|
#
|
47
55
|
# @reutrn [string] string value of this matcher
|
48
56
|
def to_s
|
49
|
-
|
57
|
+
"not #{@matcher}"
|
50
58
|
end
|
51
|
-
|
52
59
|
end
|
53
|
-
|
54
60
|
end
|
@@ -1,19 +1,23 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class PartOfSetMatcher < SetMatcher
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
MATCHER_TYPE = 'PART_OF_SET'.freeze
|
4
|
+
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute, remote_array)
|
8
8
|
super(attribute, remote_array)
|
9
9
|
end
|
10
10
|
|
11
|
-
def match?(
|
12
|
-
@local_set = local_set(
|
11
|
+
def match?(args)
|
12
|
+
@local_set = local_set(args[:attributes], @attribute)
|
13
13
|
|
14
14
|
return false if @local_set.empty?
|
15
15
|
|
16
16
|
@local_set.subset? @remote_set
|
17
17
|
end
|
18
|
+
|
19
|
+
def string_type?
|
20
|
+
false
|
21
|
+
end
|
18
22
|
end
|
19
23
|
end
|
@@ -1,12 +1,16 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module SplitIoClient
|
2
4
|
class SetMatcher
|
3
5
|
protected
|
4
6
|
|
5
7
|
def initialize(attribute, remote_array)
|
8
|
+
@attribute = attribute
|
6
9
|
@remote_set = remote_array.to_set
|
7
10
|
end
|
8
11
|
|
9
|
-
def local_set(data)
|
12
|
+
def local_set(data, attribute)
|
13
|
+
data = data.fetch(attribute) { |a| data[a.to_s] || data[a.to_sym] }
|
10
14
|
# Allow user to pass individual elements as well
|
11
15
|
local_array = data.kind_of?(Array) ? data : [data]
|
12
16
|
|
@@ -1,18 +1,26 @@
|
|
1
1
|
module SplitIoClient
|
2
2
|
class StartsWithMatcher
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
MATCHER_TYPE = 'STARTS_WITH'.freeze
|
4
|
+
|
5
|
+
attr_reader :attribute
|
6
6
|
|
7
7
|
def initialize(attribute, prefix_list)
|
8
8
|
@attribute = attribute
|
9
9
|
@prefix_list = prefix_list
|
10
10
|
end
|
11
11
|
|
12
|
-
def match?(
|
12
|
+
def match?(args)
|
13
|
+
value = args[:value] || args[:attributes].fetch(@attribute) do |a|
|
14
|
+
args[:attributes][a.to_s] || args[:attributes][a.to_sym]
|
15
|
+
end
|
16
|
+
|
13
17
|
return false if @prefix_list.empty?
|
14
18
|
|
15
19
|
@prefix_list.any? { |prefix| value.to_s.start_with? prefix }
|
16
20
|
end
|
21
|
+
|
22
|
+
def string_type?
|
23
|
+
true
|
24
|
+
end
|
17
25
|
end
|
18
26
|
end
|
@@ -1,14 +1,11 @@
|
|
1
1
|
module SplitIoClient
|
2
|
-
|
3
2
|
#
|
4
3
|
# class to implement the user defined matcher
|
5
4
|
#
|
6
|
-
class UserDefinedSegmentMatcher
|
7
|
-
|
8
|
-
attr_reader :matcher_type
|
5
|
+
class UserDefinedSegmentMatcher
|
6
|
+
MATCHER_TYPE = 'IN_SEGMENT'.freeze
|
9
7
|
|
10
8
|
def initialize(segments_repository, segment_name)
|
11
|
-
@matcher_type = "IN_SEGMENT"
|
12
9
|
@segments_repository = segments_repository
|
13
10
|
@segment_name = segment_name
|
14
11
|
end
|
@@ -19,8 +16,8 @@ module SplitIoClient
|
|
19
16
|
# @param key [string] key value to be matched
|
20
17
|
#
|
21
18
|
# @return [boolean] evaluation of the key against the segment
|
22
|
-
def match?(
|
23
|
-
@segments_repository.in_segment?(@segment_name, matching_key)
|
19
|
+
def match?(args)
|
20
|
+
@segments_repository.in_segment?(@segment_name, args[:value] || args[:matching_key])
|
24
21
|
end
|
25
22
|
|
26
23
|
#
|
@@ -40,5 +37,9 @@ module SplitIoClient
|
|
40
37
|
false
|
41
38
|
end
|
42
39
|
end
|
40
|
+
|
41
|
+
def string_type?
|
42
|
+
false
|
43
|
+
end
|
43
44
|
end
|
44
45
|
end
|
@@ -1,33 +1,36 @@
|
|
1
1
|
module SplitIoClient
|
2
|
-
|
3
2
|
#
|
4
3
|
# class to implement the user defined matcher
|
5
4
|
#
|
6
5
|
class WhitelistMatcher < NoMethodError
|
6
|
+
MATCHER_TYPE = 'WHITELIST_MATCHER'
|
7
7
|
|
8
|
-
attr_reader :
|
9
|
-
|
10
|
-
# variable that contains the keys of the whitelist
|
11
|
-
@whitelist = []
|
8
|
+
attr_reader :attribute
|
12
9
|
|
13
10
|
def initialize(whitelist_data)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
@whitelist = case whitelist_data
|
12
|
+
when Array
|
13
|
+
whitelist_data
|
14
|
+
when Hash
|
15
|
+
@matcher_type = 'ATTR_WHITELIST'
|
18
16
|
@attribute = whitelist_data[:attribute]
|
19
|
-
|
17
|
+
|
18
|
+
whitelist_data[:value]
|
19
|
+
else
|
20
|
+
[]
|
20
21
|
end
|
21
22
|
end
|
22
23
|
|
23
|
-
def match?(
|
24
|
-
|
25
|
-
|
26
|
-
if !
|
27
|
-
|
28
|
-
|
24
|
+
def match?(args)
|
25
|
+
return @whitelist.include?(args[:value] || args[:matching_key]) unless @matcher_type == 'ATTR_WHITELIST'
|
26
|
+
|
27
|
+
return false if !args.key?(:attributes) && !args.key?(:value)
|
28
|
+
return false if args.key?(:value) && args[:value].nil?
|
29
|
+
return false if args.key?(:attributes) && args[:attributes].nil?
|
29
30
|
|
30
|
-
|
31
|
+
return @whitelist.include?(args[:value] || args[:attributes][@attribute.to_sym])
|
32
|
+
|
33
|
+
false
|
31
34
|
end
|
32
35
|
|
33
36
|
#
|
@@ -48,14 +51,16 @@ module SplitIoClient
|
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
54
|
+
def string_type?
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
51
58
|
#
|
52
59
|
# function to print string value for this matcher
|
53
60
|
#
|
54
61
|
# @reutrn [string] string value of this matcher
|
55
62
|
def to_s
|
56
|
-
|
63
|
+
"in segment #{@whitelist}"
|
57
64
|
end
|
58
|
-
|
59
65
|
end
|
60
|
-
|
61
66
|
end
|
@@ -58,23 +58,21 @@ module SplitIoClient
|
|
58
58
|
in_rollout = true
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
matcher = SplitIoClient::AttributeMatcher.new(nil, matcher_type(condition))
|
68
|
-
end
|
69
|
-
if matcher.match?(keys[:matching_key], keys[:bucketing_key], self, attributes)
|
70
|
-
key = keys[:bucketing_key] ? keys[:bucketing_key] : keys[:matching_key]
|
71
|
-
result = Splitter.get_treatment(key, split[:seed], condition.partitions, split[:algo])
|
61
|
+
condition_matched = matcher_type(condition).match?(
|
62
|
+
matching_key: keys[:matching_key],
|
63
|
+
bucketing_key: keys[:bucketing_key],
|
64
|
+
evaluator: self,
|
65
|
+
attributes: attributes
|
66
|
+
)
|
72
67
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
68
|
+
next unless condition_matched
|
69
|
+
|
70
|
+
result = Splitter.get_treatment(key, split[:seed], condition.partitions, split[:algo])
|
71
|
+
|
72
|
+
if result.nil?
|
73
|
+
return treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber])
|
74
|
+
else
|
75
|
+
return treatment_hash(c[:label], result, split[:changeNumber])
|
78
76
|
end
|
79
77
|
end
|
80
78
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: splitclient-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.3.0
|
4
|
+
version: 4.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Split Software
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -283,7 +283,6 @@ files:
|
|
283
283
|
- lib/splitclient-rb/engine/api/splits.rb
|
284
284
|
- lib/splitclient-rb/engine/evaluator/splitter.rb
|
285
285
|
- lib/splitclient-rb/engine/matchers/all_keys_matcher.rb
|
286
|
-
- lib/splitclient-rb/engine/matchers/attribute_matcher.rb
|
287
286
|
- lib/splitclient-rb/engine/matchers/between_matcher.rb
|
288
287
|
- lib/splitclient-rb/engine/matchers/combiners.rb
|
289
288
|
- lib/splitclient-rb/engine/matchers/combining_matcher.rb
|
@@ -346,9 +345,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
346
345
|
version: '0'
|
347
346
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
348
347
|
requirements:
|
349
|
-
- - "
|
348
|
+
- - ">="
|
350
349
|
- !ruby/object:Gem::Version
|
351
|
-
version:
|
350
|
+
version: '0'
|
352
351
|
requirements: []
|
353
352
|
rubyforge_project:
|
354
353
|
rubygems_version: 2.5.2
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module SplitIoClient
|
2
|
-
class AttributeMatcher
|
3
|
-
def initialize(attribute, matcher)
|
4
|
-
@attribute = attribute
|
5
|
-
@matcher = matcher
|
6
|
-
end
|
7
|
-
|
8
|
-
def match?(matching_key, bucketing_key = nil, evaluator = nil, attributes = {})
|
9
|
-
if @attribute != nil
|
10
|
-
return false unless attributes
|
11
|
-
|
12
|
-
value = attributes.fetch(@attribute) { |name| attributes[name.to_s] || attributes[name.to_sym] }
|
13
|
-
|
14
|
-
@matcher.match?(value, bucketing_key, nil, nil)
|
15
|
-
else
|
16
|
-
@matcher.match?(matching_key, bucketing_key, evaluator, attributes)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|