splitclient-rb 4.5.1-java

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.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +45 -0
  3. data/CHANGES.txt +147 -0
  4. data/Detailed-README.md +571 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +13 -0
  7. data/NEWS +75 -0
  8. data/README.md +43 -0
  9. data/Rakefile +24 -0
  10. data/exe/splitio +96 -0
  11. data/ext/murmurhash/MurmurHash3.java +162 -0
  12. data/lib/murmurhash/base.rb +58 -0
  13. data/lib/murmurhash/murmurhash.jar +0 -0
  14. data/lib/murmurhash/murmurhash_mri.rb +3 -0
  15. data/lib/splitclient-rb.rb +90 -0
  16. data/lib/splitclient-rb/cache/adapters/memory_adapter.rb +12 -0
  17. data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +133 -0
  18. data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +44 -0
  19. data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +165 -0
  20. data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +30 -0
  21. data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +29 -0
  22. data/lib/splitclient-rb/cache/repositories/events_repository.rb +41 -0
  23. data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +49 -0
  24. data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +78 -0
  25. data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +21 -0
  26. data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +129 -0
  27. data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +98 -0
  28. data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +22 -0
  29. data/lib/splitclient-rb/cache/repositories/repository.rb +23 -0
  30. data/lib/splitclient-rb/cache/repositories/segments_repository.rb +82 -0
  31. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +106 -0
  32. data/lib/splitclient-rb/cache/routers/impression_router.rb +52 -0
  33. data/lib/splitclient-rb/cache/senders/events_sender.rb +47 -0
  34. data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +73 -0
  35. data/lib/splitclient-rb/cache/senders/impressions_sender.rb +67 -0
  36. data/lib/splitclient-rb/cache/senders/metrics_sender.rb +49 -0
  37. data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +48 -0
  38. data/lib/splitclient-rb/cache/stores/segment_store.rb +82 -0
  39. data/lib/splitclient-rb/cache/stores/split_store.rb +97 -0
  40. data/lib/splitclient-rb/clients/localhost_split_client.rb +92 -0
  41. data/lib/splitclient-rb/clients/split_client.rb +214 -0
  42. data/lib/splitclient-rb/engine/api/client.rb +74 -0
  43. data/lib/splitclient-rb/engine/api/events.rb +48 -0
  44. data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +55 -0
  45. data/lib/splitclient-rb/engine/api/impressions.rb +42 -0
  46. data/lib/splitclient-rb/engine/api/metrics.rb +61 -0
  47. data/lib/splitclient-rb/engine/api/segments.rb +62 -0
  48. data/lib/splitclient-rb/engine/api/splits.rb +60 -0
  49. data/lib/splitclient-rb/engine/evaluator/splitter.rb +123 -0
  50. data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +46 -0
  51. data/lib/splitclient-rb/engine/matchers/between_matcher.rb +56 -0
  52. data/lib/splitclient-rb/engine/matchers/combiners.rb +9 -0
  53. data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +86 -0
  54. data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +21 -0
  55. data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +19 -0
  56. data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +30 -0
  57. data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +20 -0
  58. data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +26 -0
  59. data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +27 -0
  60. data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +54 -0
  61. data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +19 -0
  62. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +53 -0
  63. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +53 -0
  64. data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +24 -0
  65. data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +60 -0
  66. data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +23 -0
  67. data/lib/splitclient-rb/engine/matchers/set_matcher.rb +20 -0
  68. data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +26 -0
  69. data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +45 -0
  70. data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +66 -0
  71. data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +128 -0
  72. data/lib/splitclient-rb/engine/metrics/metrics.rb +83 -0
  73. data/lib/splitclient-rb/engine/models/label.rb +8 -0
  74. data/lib/splitclient-rb/engine/models/split.rb +17 -0
  75. data/lib/splitclient-rb/engine/models/treatment.rb +3 -0
  76. data/lib/splitclient-rb/engine/parser/condition.rb +210 -0
  77. data/lib/splitclient-rb/engine/parser/evaluator.rb +118 -0
  78. data/lib/splitclient-rb/engine/parser/partition.rb +35 -0
  79. data/lib/splitclient-rb/engine/parser/split_adapter.rb +88 -0
  80. data/lib/splitclient-rb/exceptions/impressions_shutdown_exception.rb +4 -0
  81. data/lib/splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception.rb +4 -0
  82. data/lib/splitclient-rb/localhost_split_factory.rb +13 -0
  83. data/lib/splitclient-rb/localhost_utils.rb +36 -0
  84. data/lib/splitclient-rb/managers/localhost_split_manager.rb +45 -0
  85. data/lib/splitclient-rb/managers/split_manager.rb +77 -0
  86. data/lib/splitclient-rb/split_config.rb +391 -0
  87. data/lib/splitclient-rb/split_factory.rb +35 -0
  88. data/lib/splitclient-rb/split_factory_builder.rb +16 -0
  89. data/lib/splitclient-rb/utilitites.rb +41 -0
  90. data/lib/splitclient-rb/version.rb +3 -0
  91. data/splitclient-rb.gemspec +50 -0
  92. data/splitio.yml.example +7 -0
  93. data/tasks/benchmark_get_treatment.rake +43 -0
  94. data/tasks/irb.rake +4 -0
  95. data/tasks/rspec.rake +3 -0
  96. metadata +321 -0
@@ -0,0 +1,53 @@
1
+ module SplitIoClient
2
+ class LessThanOrEqualToMatcher
3
+ MATCHER_TYPE = 'LESS_THAN_OR_EQUAL_TO'.freeze
4
+
5
+ attr_reader :attribute
6
+
7
+ def initialize(attribute_hash)
8
+ @attribute = attribute_hash[:attribute]
9
+ @data_type = attribute_hash[:data_type]
10
+ @value = formatted_value(attribute_hash[:value], true)
11
+ end
12
+
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
21
+ end
22
+
23
+ def equals?(obj)
24
+ if obj.nil?
25
+ false
26
+ elsif !obj.instance_of?(LessThanOrEqualToMatcher)
27
+ false
28
+ elsif self.equal?(obj)
29
+ true
30
+ else
31
+ false
32
+ end
33
+ end
34
+
35
+ def string_type?
36
+ false
37
+ end
38
+
39
+ private
40
+
41
+ def formatted_value(value, sdk_data = false)
42
+ case @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')
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,24 @@
1
+ module SplitIoClient
2
+ class MatchesStringMatcher
3
+ MATCHER_TYPE = 'MATCHES_STRING'.freeze
4
+
5
+ attr_reader :attribute
6
+
7
+ def initialize(attribute, regexp_string)
8
+ @attribute = attribute
9
+ @regexp_string = @regexp_string.is_a?(Regexp) ? regexp_string : Regexp.new(regexp_string)
10
+ end
11
+
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
+
17
+ (value =~ @regexp_string) != nil
18
+ end
19
+
20
+ def string_type?
21
+ true
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,60 @@
1
+ module SplitIoClient
2
+ #
3
+ # class to implement the negation of a matcher
4
+ #
5
+ class NegationMatcher
6
+ MATCHER_TYPE = 'NEGATION_MATCHER'.freeze
7
+
8
+ def initialize(matcher = nil)
9
+ @matcher = matcher
10
+ end
11
+
12
+ #
13
+ # evaluates if the key matches the negation of the matcher
14
+ #
15
+ # @param key [string] key value to be matched
16
+ #
17
+ # @return [boolean] evaluation of the negation matcher
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?
32
+ end
33
+
34
+ #
35
+ # evaluates if the given object equals the matcher
36
+ #
37
+ # @param obj [object] object to be evaluated
38
+ #
39
+ # @returns [boolean] true if obj equals the matcher
40
+ def equals?(obj)
41
+ if obj.nil?
42
+ false
43
+ elsif !obj.instance_of?(NegationMatcher)
44
+ false
45
+ elsif self.equal?(obj)
46
+ true
47
+ else
48
+ false
49
+ end
50
+ end
51
+
52
+ #
53
+ # function to print string value for this matcher
54
+ #
55
+ # @reutrn [string] string value of this matcher
56
+ def to_s
57
+ "not #{@matcher}"
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,23 @@
1
+ module SplitIoClient
2
+ class PartOfSetMatcher < SetMatcher
3
+ MATCHER_TYPE = 'PART_OF_SET'.freeze
4
+
5
+ attr_reader :attribute
6
+
7
+ def initialize(attribute, remote_array)
8
+ super(attribute, remote_array)
9
+ end
10
+
11
+ def match?(args)
12
+ @local_set = local_set(args[:attributes], @attribute)
13
+
14
+ return false if @local_set.empty?
15
+
16
+ @local_set.subset? @remote_set
17
+ end
18
+
19
+ def string_type?
20
+ false
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ require 'set'
2
+
3
+ module SplitIoClient
4
+ class SetMatcher
5
+ protected
6
+
7
+ def initialize(attribute, remote_array)
8
+ @attribute = attribute
9
+ @remote_set = remote_array.to_set
10
+ end
11
+
12
+ def local_set(data, attribute)
13
+ data = data.fetch(attribute) { |a| data[a.to_s] || data[a.to_sym] }
14
+ # Allow user to pass individual elements as well
15
+ local_array = data.kind_of?(Array) ? data : [data]
16
+
17
+ local_array.to_set
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ module SplitIoClient
2
+ class StartsWithMatcher
3
+ MATCHER_TYPE = 'STARTS_WITH'.freeze
4
+
5
+ attr_reader :attribute
6
+
7
+ def initialize(attribute, prefix_list)
8
+ @attribute = attribute
9
+ @prefix_list = prefix_list
10
+ end
11
+
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
+
17
+ return false if @prefix_list.empty?
18
+
19
+ @prefix_list.any? { |prefix| value.to_s.start_with? prefix }
20
+ end
21
+
22
+ def string_type?
23
+ true
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,45 @@
1
+ module SplitIoClient
2
+ #
3
+ # class to implement the user defined matcher
4
+ #
5
+ class UserDefinedSegmentMatcher
6
+ MATCHER_TYPE = 'IN_SEGMENT'.freeze
7
+
8
+ def initialize(segments_repository, segment_name)
9
+ @segments_repository = segments_repository
10
+ @segment_name = segment_name
11
+ end
12
+
13
+ #
14
+ # evaluates if the key matches the matcher
15
+ #
16
+ # @param key [string] key value to be matched
17
+ #
18
+ # @return [boolean] evaluation of the key against the segment
19
+ def match?(args)
20
+ @segments_repository.in_segment?(@segment_name, args[:value] || args[:matching_key])
21
+ end
22
+
23
+ #
24
+ # evaluates if the given object equals the matcher
25
+ #
26
+ # @param obj [object] object to be evaluated
27
+ #
28
+ # @returns [boolean] true if obj equals the matcher
29
+ def equals?(obj)
30
+ if obj.nil?
31
+ false
32
+ elsif !obj.instance_of?(UserDefinedSegmentMatcher)
33
+ false
34
+ elsif self.equal?(obj)
35
+ true
36
+ else
37
+ false
38
+ end
39
+ end
40
+
41
+ def string_type?
42
+ false
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,66 @@
1
+ module SplitIoClient
2
+ #
3
+ # class to implement the user defined matcher
4
+ #
5
+ class WhitelistMatcher < NoMethodError
6
+ MATCHER_TYPE = 'WHITELIST_MATCHER'
7
+
8
+ attr_reader :attribute
9
+
10
+ def initialize(whitelist_data)
11
+ @whitelist = case whitelist_data
12
+ when Array
13
+ whitelist_data
14
+ when Hash
15
+ @matcher_type = 'ATTR_WHITELIST'
16
+ @attribute = whitelist_data[:attribute]
17
+
18
+ whitelist_data[:value]
19
+ else
20
+ []
21
+ end
22
+ end
23
+
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?
30
+
31
+ return @whitelist.include?(args[:value] || args[:attributes][@attribute.to_sym])
32
+
33
+ false
34
+ end
35
+
36
+ #
37
+ # evaluates if the given object equals the matcher
38
+ #
39
+ # @param obj [object] object to be evaluated
40
+ #
41
+ # @returns [boolean] true if obj equals the matcher
42
+ def equals?(obj)
43
+ if obj.nil?
44
+ false
45
+ elsif !obj.instance_of?(WhitelistMatcher)
46
+ false
47
+ elsif self.equal?(obj)
48
+ true
49
+ else
50
+ false
51
+ end
52
+ end
53
+
54
+ def string_type?
55
+ true
56
+ end
57
+
58
+ #
59
+ # function to print string value for this matcher
60
+ #
61
+ # @reutrn [string] string value of this matcher
62
+ def to_s
63
+ "in segment #{@whitelist}"
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,128 @@
1
+ module SplitIoClient
2
+
3
+ #
4
+ # Tracks latencies pero bucket of time.
5
+ # Each bucket represent a latency greater than the one before
6
+ # and each number within each bucket is a number of calls in the range.
7
+ #
8
+ # (1) 1.00
9
+ # (2) 1.50
10
+ # (3) 2.25
11
+ # (4) 3.38
12
+ # (5) 5.06
13
+ # (6) 7.59
14
+ # (7) 11.39
15
+ # (8) 17.09
16
+ # (9) 25.63
17
+ # (10) 38.44
18
+ # (11) 57.67
19
+ # (12) 86.50
20
+ # (13) 129.75
21
+ # (14) 194.62
22
+ # (15) 291.93
23
+ # (16) 437.89
24
+ # (17) 656.84
25
+ # (18) 985.26
26
+ # (19) 1,477.89
27
+ # (20) 2,216.84
28
+ # (21) 3,325.26
29
+ # (22) 4,987.89
30
+ # (23) 7,481.83
31
+ #
32
+ # Created by fvitale on 2/17/16 based on java implementation by patricioe.
33
+ #
34
+
35
+ class BinarySearchLatencyTracker < NoMethodError
36
+
37
+ BUCKETS = [ 1000, 1500, 2250, 3375, 5063,
38
+ 7594, 11391, 17086, 25629, 38443,
39
+ 57665, 86498, 129746, 194620, 291929,
40
+ 437894, 656841, 985261, 1477892, 2216838,
41
+ 3325257, 4987885, 7481828 ].freeze
42
+
43
+ MAX_LATENCY = 7481828
44
+
45
+ attr_accessor :latencies
46
+
47
+ def initialize
48
+ @latencies = Array.new(BUCKETS.length, 0)
49
+ end
50
+
51
+ #
52
+ # Increment the internal counter for the bucket this latency falls into.
53
+ # @param millis
54
+ #
55
+ def add_latency_millis(millis, return_index = false)
56
+ index = find_bucket_index(millis * 1000)
57
+
58
+ return index if return_index
59
+
60
+ @latencies[index] += 1
61
+ @latencies
62
+ end
63
+
64
+ # Increment the internal counter for the bucket this latency falls into.
65
+ # @param micros
66
+ def add_latency_micros(micros, return_index = false)
67
+ index = find_bucket_index(micros)
68
+
69
+ return index if return_index
70
+
71
+ @latencies[index] += 1
72
+ @latencies
73
+ end
74
+
75
+ # Returns the list of latencies buckets as an array.
76
+ #
77
+ #
78
+ # @return the list of latencies buckets as an array.
79
+ def get_latencies
80
+ @latencies
81
+ end
82
+
83
+ def get_latency(index)
84
+ return @latencies[index]
85
+ end
86
+
87
+ def clear
88
+ @latencies = Array.new(BUCKETS.length, 0)
89
+ end
90
+
91
+ #
92
+ # Returns the counts in the bucket this latency falls into.
93
+ # The latencies will not be updated.
94
+ # @param latency
95
+ # @return the bucket content for the latency.
96
+ #
97
+ def get_bucket_for_latency_millis(latency)
98
+ return @latencies[find_bucket_index(latency * 1000)]
99
+ end
100
+
101
+ #
102
+ # Returns the counts in the bucket this latency falls into.
103
+ # The latencies will not be updated.
104
+ # @param latency
105
+ # @return the bucket content for the latency.
106
+ #
107
+ def get_bucket_for_latency_micros(latency)
108
+ return @latencies[find_bucket_index(latency)]
109
+ end
110
+
111
+ private
112
+
113
+ def find_bucket_index(micros)
114
+ if (micros > MAX_LATENCY) then
115
+ return BUCKETS.length - 1
116
+ end
117
+
118
+ if (micros < 1500) then
119
+ return 0
120
+ end
121
+
122
+ index = BUCKETS.find_index(BUCKETS.bsearch {|x| x >= micros })
123
+
124
+ return index
125
+ end
126
+
127
+ end
128
+ end