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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.txt +2 -1
  3. data/Detailed-README.md +8 -0
  4. data/lib/splitclient-rb.rb +0 -1
  5. data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +8 -10
  6. data/lib/splitclient-rb/engine/matchers/between_matcher.rb +27 -22
  7. data/lib/splitclient-rb/engine/matchers/combiners.rb +3 -7
  8. data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +33 -44
  9. data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +9 -5
  10. data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +9 -5
  11. data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +16 -4
  12. data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +9 -5
  13. data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +12 -4
  14. data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +12 -4
  15. data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +26 -21
  16. data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +9 -5
  17. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +25 -21
  18. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +25 -21
  19. data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +12 -4
  20. data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +19 -13
  21. data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +9 -5
  22. data/lib/splitclient-rb/engine/matchers/set_matcher.rb +5 -1
  23. data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +12 -4
  24. data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +8 -7
  25. data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +25 -20
  26. data/lib/splitclient-rb/engine/parser/condition.rb +1 -1
  27. data/lib/splitclient-rb/engine/parser/evaluator.rb +14 -16
  28. data/lib/splitclient-rb/version.rb +1 -1
  29. metadata +4 -5
  30. 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: b65d200504de0d0e0c33db504df5d40bde0a023b
4
- data.tar.gz: 8b483c1b5ba41fe2745a992e018ba14dbce4e3cb
3
+ metadata.gz: 1b62b60ce935de1b5345ec16107e6911321abf9c
4
+ data.tar.gz: 2ed5525256582608b165f9a42a056657fb6fc24c
5
5
  SHA512:
6
- metadata.gz: 7506af68ad2f63241782631576a73eaa845701dfc7dbbfc6274a9afde8eabf3cf3c830eae4e2b1ec8734ceee64f15fc6c57bed268662595b0e92f5760133f748
7
- data.tar.gz: 600ea370b948fcb2de1f1bbcf6f07b85cc39daa93f894675b62e0bce1b801a9c4b943fcf205b6a9324238323fc4d29e4898059d749f3564cb6913ecffb4f4770
6
+ metadata.gz: 837b99afc42609f08b51eee920c0b9492da45fb93e3ddfe187f0edc454e36077684e1bef54312a3a31e529d7fba2b10730179cc7e82a88becc4dc4e9d2435acf
7
+ data.tar.gz: cb785d0b3152892b86fa24a7b3369247ee4d17ffd2a4e9d01452bdb3d4e7b7eedb7648793ce8eb5c9e51d3ce2911256ce1da5e9bea7ad285d90f1a6bee913708
data/CHANGES.txt CHANGED
@@ -1,8 +1,9 @@
1
- 4.3.0 (Sept 14th, 2017)
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:
@@ -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 < NoMethodError
6
- attr_reader :matcher_type
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?(_matching_key, _bucketing_key, _evaluator, _attributes)
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
- # @returns [boolean] true if obj equals the matcher
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
- class BetweenMatcher < NoMethodError
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 = get_formatted_value attribute_hash[:start_value], true
12
- @end_value = get_formatted_value attribute_hash[:end_value], true
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?(value, _matching_key, _bucketing_key, _evaluator)
16
- matches = false
17
- if !value.nil?
18
- param_value = get_formatted_value(value)
19
- matches = param_value.is_a?(Integer) ? ((param_value >= @start_value) && (param_value <= @end_value)) : false
20
- end
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
- matches
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
- def get_formatted_value(value, is_sdk_data = false)
42
+
43
+ def formatted_value(value, sdk_data = false)
39
44
  case @data_type
40
- when "NUMBER"
41
- return value
42
- when "DATETIME"
43
- value = value/1000 if is_sdk_data
44
- return SplitIoClient::Utilities.to_milis_zero_out_from_seconds value
45
- else
46
- @logger.error('Invalid data type')
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
@@ -1,13 +1,9 @@
1
1
  module SplitIoClient
2
-
3
2
  #
4
3
  # class to represent combiner values
5
4
  #
6
- class Combiners < NoMethodError
7
-
5
+ class Combiners
8
6
  # available combiners of the sdk
9
- AND = 'AND'
10
-
7
+ AND = 'AND'.freeze
11
8
  end
12
-
13
- end
9
+ end
@@ -2,63 +2,59 @@ module SplitIoClient
2
2
  #
3
3
  # class to implement the combining matcher
4
4
  #
5
- class CombiningMatcher < NoMethodError
5
+ class CombiningMatcher
6
+ MATCHER_TYPE = 'COMBINING_MATCHER'.freeze
6
7
 
7
- #
8
- # list of matcher within the combiner
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 key [string] key value to be matched
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] match value for combiner delegates
32
- def match?(matching_key, bucketing_key, evaluator, attributes)
33
- if @matcher_list.empty?
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
- when Combiners::AND
39
- return and_eval(matching_key, bucketing_key, evaluator, attributes)
40
- else
41
- @logger.error('Invalid combiner type')
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 key [string] key value to be matched
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 and_eval(matching_key, bucketing_key, evaluator, attributes)
55
- @matcher_list.each do |delegate|
56
- matched = delegate.match?(matching_key, bucketing_key, evaluator, attributes)
57
-
58
- return false unless matched
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
- true
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
- result = ''
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
- def self.matcher_type
4
- 'CONTAINS_ALL'.freeze
5
- end
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?(data, bucketing_key, _evaluator, _attributes)
11
+ def match?(args)
12
12
  return false if @remote_set.empty?
13
13
 
14
- @remote_set.subset? local_set(data)
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
- def self.matcher_type
4
- 'CONTAINS_ANY'.freeze
5
- end
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?(data, bucketing_key, _evaluator, _attributes)
12
- local_set(data).intersect? @remote_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
- def self.matcher_type
4
- 'CONTAINS_WITH'.freeze
5
- end
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?(value, _matching_key, _bucketing_key, _evaluator)
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
- def self.matcher_type
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?(matching_key, bucketing_key, evaluator, attributes)
13
- @treatments.include? evaluator.call({ matching_key: matching_key, bucketing_key: bucketing_key }, @split, attributes)[:treatment]
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
- def self.matcher_type
4
- 'ENDS_WITH'.freeze
5
- end
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?(value, _matching_key, _bucketing_key, _evaluator)
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
- def self.matcher_type
4
- 'EQUAL_TO_BOOLEAN'.freeze
5
- end
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?(value, _matching_key, _bucketing_key, _evaluator)
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
- class EqualToMatcher < NoMethodError
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 = get_formatted_value attribute_hash[:value], true
10
+ @value = formatted_value(attribute_hash[:value], true)
12
11
  end
13
12
 
14
- def match?(value, _matching_key, _bucketing_key, _evaluator)
15
- matches = false
16
- if !value.nil?
17
- param_value = get_formatted_value(value)
18
- matches = param_value.is_a?(Integer) ? (param_value == @value) : false
19
- end
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
- def get_formatted_value(value, is_sdk_data = false)
40
+
41
+ def formatted_value(value, sdk_data = false)
36
42
  case @data_type
37
- when "NUMBER"
38
- return value
39
- when "DATETIME"
40
- value = value/1000 if is_sdk_data
41
- return SplitIoClient::Utilities.to_milis_zero_out_from_hour value
42
- else
43
- @logger.error('Invalid data type')
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
- def self.matcher_type
4
- 'EQUAL_TO_SET'.freeze
5
- end
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?(data, bucketing_key, _evaluator, _attributes)
12
- local_set(data) == @remote_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
- class GreaterThanOrEqualToMatcher < NoMethodError
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 = get_formatted_value attribute_hash[:value], true
10
+ @value = formatted_value(attribute_hash[:value], true)
12
11
  end
13
12
 
14
- def match?(value, _matching_key, _bucketing_key, _evaluator)
15
- matches = false
16
- if !value.nil?
17
- param_value = get_formatted_value(value)
18
- matches = param_value.is_a?(Integer) ? (param_value >= @value) : false
19
- end
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
- def get_formatted_value(value, is_sdk_data = false)
40
+
41
+ def formatted_value(value, sdk_data = false)
36
42
  case @data_type
37
- when "NUMBER"
38
- return value
39
- when "DATETIME"
40
- value = value/1000 if is_sdk_data # sdk returns already miliseconds, turning to seconds to do a correct zero_our
41
- return SplitIoClient::Utilities.to_milis_zero_out_from_seconds value
42
- else
43
- @logger.error('Invalid data type')
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
- class LessThanOrEqualToMatcher < NoMethodError
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 = get_formatted_value attribute_hash[:value], true
10
+ @value = formatted_value(attribute_hash[:value], true)
12
11
  end
13
12
 
14
- def match?(value, _matching_key, _bucketing_key, _evaluator)
15
- matches = false
16
- if !value.nil?
17
- param_value = get_formatted_value(value)
18
- matches = param_value.is_a?(Integer) ? (param_value <= @value) : false
19
- end
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
- def get_formatted_value(value, is_sdk_data = false)
40
+
41
+ def formatted_value(value, sdk_data = false)
36
42
  case @data_type
37
- when "NUMBER"
38
- return value
39
- when "DATETIME"
40
- value = value/1000 if is_sdk_data # sdk returns already miliseconds, turning to seconds to do a correct zero_our
41
- return SplitIoClient::Utilities.to_milis_zero_out_from_seconds value
42
- else
43
- @logger.error('Invalid data type')
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
- def self.matcher_type
4
- 'MATCHES_STRING'.freeze
5
- end
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?(value, _matching_key, _bucketing_key, _evaluator)
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 < NoMethodError
7
-
8
- @matcher = nil
5
+ class NegationMatcher
6
+ MATCHER_TYPE = 'NEGATION_MATCHER'.freeze
9
7
 
10
- def initialize(matcher)
11
- unless matcher.nil?
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?(matching_key, bucketing_key, evaluator, attributes)
23
- !@matcher.match?(matching_key, bucketing_key, evaluator, attributes)
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
- 'not ' + @matcher.to_s
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
- def self.matcher_type
4
- 'PART_OF_SET'.freeze
5
- end
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?(data, bucketing_key, _evaluator, _attributes)
12
- @local_set = local_set(data)
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
- def self.matcher_type
4
- 'STARTS_WITH'.freeze
5
- end
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?(value, _matching_key, _bucketing_key, _evaluator)
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 < NoMethodError
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?(matching_key, _bucketing_key, _evaluator, attributes)
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 :matcher_type
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
- if whitelist_data.instance_of? Array
15
- @whitelist = whitelist_data unless whitelist_data.nil?
16
- elsif whitelist_data.instance_of? Hash
17
- @matcher_type = "ATTR_WHITELIST"
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
- @whitelist = whitelist_data[:value] unless whitelist_data[:value].nil?
17
+
18
+ whitelist_data[:value]
19
+ else
20
+ []
20
21
  end
21
22
  end
22
23
 
23
- def match?(value, _matching_key, _bucketing_key, _evaluator)
24
- matches = false
25
-
26
- if !value.nil?
27
- matches = @whitelist.include?(value)
28
- end
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
- matches
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
- 'in segment ' + @whitelist.to_s
63
+ "in segment #{@whitelist}"
57
64
  end
58
-
59
65
  end
60
-
61
66
  end
@@ -17,7 +17,7 @@ module SplitIoClient
17
17
  end
18
18
 
19
19
  def create_condition_matcher(matchers)
20
- CombiningMatcher.new(combiner, matchers) unless combiner.nil?
20
+ CombiningMatcher.new(combiner, matchers) if combiner
21
21
  end
22
22
 
23
23
  #
@@ -58,23 +58,21 @@ module SplitIoClient
58
58
  in_rollout = true
59
59
  end
60
60
 
61
- begin
62
- matcher = SplitIoClient::AttributeMatcher.new(
63
- condition.data[:matcherGroup][:matchers][0][:keySelector][:attribute],
64
- matcher_type(condition)
65
- )
66
- rescue NoMethodError
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
- if result.nil?
74
- return treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber])
75
- else
76
- return treatment_hash(c[:label], result, split[:changeNumber])
77
- end
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
 
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '4.3.0.canary.2'
2
+ VERSION = '4.3.0'
3
3
  end
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.canary.2
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-09-18 00:00:00.000000000 Z
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: 1.3.1
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