splitclient-rb 6.3.0 → 8.11.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.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/pull_request_template.md +9 -0
  4. data/.github/workflows/ci.yml +90 -0
  5. data/.github/workflows/update-license-year.yml +45 -0
  6. data/.gitignore +4 -0
  7. data/.rubocop.yml +46 -3
  8. data/CHANGES.txt +158 -11
  9. data/CONTRIBUTORS-GUIDE.md +49 -0
  10. data/LICENSE +169 -13
  11. data/NOTICE.txt +5 -0
  12. data/README.md +67 -27
  13. data/Rakefile +1 -8
  14. data/ext/murmurhash/3_x64_128.c +117 -0
  15. data/ext/murmurhash/murmurhash.c +5 -1
  16. data/lib/murmurhash/murmurhash.jar +0 -0
  17. data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +3 -3
  18. data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +4 -0
  19. data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +7 -0
  20. data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +12 -4
  21. data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +83 -0
  22. data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +70 -0
  23. data/lib/splitclient-rb/cache/filter/bloom_filter.rb +67 -0
  24. data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
  25. data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
  26. data/lib/splitclient-rb/cache/hashers/impression_hasher.rb +34 -0
  27. data/lib/splitclient-rb/cache/observers/impression_observer.rb +22 -0
  28. data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
  29. data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +26 -14
  30. data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +9 -14
  31. data/lib/splitclient-rb/cache/repositories/events_repository.rb +31 -10
  32. data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
  33. data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
  34. data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +22 -23
  35. data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +15 -22
  36. data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +6 -31
  37. data/lib/splitclient-rb/cache/repositories/repository.rb +6 -5
  38. data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
  39. data/lib/splitclient-rb/cache/repositories/segments_repository.rb +46 -6
  40. data/lib/splitclient-rb/cache/repositories/splits_repository.rb +232 -43
  41. data/lib/splitclient-rb/cache/routers/impression_router.rb +24 -22
  42. data/lib/splitclient-rb/cache/senders/events_sender.rb +12 -29
  43. data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
  44. data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +69 -0
  45. data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +43 -0
  46. data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +27 -13
  47. data/lib/splitclient-rb/cache/senders/impressions_sender.rb +11 -25
  48. data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
  49. data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +47 -0
  50. data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +95 -0
  51. data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +110 -0
  52. data/lib/splitclient-rb/cache/stores/store_utils.rb +13 -0
  53. data/lib/splitclient-rb/clients/split_client.rb +385 -138
  54. data/lib/splitclient-rb/constants.rb +16 -0
  55. data/lib/splitclient-rb/engine/api/client.rb +38 -43
  56. data/lib/splitclient-rb/engine/api/events.rb +19 -11
  57. data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +1 -0
  58. data/lib/splitclient-rb/engine/api/impressions.rb +49 -14
  59. data/lib/splitclient-rb/engine/api/segments.rb +31 -24
  60. data/lib/splitclient-rb/engine/api/splits.rb +108 -33
  61. data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
  62. data/lib/splitclient-rb/engine/auth_api_client.rb +96 -0
  63. data/lib/splitclient-rb/engine/back_off.rb +26 -0
  64. data/lib/splitclient-rb/engine/common/impressions_counter.rb +45 -0
  65. data/lib/splitclient-rb/engine/common/impressions_manager.rb +165 -0
  66. data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
  67. data/lib/splitclient-rb/engine/events/events_delivery.rb +20 -0
  68. data/lib/splitclient-rb/engine/events/events_manager.rb +194 -0
  69. data/lib/splitclient-rb/engine/events/events_manager_config.rb +96 -0
  70. data/lib/splitclient-rb/engine/events/events_task.rb +50 -0
  71. data/lib/splitclient-rb/engine/events/noop_events_queue.rb +13 -0
  72. data/lib/splitclient-rb/engine/fallback_treatment_calculator.rb +48 -0
  73. data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
  74. data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +144 -0
  75. data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +1 -1
  76. data/lib/splitclient-rb/engine/matchers/between_matcher.rb +7 -5
  77. data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
  78. data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +10 -8
  79. data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +2 -6
  80. data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +1 -5
  81. data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +7 -5
  82. data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +6 -5
  83. data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +5 -4
  84. data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +3 -2
  85. data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +6 -4
  86. data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
  87. data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +1 -5
  88. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +6 -4
  89. data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher.rb +28 -0
  90. data/lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb +36 -0
  91. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +6 -4
  92. data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
  93. data/lib/splitclient-rb/engine/matchers/matcher.rb +22 -0
  94. data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +3 -2
  95. data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +3 -2
  96. data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +2 -6
  97. data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
  98. data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +78 -0
  99. data/lib/splitclient-rb/engine/matchers/semver.rb +201 -0
  100. data/lib/splitclient-rb/engine/matchers/set_matcher.rb +2 -1
  101. data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +4 -3
  102. data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +3 -2
  103. data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +7 -5
  104. data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +3 -65
  105. data/lib/splitclient-rb/engine/models/evaluation_options.rb +9 -0
  106. data/lib/splitclient-rb/engine/models/event_active_subscriptions.rb +14 -0
  107. data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -0
  108. data/lib/splitclient-rb/engine/models/fallback_treatment.rb +11 -0
  109. data/lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb +36 -0
  110. data/lib/splitclient-rb/engine/models/label.rb +3 -0
  111. data/lib/splitclient-rb/engine/models/sdk_event.rb +4 -0
  112. data/lib/splitclient-rb/engine/models/sdk_event_type.rb +4 -0
  113. data/lib/splitclient-rb/engine/models/sdk_internal_event.rb +8 -0
  114. data/lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb +14 -0
  115. data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
  116. data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
  117. data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
  118. data/lib/splitclient-rb/engine/parser/condition.rb +81 -20
  119. data/lib/splitclient-rb/engine/parser/evaluator.rb +40 -51
  120. data/lib/splitclient-rb/engine/push_manager.rb +66 -0
  121. data/lib/splitclient-rb/engine/status_manager.rb +39 -0
  122. data/lib/splitclient-rb/engine/sync_manager.rb +180 -0
  123. data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
  124. data/lib/splitclient-rb/exceptions.rb +20 -1
  125. data/lib/splitclient-rb/helpers/decryption_helper.rb +25 -0
  126. data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
  127. data/lib/splitclient-rb/helpers/repository_helper.rb +61 -0
  128. data/lib/splitclient-rb/helpers/thread_helper.rb +24 -0
  129. data/lib/splitclient-rb/helpers/util.rb +26 -0
  130. data/lib/splitclient-rb/managers/split_manager.rb +58 -20
  131. data/lib/splitclient-rb/spec.rb +9 -0
  132. data/lib/splitclient-rb/split_config.rb +336 -54
  133. data/lib/splitclient-rb/split_factory.rb +219 -33
  134. data/lib/splitclient-rb/split_factory_builder.rb +1 -22
  135. data/lib/splitclient-rb/split_factory_registry.rb +63 -0
  136. data/lib/splitclient-rb/split_logger.rb +9 -10
  137. data/lib/splitclient-rb/sse/event_source/client.rb +263 -0
  138. data/lib/splitclient-rb/sse/event_source/event_parser.rb +65 -0
  139. data/lib/splitclient-rb/sse/event_source/event_types.rb +15 -0
  140. data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
  141. data/lib/splitclient-rb/sse/notification_manager_keeper.rb +84 -0
  142. data/lib/splitclient-rb/sse/notification_processor.rb +48 -0
  143. data/lib/splitclient-rb/sse/sse_handler.rb +44 -0
  144. data/lib/splitclient-rb/sse/workers/segments_worker.rb +62 -0
  145. data/lib/splitclient-rb/sse/workers/splits_worker.rb +149 -0
  146. data/lib/splitclient-rb/telemetry/domain/constants.rb +48 -0
  147. data/lib/splitclient-rb/telemetry/domain/structs.rb +35 -0
  148. data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
  149. data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
  150. data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
  151. data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
  152. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
  153. data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
  154. data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
  155. data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
  156. data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +119 -0
  157. data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +87 -0
  158. data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +213 -0
  159. data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
  160. data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
  161. data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +27 -0
  162. data/lib/splitclient-rb/telemetry/runtime_consumer.rb +25 -0
  163. data/lib/splitclient-rb/telemetry/runtime_producer.rb +25 -0
  164. data/lib/splitclient-rb/telemetry/storages/memory.rb +159 -0
  165. data/lib/splitclient-rb/telemetry/sync_task.rb +36 -0
  166. data/lib/splitclient-rb/telemetry/synchronizer.rb +33 -0
  167. data/lib/splitclient-rb/utilitites.rb +8 -0
  168. data/lib/splitclient-rb/validators.rb +142 -38
  169. data/lib/splitclient-rb/version.rb +1 -1
  170. data/lib/splitclient-rb.rb +101 -16
  171. data/sonar-project.properties +6 -0
  172. data/splitclient-rb.gemspec +28 -23
  173. metadata +262 -82
  174. data/.travis.yml +0 -11
  175. data/Appraisals +0 -10
  176. data/Detailed-README.md +0 -588
  177. data/NEWS +0 -141
  178. data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +0 -127
  179. data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +0 -96
  180. data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +0 -21
  181. data/lib/splitclient-rb/cache/senders/metrics_sender.rb +0 -56
  182. data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +0 -46
  183. data/lib/splitclient-rb/cache/stores/segment_store.rb +0 -81
  184. data/lib/splitclient-rb/cache/stores/split_store.rb +0 -102
  185. data/lib/splitclient-rb/clients/localhost_split_client.rb +0 -183
  186. data/lib/splitclient-rb/engine/api/faraday_adapter/patched_net_http_persistent.rb +0 -46
  187. data/lib/splitclient-rb/engine/api/metrics.rb +0 -60
  188. data/lib/splitclient-rb/engine/metrics/metrics.rb +0 -80
  189. data/lib/splitclient-rb/engine/parser/split_adapter.rb +0 -81
  190. data/lib/splitclient-rb/localhost_split_factory.rb +0 -13
  191. data/lib/splitclient-rb/localhost_utils.rb +0 -59
  192. data/lib/splitclient-rb/managers/localhost_split_manager.rb +0 -60
@@ -42,75 +42,13 @@ module SplitIoClient
42
42
 
43
43
  MAX_LATENCY = 7481828
44
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)]
45
+ def self.get_bucket(latency)
46
+ return find_bucket_index(latency * 1000)
109
47
  end
110
48
 
111
49
  private
112
50
 
113
- def find_bucket_index(micros)
51
+ def self.find_bucket_index(micros)
114
52
  if (micros > MAX_LATENCY) then
115
53
  return BUCKETS.length - 1
116
54
  end
@@ -0,0 +1,9 @@
1
+ module SplitIoClient::Engine::Models
2
+ class EvaluationOptions
3
+ attr_accessor :properties
4
+
5
+ def initialize(properties)
6
+ @properties = properties
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: false
2
+
3
+ module SplitIoClient
4
+ module Engine::Models
5
+ class EventActiveSubscriptions
6
+ attr_accessor :triggered, :handler
7
+
8
+ def initialize(triggered, handler)
9
+ @triggered = triggered
10
+ @handler = handler
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module SplitIoClient::Engine::Models
2
+ class EventsMetadata
3
+ attr_accessor :type, :names
4
+
5
+ def initialize(type, names=nil)
6
+ @type = type
7
+ @names = names
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module SplitIoClient::Engine::Models
2
+ class FallbackTreatment
3
+ attr_accessor :treatment, :config, :label
4
+
5
+ def initialize(treatment, config=nil, label=nil)
6
+ @treatment = treatment
7
+ @config = config
8
+ @label = label
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,36 @@
1
+ module SplitIoClient::Engine::Models
2
+ class FallbackTreatmentsConfiguration
3
+ attr_accessor :global_fallback_treatment, :by_flag_fallback_treatment
4
+
5
+ def initialize(global_fallback_treatment=nil, by_flag_fallback_treatment=nil)
6
+ @global_fallback_treatment = build_global_fallback_treatment(global_fallback_treatment)
7
+ @by_flag_fallback_treatment = build_by_flag_fallback_treatment(by_flag_fallback_treatment)
8
+ end
9
+
10
+ private
11
+
12
+ def build_global_fallback_treatment(global_fallback_treatment)
13
+ if global_fallback_treatment.is_a? String
14
+ return FallbackTreatment.new(global_fallback_treatment)
15
+ end
16
+
17
+ global_fallback_treatment
18
+ end
19
+
20
+ def build_by_flag_fallback_treatment(by_flag_fallback_treatment)
21
+ return nil unless by_flag_fallback_treatment.is_a?(Hash)
22
+ processed_by_flag_fallback_treatment = Hash.new
23
+
24
+ by_flag_fallback_treatment.each do |key, value|
25
+ if value.is_a? String
26
+ processed_by_flag_fallback_treatment[key] = FallbackTreatment.new(value)
27
+ next
28
+ end
29
+
30
+ processed_by_flag_fallback_treatment[key] = value
31
+ end
32
+
33
+ processed_by_flag_fallback_treatment
34
+ end
35
+ end
36
+ end
@@ -4,4 +4,7 @@ class SplitIoClient::Engine::Models::Label
4
4
  EXCEPTION = 'exception'.freeze
5
5
  KILLED = 'killed'.freeze
6
6
  NOT_IN_SPLIT = 'not in split'.freeze
7
+ NOT_READY = 'not ready'.freeze
8
+ NOT_FOUND = 'definition not found'.freeze
9
+ PREREQUISITES_NOT_MET = 'prerequisites not met'.freeze
7
10
  end
@@ -0,0 +1,4 @@
1
+ class SplitIoClient::Engine::Models::SdkEvent
2
+ SDK_READY = 'SDK_READY'
3
+ SDK_UPDATE = 'SDK_UPDATE'
4
+ end
@@ -0,0 +1,4 @@
1
+ class SplitIoClient::Engine::Models::SdkEventType
2
+ FLAG_UPDATE = 'FLAG_UPDATE'
3
+ SEGMENTS_UPDATE = 'SEGMENTS_UPDATE'
4
+ end
@@ -0,0 +1,8 @@
1
+ class SplitIoClient::Engine::Models::SdkInternalEvent
2
+ SDK_READY = 'SDK_READY'
3
+ FLAGS_UPDATED = 'FLAGS_UPDATED'
4
+ FLAG_KILLED_NOTIFICATION = 'FLAG_KILLED_NOTIFICATION'
5
+ SEGMENTS_UPDATED = 'SEGMENTS_UPDATED'
6
+ RB_SEGMENTS_UPDATED = 'RB_SEGMENTS_UPDATED'
7
+ LARGE_SEGMENTS_UPDATED = 'LARGE_SEGMENTS_UPDATED'
8
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: false
2
+
3
+ module SplitIoClient
4
+ module Engine::Models
5
+ class SdkInternalEventNotification
6
+ attr_reader :internal_event, :metadata
7
+
8
+ def initialize(internal_event, metadata)
9
+ @internal_event = internal_event
10
+ @metadata = metadata
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ class SplitIoClient::Engine::Models::SegmentType
2
+ STANDARD = 'standard'
3
+ RULE_BASED_SEGMENT = 'rule-based'
4
+ end
@@ -0,0 +1,19 @@
1
+ module SplitIoClient
2
+ module Engine
3
+ module Models
4
+ class SplitHttpResponse
5
+ attr_accessor :status, :body
6
+
7
+ def initialize(status, body, success)
8
+ @status = status
9
+ @body = body
10
+ @success = success
11
+ end
12
+
13
+ def success?
14
+ @success
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: false
2
+
3
+ module SplitIoClient
4
+ module Engine::Models
5
+ class ValidSdkEvent
6
+ attr_reader :sdk_event, :valid
7
+
8
+ def initialize(sdk_event, valid)
9
+ @sdk_event = sdk_event
10
+ @valid = valid
11
+ end
12
+ end
13
+ end
14
+ end
@@ -11,13 +11,14 @@ module SplitIoClient
11
11
  # @returns [object] condition values
12
12
  attr_accessor :data
13
13
 
14
- def initialize(condition)
14
+ def initialize(condition, config)
15
15
  @data = condition
16
16
  @partitions = set_partitions
17
+ @config = config
17
18
  end
18
19
 
19
20
  def create_condition_matcher(matchers)
20
- CombiningMatcher.new(combiner, matchers) if combiner
21
+ CombiningMatcher.new(@config.split_logger, combiner, matchers) if combiner
21
22
  end
22
23
 
23
24
  #
@@ -45,11 +46,11 @@ module SplitIoClient
45
46
  end
46
47
 
47
48
  def negation_matcher(matcher)
48
- NegationMatcher.new(matcher)
49
+ NegationMatcher.new(@config.split_logger, matcher)
49
50
  end
50
51
 
51
52
  def matcher_all_keys(_params)
52
- @matcher_all_keys ||= AllKeysMatcher.new
53
+ @matcher_all_keys ||= AllKeysMatcher.new(@config.split_logger)
53
54
  end
54
55
 
55
56
  # returns UserDefinedSegmentMatcher[object]
@@ -57,7 +58,7 @@ module SplitIoClient
57
58
  matcher = params[:matcher]
58
59
  segment_name = matcher[:userDefinedSegmentMatcherData] && matcher[:userDefinedSegmentMatcherData][:segmentName]
59
60
 
60
- UserDefinedSegmentMatcher.new(params[:segments_repository], segment_name)
61
+ UserDefinedSegmentMatcher.new(params[:segments_repository], segment_name, @config.split_logger)
61
62
  end
62
63
 
63
64
  # returns WhitelistMatcher[object] the whitelist for this condition in case it has a whitelist matcher
@@ -72,7 +73,7 @@ module SplitIoClient
72
73
  white_list = (matcher[:whitelistMatcherData])[:whitelist]
73
74
  result = { attribute: attribute, value: white_list }
74
75
  end
75
- WhitelistMatcher.new(result)
76
+ WhitelistMatcher.new(result, @config.split_logger, @config.split_validator)
76
77
  end
77
78
 
78
79
  def matcher_equal_to(params)
@@ -80,7 +81,7 @@ module SplitIoClient
80
81
  attribute = (matcher[:keySelector])[:attribute]
81
82
  value = (matcher[:unaryNumericMatcherData])[:value]
82
83
  data_type = (matcher[:unaryNumericMatcherData])[:dataType]
83
- EqualToMatcher.new(attribute: attribute, value: value, data_type: data_type)
84
+ EqualToMatcher.new({attribute: attribute, value: value, data_type: data_type}, @config.split_logger, @config.split_validator)
84
85
  end
85
86
 
86
87
  def matcher_greater_than_or_equal_to(params)
@@ -88,7 +89,7 @@ module SplitIoClient
88
89
  attribute = (matcher[:keySelector])[:attribute]
89
90
  value = (matcher[:unaryNumericMatcherData])[:value]
90
91
  data_type = (matcher[:unaryNumericMatcherData])[:dataType]
91
- GreaterThanOrEqualToMatcher.new(attribute: attribute, value: value, data_type: data_type)
92
+ GreaterThanOrEqualToMatcher.new({attribute: attribute, value: value, data_type: data_type}, @config.split_logger, @config.split_validator)
92
93
  end
93
94
 
94
95
  def matcher_less_than_or_equal_to(params)
@@ -96,7 +97,7 @@ module SplitIoClient
96
97
  attribute = (matcher[:keySelector])[:attribute]
97
98
  value = (matcher[:unaryNumericMatcherData])[:value]
98
99
  data_type = (matcher[:unaryNumericMatcherData])[:dataType]
99
- LessThanOrEqualToMatcher.new(attribute: attribute, value: value, data_type: data_type)
100
+ LessThanOrEqualToMatcher.new({attribute: attribute, value: value, data_type: data_type}, @config.split_logger, @config.split_validator)
100
101
  end
101
102
 
102
103
  def matcher_between(params)
@@ -105,79 +106,137 @@ module SplitIoClient
105
106
  start_value = (matcher[:betweenMatcherData])[:start]
106
107
  end_value = (matcher[:betweenMatcherData])[:end]
107
108
  data_type = (matcher[:betweenMatcherData])[:dataType]
108
- BetweenMatcher.new(attribute: attribute, start_value: start_value, end_value: end_value, data_type: data_type)
109
+ BetweenMatcher.new({attribute: attribute, start_value: start_value, end_value: end_value, data_type: data_type}, @config.split_logger, @config.split_validator)
109
110
  end
110
111
 
111
112
  def matcher_equal_to_set(params)
112
113
  EqualToSetMatcher.new(
113
114
  params[:matcher][:keySelector][:attribute],
114
- params[:matcher][:whitelistMatcherData][:whitelist]
115
+ params[:matcher][:whitelistMatcherData][:whitelist],
116
+ @config.split_logger
115
117
  )
116
118
  end
117
119
 
118
120
  def matcher_contains_any_of_set(params)
119
121
  ContainsAnyMatcher.new(
120
122
  params[:matcher][:keySelector][:attribute],
121
- params[:matcher][:whitelistMatcherData][:whitelist]
123
+ params[:matcher][:whitelistMatcherData][:whitelist],
124
+ @config.split_logger
122
125
  )
123
126
  end
124
127
 
125
128
  def matcher_contains_all_of_set(params)
126
129
  ContainsAllMatcher.new(
127
130
  params[:matcher][:keySelector][:attribute],
128
- params[:matcher][:whitelistMatcherData][:whitelist]
131
+ params[:matcher][:whitelistMatcherData][:whitelist],
132
+ @config.split_logger
129
133
  )
130
134
  end
131
135
 
132
136
  def matcher_part_of_set(params)
133
137
  PartOfSetMatcher.new(
134
138
  params[:matcher][:keySelector][:attribute],
135
- params[:matcher][:whitelistMatcherData][:whitelist]
139
+ params[:matcher][:whitelistMatcherData][:whitelist],
140
+ @config.split_logger
136
141
  )
137
142
  end
138
143
 
139
144
  def matcher_starts_with(params)
140
145
  StartsWithMatcher.new(
141
146
  params[:matcher][:keySelector][:attribute],
142
- params[:matcher][:whitelistMatcherData][:whitelist]
147
+ params[:matcher][:whitelistMatcherData][:whitelist],
148
+ @config.split_logger
143
149
  )
144
150
  end
145
151
 
146
152
  def matcher_ends_with(params)
147
153
  EndsWithMatcher.new(
148
154
  params[:matcher][:keySelector][:attribute],
149
- params[:matcher][:whitelistMatcherData][:whitelist]
155
+ params[:matcher][:whitelistMatcherData][:whitelist],
156
+ @config.split_logger
150
157
  )
151
158
  end
152
159
 
153
160
  def matcher_contains_string(params)
154
161
  ContainsMatcher.new(
155
162
  params[:matcher][:keySelector][:attribute],
156
- params[:matcher][:whitelistMatcherData][:whitelist]
163
+ params[:matcher][:whitelistMatcherData][:whitelist],
164
+ @config.split_logger, @config.split_validator
157
165
  )
158
166
  end
159
167
 
160
168
  def matcher_in_split_treatment(params)
161
169
  DependencyMatcher.new(
162
170
  params[:matcher][:dependencyMatcherData][:split],
163
- params[:matcher][:dependencyMatcherData][:treatments]
171
+ params[:matcher][:dependencyMatcherData][:treatments],
172
+ @config.split_logger
164
173
  )
165
174
  end
166
175
 
167
176
  def matcher_equal_to_boolean(params)
168
177
  EqualToBooleanMatcher.new(
169
178
  params[:matcher][:keySelector][:attribute],
170
- params[:matcher][:booleanMatcherData]
179
+ params[:matcher][:booleanMatcherData],
180
+ @config.split_logger
171
181
  )
172
182
  end
173
183
 
174
184
  def matcher_matches_string(params)
175
185
  MatchesStringMatcher.new(
176
186
  params[:matcher][:keySelector][:attribute],
177
- params[:matcher][:stringMatcherData]
187
+ params[:matcher][:stringMatcherData],
188
+ @config.split_logger
178
189
  )
179
190
  end
180
191
 
192
+ def matcher_equal_to_semver(params)
193
+ EqualToSemverMatcher.new(
194
+ params[:matcher][:keySelector][:attribute],
195
+ params[:matcher][:stringMatcherData],
196
+ @config.split_logger, @config.split_validator
197
+ )
198
+ end
199
+
200
+ def matcher_greater_than_or_equal_to_semver(params)
201
+ GreaterThanOrEqualToSemverMatcher.new(
202
+ params[:matcher][:keySelector][:attribute],
203
+ params[:matcher][:stringMatcherData],
204
+ @config.split_logger, @config.split_validator
205
+ )
206
+ end
207
+
208
+ def matcher_less_than_or_equal_to_semver(params)
209
+ LessThanOrEqualToSemverMatcher.new(
210
+ params[:matcher][:keySelector][:attribute],
211
+ params[:matcher][:stringMatcherData],
212
+ @config.split_logger, @config.split_validator
213
+ )
214
+ end
215
+
216
+ def matcher_between_semver(params)
217
+ BetweenSemverMatcher.new(
218
+ params[:matcher][:keySelector][:attribute],
219
+ params[:matcher][:betweenStringMatcherData][:start],
220
+ params[:matcher][:betweenStringMatcherData][:end],
221
+ @config.split_logger, @config.split_validator
222
+ )
223
+ end
224
+
225
+ def matcher_in_list_semver(params)
226
+ InListSemverMatcher.new(
227
+ params[:matcher][:keySelector][:attribute],
228
+ params[:matcher][:whitelistMatcherData][:whitelist],
229
+ @config.split_logger, @config.split_validator
230
+ )
231
+ end
232
+
233
+ def matcher_in_rule_based_segment(params)
234
+ matcher = params[:matcher]
235
+ segment_name = matcher[:userDefinedSegmentMatcherData] && matcher[:userDefinedSegmentMatcherData][:segmentName]
236
+
237
+ RuleBasedSegmentMatcher.new(params[:segments_repository], params[:rule_based_segments_repository], segment_name, @config)
238
+ end
239
+
181
240
  #
182
241
  # @return [object] the negate value for this condition
183
242
  def negate
@@ -194,6 +253,8 @@ module SplitIoClient
194
253
  # @return [void]
195
254
  def set_partitions
196
255
  partitions_list = []
256
+ return partitions_list unless @data.key?(:partitions) or @data.key?('partitions')
257
+
197
258
  @data[:partitions].each do |p|
198
259
  partition = SplitIoClient::Partition.new(p)
199
260
  partitions_list << partition
@@ -2,53 +2,52 @@ module SplitIoClient
2
2
  module Engine
3
3
  module Parser
4
4
  class Evaluator
5
- def initialize(segments_repository, splits_repository, multiple = false)
5
+ def initialize(segments_repository, splits_repository, rb_segment_repository, config)
6
6
  @splits_repository = splits_repository
7
7
  @segments_repository = segments_repository
8
- @multiple = multiple
9
- @cache = {}
8
+ @rb_segment_repository = rb_segment_repository
9
+ @config = config
10
10
  end
11
11
 
12
- def call(keys, split, attributes = nil)
12
+ def evaluate_feature_flag(keys, feature_flag, attributes = nil)
13
13
  # DependencyMatcher here, split is actually a split_name in this case
14
- cache_result = split.is_a? String
15
- split = @splits_repository.get_split(split) if cache_result
16
- digest = Digest::MD5.hexdigest("#{{matching_key: keys[:matching_key]}}#{split}#{attributes}")
14
+ cache_result = feature_flag.is_a? String
15
+ feature_flag = @splits_repository.get_split(feature_flag) if cache_result
16
+ evaluate_treatment(keys, feature_flag, attributes)
17
+ end
17
18
 
18
- if Models::Split.archived?(split)
19
- return treatment_hash(Models::Label::ARCHIVED, Models::Treatment::CONTROL, split[:changeNumber])
20
- end
19
+ private
21
20
 
22
- treatment = if Models::Split.matchable?(split)
23
- if @multiple && @cache[digest]
24
- @cache[digest]
25
- else
26
- match(split, keys, attributes)
27
- end
28
- else
29
- treatment_hash(Models::Label::KILLED, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split))
21
+ def evaluate_treatment(keys, feature_flag, attributes)
22
+ if Models::Split.archived?(feature_flag)
23
+ return treatment_hash(Models::Label::ARCHIVED, Models::Treatment::CONTROL, feature_flag[:changeNumber])
30
24
  end
31
25
 
32
- @cache[digest] = treatment if cache_result
26
+ treatment = if Models::Split.matchable?(feature_flag)
27
+ match(feature_flag, keys, attributes)
28
+ else
29
+ treatment_hash(Models::Label::KILLED, feature_flag[:defaultTreatment], feature_flag[:changeNumber], split_configurations(feature_flag[:defaultTreatment], feature_flag))
30
+ end
33
31
 
34
32
  treatment
35
33
  end
36
34
 
37
- private
38
-
39
35
  def split_configurations(treatment, split)
40
36
  return nil if split[:configurations].nil?
41
37
  split[:configurations][treatment.to_sym]
42
38
  end
43
39
 
44
40
  def match(split, keys, attributes)
41
+
42
+ return treatment_hash(Models::Label::PREREQUISITES_NOT_MET, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split)) unless check_prerequisites_matcher(split, keys, attributes)
43
+
45
44
  in_rollout = false
46
45
  key = keys[:bucketing_key] ? keys[:bucketing_key] : keys[:matching_key]
47
46
  legacy_algo = (split[:algo] == 1 || split[:algo] == nil) ? true : false
48
47
  splitter = Splitter.new
49
48
 
50
49
  split[:conditions].each do |c|
51
- condition = SplitIoClient::Condition.new(c)
50
+ condition = SplitIoClient::Condition.new(c, @config)
52
51
 
53
52
  next if condition.empty?
54
53
 
@@ -63,8 +62,7 @@ module SplitIoClient
63
62
 
64
63
  in_rollout = true
65
64
  end
66
-
67
- condition_matched = matcher_type(condition).match?(
65
+ condition_matched = Helpers::EvaluatorHelper::matcher_type(condition, @segments_repository, @rb_segment_repository).match?(
68
66
  matching_key: keys[:matching_key],
69
67
  bucketing_key: keys[:bucketing_key],
70
68
  evaluator: self,
@@ -75,35 +73,19 @@ module SplitIoClient
75
73
 
76
74
  result = splitter.get_treatment(key, split[:seed], condition.partitions, split[:algo])
77
75
 
78
- if result.nil?
79
- return treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split))
80
- else
81
- return treatment_hash(c[:label], result, split[:changeNumber],split_configurations(result, split))
82
- end
76
+ return treatment_from_result(result, split, c)
83
77
  end
84
78
 
85
79
  treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split))
86
80
  end
87
81
 
88
- def matcher_type(condition)
89
- matchers = []
90
-
91
- @segments_repository.adapter.pipelined do
92
- condition.matchers.each do |matcher|
93
- matchers << if matcher[:negate]
94
- condition.negation_matcher(matcher_instance(matcher[:matcherType], condition, matcher))
95
- else
96
- matcher_instance(matcher[:matcherType], condition, matcher)
97
- end
98
- end
99
- end
100
-
101
- final_matcher = condition.create_condition_matcher(matchers)
82
+ private
102
83
 
103
- if final_matcher.nil?
104
- @logger.error('Invalid matcher type')
84
+ def treatment_from_result(result, split, condition)
85
+ if result.nil?
86
+ return treatment_hash(Models::Label::NO_RULE_MATCHED, split[:defaultTreatment], split[:changeNumber], split_configurations(split[:defaultTreatment], split))
105
87
  else
106
- final_matcher
88
+ return treatment_hash(condition[:label], result, split[:changeNumber],split_configurations(result, split))
107
89
  end
108
90
  end
109
91
 
@@ -111,11 +93,18 @@ module SplitIoClient
111
93
  { label: label, treatment: treatment, change_number: change_number, config: configurations }
112
94
  end
113
95
 
114
- def matcher_instance(type, condition, matcher)
115
- condition.send(
116
- "matcher_#{type.downcase}",
117
- matcher: matcher, segments_repository: @segments_repository
118
- )
96
+ def check_prerequisites_matcher(split, keys, attributes)
97
+ if split.key?(:prerequisites) && !split[:prerequisites].nil?
98
+ prerequisites_matcher = SplitIoClient::PrerequisitesMatcher.new(split[:prerequisites], @config.split_logger)
99
+ return prerequisites_matcher.match?(
100
+ matching_key: keys[:matching_key],
101
+ bucketing_key: keys[:bucketing_key],
102
+ evaluator: self,
103
+ attributes: attributes
104
+ )
105
+ end
106
+
107
+ true
119
108
  end
120
109
  end
121
110
  end