splitclient-rb 5.1.2.pre.rc21-java → 5.1.3.pre.rc1-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.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/CHANGES.txt +6 -0
- data/Detailed-README.md +8 -0
- data/NEWS +8 -0
- data/lib/splitclient-rb.rb +3 -2
- data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +131 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +6 -1
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +7 -2
- data/lib/splitclient-rb/clients/split_client.rb +57 -50
- data/lib/splitclient-rb/engine/models/label.rb +0 -1
- data/lib/splitclient-rb/exceptions.rb +7 -0
- data/lib/splitclient-rb/managers/split_manager.rb +1 -2
- data/lib/splitclient-rb/split_config.rb +23 -0
- data/lib/splitclient-rb/validators.rb +185 -0
- data/lib/splitclient-rb/version.rb +1 -1
- data/splitclient-rb.gemspec +2 -0
- metadata +33 -4
- data/lib/splitclient-rb/exceptions/impressions_shutdown_exception.rb +0 -4
- data/lib/splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86614a077b8bb2e11605c201e8d7ce74fa53af08
|
4
|
+
data.tar.gz: 5a775b16d37564ba6897dccd48d33472e7c4e1c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22d0552dfae11161414e2a624ffaf8a4e7d402914541109da17f71178474b6627e6b5c5ef71622e56190cbb1b30cec8cba60c2bf39099b0019f8705ed7c4f71a
|
7
|
+
data.tar.gz: 90e26ace99de500d55c05ddd9dc632b17e9d67bc8a1b5abbd1facae06110dfb8a43cb5443b9172293da7a25e1156a409b8e05406c7be5c1475ef307e33d70011
|
data/.gitignore
CHANGED
data/CHANGES.txt
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
5.1.3
|
2
|
+
- Add cache wrapper to treatments and segments.
|
3
|
+
|
4
|
+
5.1.2 (October 26th, 2018)
|
5
|
+
- Add input validation for client API methods
|
6
|
+
|
1
7
|
5.1.1 (October 4th, 2018)
|
2
8
|
- Change get_treatments so that it sends a single latency metric
|
3
9
|
- Removed unused call to Redis#scan when adding latencies
|
data/Detailed-README.md
CHANGED
@@ -301,6 +301,14 @@ _To use Redis, include `redis-rb` in your app's Gemfile._
|
|
301
301
|
|
302
302
|
*default value* = (your current hostname)
|
303
303
|
|
304
|
+
**cache_ttl** : Time to live in seconds for the memory cache values when using Redis.
|
305
|
+
|
306
|
+
*default value* = `5`
|
307
|
+
|
308
|
+
**max_cache_size** : Maximum number of items held in the memory cache values when using Redis. When cache is full an LRU strategy for pruning shall be used.
|
309
|
+
|
310
|
+
*default value* = `500`
|
311
|
+
|
304
312
|
**redis_url** : Redis URL or hash with configuration for the SDK to connect to. See [Redis#initialize](https://www.rubydoc.info/github/redis/redis-rb/Redis%3Ainitialize) for detailed information.
|
305
313
|
|
306
314
|
*default value* = `'redis://127.0.0.1:6379/0'`
|
data/NEWS
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
5.1.3
|
2
|
+
|
3
|
+
Add cache wrapper to treatments and segments.
|
4
|
+
|
5
|
+
5.1.2
|
6
|
+
|
7
|
+
Add input validation for client API methods: get_treatment, get_treatments, track, manager
|
8
|
+
|
1
9
|
5.1.1
|
2
10
|
|
3
11
|
Reduces the number of calls to Redis when calling #client.get_treatments using such cache adapter.
|
data/lib/splitclient-rb.rb
CHANGED
@@ -2,11 +2,11 @@ require 'forwardable'
|
|
2
2
|
|
3
3
|
require 'splitclient-rb/version'
|
4
4
|
|
5
|
-
require 'splitclient-rb/exceptions
|
6
|
-
require 'splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception'
|
5
|
+
require 'splitclient-rb/exceptions'
|
7
6
|
require 'splitclient-rb/cache/routers/impression_router'
|
8
7
|
require 'splitclient-rb/cache/adapters/memory_adapters/map_adapter'
|
9
8
|
require 'splitclient-rb/cache/adapters/memory_adapters/queue_adapter'
|
9
|
+
require 'splitclient-rb/cache/adapters/cache_adapter'
|
10
10
|
require 'splitclient-rb/cache/adapters/memory_adapter'
|
11
11
|
require 'splitclient-rb/cache/adapters/redis_adapter'
|
12
12
|
require 'splitclient-rb/cache/repositories/repository'
|
@@ -80,6 +80,7 @@ require 'splitclient-rb/engine/models/split'
|
|
80
80
|
require 'splitclient-rb/engine/models/label'
|
81
81
|
require 'splitclient-rb/engine/models/treatment'
|
82
82
|
require 'splitclient-rb/utilitites'
|
83
|
+
require 'splitclient-rb/validators'
|
83
84
|
|
84
85
|
# C extension
|
85
86
|
require 'murmurhash/murmurhash_mri'
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'lru_redux'
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Cache
|
5
|
+
module Adapters
|
6
|
+
class CacheAdapter
|
7
|
+
extend Forwardable
|
8
|
+
def_delegators :@adapter, :initialize_set, :set_bool, :pipelined
|
9
|
+
|
10
|
+
def initialize(adapter)
|
11
|
+
@cache = LruRedux::TTL::ThreadSafeCache.new(SplitIoClient.configuration.max_cache_size, SplitIoClient.configuration.cache_ttl)
|
12
|
+
@adapter = adapter
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete(key)
|
16
|
+
@cache.delete(key)
|
17
|
+
@adapter.delete(key)
|
18
|
+
end
|
19
|
+
|
20
|
+
def clear(namespace_key)
|
21
|
+
@cache.clear
|
22
|
+
@adapter.clear(namespace_key)
|
23
|
+
end
|
24
|
+
|
25
|
+
def string(key)
|
26
|
+
value = get(key)
|
27
|
+
return value if value
|
28
|
+
value = @adapter.string(key)
|
29
|
+
add(key, value)
|
30
|
+
value
|
31
|
+
end
|
32
|
+
|
33
|
+
def set_string(key, value)
|
34
|
+
add(key, value)
|
35
|
+
@adapter.set_string(key, value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def multiple_strings(keys)
|
39
|
+
cached_values = keys.each_with_object({}) do |key, memo|
|
40
|
+
memo[key] = get(key)
|
41
|
+
end
|
42
|
+
|
43
|
+
non_cached_keys = []
|
44
|
+
cached_values.delete_if{ |k,v| v.nil? ? non_cached_keys << k : false }
|
45
|
+
|
46
|
+
if non_cached_keys.any?
|
47
|
+
new_values = @adapter.multiple_strings(non_cached_keys)
|
48
|
+
|
49
|
+
new_values.keys.each do |key, value|
|
50
|
+
add(key, value)
|
51
|
+
end
|
52
|
+
|
53
|
+
cached_values.merge!(new_values)
|
54
|
+
end
|
55
|
+
|
56
|
+
cached_values
|
57
|
+
end
|
58
|
+
|
59
|
+
def find_strings_by_prefix(prefix)
|
60
|
+
@adapter.find_strings_by_prefix(prefix)
|
61
|
+
end
|
62
|
+
|
63
|
+
def exists?(key)
|
64
|
+
cached_value = get(key)
|
65
|
+
if cached_value.nil?
|
66
|
+
@adapter.exists?(key)
|
67
|
+
else
|
68
|
+
true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def add_to_set(key, values)
|
73
|
+
if values.is_a? Array
|
74
|
+
values.each { |value| add_to_map(key, value, 1) }
|
75
|
+
else
|
76
|
+
add_to_map(key, values, 1)
|
77
|
+
end
|
78
|
+
@adapter.add_to_set(key, values)
|
79
|
+
end
|
80
|
+
|
81
|
+
def in_set?(key, field)
|
82
|
+
cached_value = get(key)
|
83
|
+
if cached_value.nil?
|
84
|
+
return @adapter.in_set?(key, field)
|
85
|
+
end
|
86
|
+
cached_value.key?(field)
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_set(key)
|
90
|
+
cached_value = get(key)
|
91
|
+
if cached_value.nil?
|
92
|
+
return @adapter.get_set(key)
|
93
|
+
end
|
94
|
+
cached_value.keys
|
95
|
+
end
|
96
|
+
|
97
|
+
def delete_from_set(key, fields)
|
98
|
+
cached_value = get(key)
|
99
|
+
if cached_value
|
100
|
+
if fields.is_a? Array
|
101
|
+
fields.each { |field| cached_value.delete(field) }
|
102
|
+
else
|
103
|
+
cached_value.delete(fields)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
@adapter.delete_from_set(key, fields)
|
108
|
+
end
|
109
|
+
|
110
|
+
def initialize_map(key)
|
111
|
+
@cache[key] = Concurrent::Map.new
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def add_to_map(key, field, value)
|
117
|
+
initialize_map(key) unless get(key)
|
118
|
+
get(key).put(field.to_s, value.to_s)
|
119
|
+
end
|
120
|
+
|
121
|
+
def add(key, value)
|
122
|
+
@cache[key] = value.to_s unless value.nil?
|
123
|
+
end
|
124
|
+
|
125
|
+
def get(key)
|
126
|
+
@cache[key]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -7,7 +7,12 @@ module SplitIoClient
|
|
7
7
|
attr_reader :adapter
|
8
8
|
|
9
9
|
def initialize(adapter)
|
10
|
-
@adapter = adapter
|
10
|
+
@adapter = case adapter.class.to_s
|
11
|
+
when 'SplitIoClient::Cache::Adapters::RedisAdapter'
|
12
|
+
SplitIoClient::Cache::Adapters::CacheAdapter.new(adapter)
|
13
|
+
else
|
14
|
+
adapter
|
15
|
+
end
|
11
16
|
@adapter.set_bool(namespace_key('.ready'), false) unless SplitIoClient.configuration.mode == :consumer
|
12
17
|
end
|
13
18
|
|
@@ -7,7 +7,12 @@ module SplitIoClient
|
|
7
7
|
attr_reader :adapter
|
8
8
|
|
9
9
|
def initialize(adapter)
|
10
|
-
@adapter = adapter
|
10
|
+
@adapter = case adapter.class.to_s
|
11
|
+
when 'SplitIoClient::Cache::Adapters::RedisAdapter'
|
12
|
+
SplitIoClient::Cache::Adapters::CacheAdapter.new(adapter)
|
13
|
+
else
|
14
|
+
adapter
|
15
|
+
end
|
11
16
|
unless SplitIoClient.configuration.mode == :consumer
|
12
17
|
@adapter.set_string(namespace_key('.splits.till'), '-1')
|
13
18
|
@adapter.initialize_map(namespace_key('.segments.registered'))
|
@@ -26,7 +31,7 @@ module SplitIoClient
|
|
26
31
|
|
27
32
|
def get_splits(names)
|
28
33
|
splits = {}
|
29
|
-
split_names = names.
|
34
|
+
split_names = names.map { |name| namespace_key(".split.#{name}") }
|
30
35
|
splits.merge!(
|
31
36
|
@adapter
|
32
37
|
.multiple_strings(split_names)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
module SplitIoClient
|
2
|
+
|
2
3
|
class SplitClient
|
3
4
|
#
|
4
5
|
# Creates a new split client instance that connects to split.io API.
|
@@ -17,11 +18,24 @@ module SplitIoClient
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def get_treatments(key, split_names, attributes = {})
|
21
|
+
|
22
|
+
return nil unless SplitIoClient::Validators.valid_get_treatments_parameters(split_names)
|
23
|
+
|
24
|
+
sanitized_split_names = sanitize_split_names(split_names)
|
25
|
+
|
26
|
+
if sanitized_split_names.empty?
|
27
|
+
SplitIoClient.configuration.logger.warn('get_treatments: split_names is an empty array or has null values')
|
28
|
+
return {}
|
29
|
+
end
|
30
|
+
|
20
31
|
bucketing_key, matching_key = keys_from_key(key)
|
32
|
+
bucketing_key = bucketing_key ? bucketing_key.to_s : nil
|
33
|
+
matching_key = matching_key ? matching_key.to_s : nil
|
34
|
+
|
21
35
|
evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, true)
|
22
36
|
start = Time.now
|
23
37
|
treatments_labels_change_numbers =
|
24
|
-
@splits_repository.get_splits(
|
38
|
+
@splits_repository.get_splits(sanitized_split_names).each_with_object({}) do |(name, data), memo|
|
25
39
|
memo.merge!(name => get_treatment(key, name, attributes, data, false, true, evaluator))
|
26
40
|
end
|
27
41
|
latency = (Time.now - start) * 1000.0
|
@@ -34,13 +48,13 @@ module SplitIoClient
|
|
34
48
|
matching_key, bucketing_key, treatments_labels_change_numbers, time
|
35
49
|
)
|
36
50
|
|
37
|
-
route_impressions(
|
51
|
+
route_impressions(sanitized_split_names, matching_key, bucketing_key, time, treatments_labels_change_numbers, attributes)
|
38
52
|
end
|
39
53
|
|
40
|
-
|
54
|
+
split_names_keys = treatments_labels_change_numbers.keys
|
41
55
|
treatments = treatments_labels_change_numbers.values.map { |v| v[:treatment] }
|
42
56
|
|
43
|
-
Hash[
|
57
|
+
Hash[split_names_keys.zip(treatments)]
|
44
58
|
end
|
45
59
|
|
46
60
|
#
|
@@ -59,68 +73,43 @@ module SplitIoClient
|
|
59
73
|
key, split_name, attributes = {}, split_data = nil, store_impressions = true,
|
60
74
|
multiple = false, evaluator = nil
|
61
75
|
)
|
62
|
-
|
63
|
-
|
64
|
-
evaluator ||= Engine::Parser::Evaluator.new(@segments_repository, @splits_repository)
|
76
|
+
control_treatment = { label: Engine::Models::Label::EXCEPTION, treatment: SplitIoClient::Engine::Models::Treatment::CONTROL }
|
77
|
+
parsed_control_treatment = parsed_treatment(multiple, control_treatment)
|
65
78
|
|
66
|
-
|
67
|
-
SplitIoClient.configuration.logger.warn('matching_key was null for split_name: ' + split_name.to_s)
|
68
|
-
return parsed_treatment(multiple, treatment_data)
|
69
|
-
end
|
79
|
+
bucketing_key, matching_key = keys_from_key(key)
|
70
80
|
|
71
|
-
|
72
|
-
SplitIoClient.configuration.logger.warn('split_name was null for key: ' + key)
|
73
|
-
return parsed_treatment(multiple, treatment_data)
|
74
|
-
end
|
81
|
+
return parsed_control_treatment unless SplitIoClient::Validators.valid_get_treatment_parameters(key, split_name, matching_key, bucketing_key)
|
75
82
|
|
76
|
-
|
83
|
+
bucketing_key = bucketing_key ? bucketing_key.to_s : nil
|
84
|
+
matching_key = matching_key.to_s
|
85
|
+
evaluator ||= Engine::Parser::Evaluator.new(@segments_repository, @splits_repository)
|
77
86
|
|
78
87
|
begin
|
88
|
+
start = Time.now
|
89
|
+
|
79
90
|
split = multiple ? split_data : @splits_repository.get_split(split_name)
|
80
91
|
|
81
92
|
if split.nil?
|
82
|
-
SplitIoClient.configuration.logger.
|
83
|
-
return
|
84
|
-
else
|
85
|
-
treatment_data =
|
86
|
-
evaluator.call(
|
87
|
-
{ bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
|
88
|
-
)
|
93
|
+
SplitIoClient.configuration.logger.warn("split_name: #{split_name} does not exist. Returning CONTROL")
|
94
|
+
return parsed_control_treatment
|
89
95
|
end
|
90
|
-
rescue StandardError => error
|
91
|
-
SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
|
92
96
|
|
93
|
-
|
94
|
-
|
95
|
-
{
|
96
|
-
treatment: SplitIoClient::Engine::Models::Treatment::CONTROL,
|
97
|
-
label: SplitIoClient::Engine::Models::Label::EXCEPTION
|
98
|
-
},
|
99
|
-
store_impressions, attributes
|
97
|
+
treatment_data =
|
98
|
+
evaluator.call(
|
99
|
+
{ bucketing_key: bucketing_key, matching_key: matching_key }, split, attributes
|
100
100
|
)
|
101
101
|
|
102
|
-
return parsed_treatment(multiple, treatment_data)
|
103
|
-
end
|
104
|
-
|
105
|
-
begin
|
106
102
|
latency = (Time.now - start) * 1000.0
|
107
|
-
|
103
|
+
store_impression(split_name, matching_key, bucketing_key, treatment_data, store_impressions, attributes)
|
108
104
|
|
109
105
|
# Measure
|
110
106
|
@adapter.metrics.time('sdk.get_treatment', latency) unless multiple
|
111
107
|
rescue StandardError => error
|
112
108
|
SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
|
113
109
|
|
114
|
-
store_impression(
|
115
|
-
split_name, matching_key, bucketing_key,
|
116
|
-
{
|
117
|
-
treatment: SplitIoClient::Engine::Models::Treatment::CONTROL,
|
118
|
-
label: SplitIoClient::Engine::Models::Label::EXCEPTION
|
119
|
-
},
|
120
|
-
store_impressions, attributes
|
121
|
-
)
|
110
|
+
store_impression(split_name, matching_key, bucketing_key, control_treatment, store_impressions, attributes)
|
122
111
|
|
123
|
-
return
|
112
|
+
return parsed_control_treatment
|
124
113
|
end
|
125
114
|
|
126
115
|
parsed_treatment(multiple, treatment_data)
|
@@ -188,16 +177,23 @@ module SplitIoClient
|
|
188
177
|
@impression_router ||= SplitIoClient::ImpressionRouter.new
|
189
178
|
end
|
190
179
|
|
191
|
-
def track(key,
|
192
|
-
|
180
|
+
def track(key, traffic_type_name, event_type, value = nil)
|
181
|
+
return false unless SplitIoClient::Validators.valid_track_parameters(key, traffic_type_name, event_type, value)
|
182
|
+
begin
|
183
|
+
@events_repository.add(key.to_s, traffic_type_name, event_type.to_s, (Time.now.to_f * 1000).to_i, value)
|
184
|
+
true
|
185
|
+
rescue StandardError => error
|
186
|
+
SplitIoClient.configuration.log_found_exception(__method__.to_s, error)
|
187
|
+
false
|
188
|
+
end
|
193
189
|
end
|
194
190
|
|
195
191
|
def keys_from_key(key)
|
196
192
|
case key.class.to_s
|
197
193
|
when 'Hash'
|
198
|
-
key.values_at(:bucketing_key, :matching_key).map { |k| k.nil? ? nil : k
|
194
|
+
key.values_at(:bucketing_key, :matching_key).map { |k| k.nil? ? nil : k }
|
199
195
|
else
|
200
|
-
[nil, key].map { |k| k.nil? ? nil : k
|
196
|
+
[nil, key].map { |k| k.nil? ? nil : k }
|
201
197
|
end
|
202
198
|
end
|
203
199
|
|
@@ -212,5 +208,16 @@ module SplitIoClient
|
|
212
208
|
treatment_data[:treatment]
|
213
209
|
end
|
214
210
|
end
|
211
|
+
|
212
|
+
def sanitize_split_names(split_names)
|
213
|
+
split_names.compact.uniq.select do |split_name|
|
214
|
+
if split_name.is_a?(String) && !split_name.empty?
|
215
|
+
true
|
216
|
+
else
|
217
|
+
SplitIoClient.configuration.logger.warn('get_treatments: split_name has to be a non empty string')
|
218
|
+
false
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
215
222
|
end
|
216
223
|
end
|
@@ -43,7 +43,7 @@ module SplitIoClient
|
|
43
43
|
#
|
44
44
|
# @returns a split view
|
45
45
|
def split(split_name)
|
46
|
-
return unless @splits_repository
|
46
|
+
return unless @splits_repository && SplitIoClient::Validators.valid_split_parameters(split_name)
|
47
47
|
|
48
48
|
split = @splits_repository.get_split(split_name)
|
49
49
|
|
@@ -63,7 +63,6 @@ module SplitIoClient
|
|
63
63
|
treatments = []
|
64
64
|
end
|
65
65
|
|
66
|
-
|
67
66
|
{
|
68
67
|
name: name,
|
69
68
|
traffic_type_name: split[:trafficTypeName],
|
@@ -33,6 +33,8 @@ module SplitIoClient
|
|
33
33
|
# @option opts [Int] :impressions_queue_size Size of the impressions queue in the memory repository. Once reached, newer impressions will be dropped
|
34
34
|
# @option opts [Int] :impressions_bulk_size Max number of impressions to be sent to the backend on each post
|
35
35
|
# @option opts [#log] :impression_listener this object will capture all impressions and process them through `#log`
|
36
|
+
# @option opts [Int] :cache_ttl Time to live in seconds for the memory cache values when using Redis.
|
37
|
+
# @option opts [Int] :max_cache_size Max number of items to be held in the memory cache before prunning when using Redis.
|
36
38
|
# @return [type] SplitConfig with configuration options
|
37
39
|
def initialize(opts = {})
|
38
40
|
@base_uri = (opts[:base_uri] || SplitConfig.default_base_uri).chomp('/')
|
@@ -70,6 +72,9 @@ module SplitIoClient
|
|
70
72
|
@machine_name = opts[:machine_name] || SplitConfig.machine_hostname
|
71
73
|
@machine_ip = opts[:machine_ip] || SplitConfig.machine_ip
|
72
74
|
|
75
|
+
@cache_ttl = opts[:cache_ttl] || SplitConfig.cache_ttl
|
76
|
+
@max_cache_size = opts[:max_cache_size] || SplitConfig.max_cache_size
|
77
|
+
|
73
78
|
@language = opts[:language] || 'ruby'
|
74
79
|
@version = opts[:version] || SplitIoClient::VERSION
|
75
80
|
|
@@ -176,6 +181,9 @@ module SplitIoClient
|
|
176
181
|
attr_accessor :machine_ip
|
177
182
|
attr_accessor :machine_name
|
178
183
|
|
184
|
+
attr_accessor :cache_ttl
|
185
|
+
attr_accessor :max_cache_size
|
186
|
+
|
179
187
|
attr_accessor :language
|
180
188
|
attr_accessor :version
|
181
189
|
|
@@ -357,6 +365,21 @@ module SplitIoClient
|
|
357
365
|
false
|
358
366
|
end
|
359
367
|
|
368
|
+
#
|
369
|
+
# The default cache time to live
|
370
|
+
#
|
371
|
+
# @return [boolean]
|
372
|
+
def self.cache_ttl
|
373
|
+
5
|
374
|
+
end
|
375
|
+
|
376
|
+
# The default max cache size
|
377
|
+
#
|
378
|
+
# @return [boolean]
|
379
|
+
def self.max_cache_size
|
380
|
+
500
|
381
|
+
end
|
382
|
+
|
360
383
|
#
|
361
384
|
# custom logger of exceptions
|
362
385
|
#
|
@@ -0,0 +1,185 @@
|
|
1
|
+
module SplitIoClient
|
2
|
+
module Validators
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def valid_get_treatment_parameters(key, split_name, matching_key, bucketing_key)
|
6
|
+
valid_key?(key) && valid_split_name?(split_name) && valid_matching_key?(matching_key) && valid_bucketing_key?(bucketing_key)
|
7
|
+
end
|
8
|
+
|
9
|
+
def valid_get_treatments_parameters(split_names)
|
10
|
+
valid_split_names?(split_names)
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid_track_parameters(key, traffic_type_name, event_type, value)
|
14
|
+
valid_track_key?(key) && valid_traffic_type_name?(traffic_type_name) && valid_event_type?(event_type) && valid_value?(value)
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid_split_parameters(split_name)
|
18
|
+
valid_split_name?(split_name, :split)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def string?(value)
|
24
|
+
value.is_a?(String) || value.is_a?(Symbol)
|
25
|
+
end
|
26
|
+
|
27
|
+
def number_or_string?(value)
|
28
|
+
value.is_a?(Numeric) || string?(value)
|
29
|
+
end
|
30
|
+
|
31
|
+
def log_nil(key, method)
|
32
|
+
SplitIoClient.configuration.logger.error("#{method}: #{key} cannot be nil")
|
33
|
+
end
|
34
|
+
|
35
|
+
def log_string(key, method)
|
36
|
+
SplitIoClient.configuration.logger.error("#{method}: #{key} must be a String or a Symbol")
|
37
|
+
end
|
38
|
+
|
39
|
+
def log_number_or_string(key, method)
|
40
|
+
SplitIoClient.configuration.logger.error("#{method}: #{key} must be a String")
|
41
|
+
end
|
42
|
+
|
43
|
+
def log_convert_numeric(key, method)
|
44
|
+
SplitIoClient.configuration.logger.warn("#{method}: #{key} is not of type String, converting to String")
|
45
|
+
end
|
46
|
+
|
47
|
+
def valid_split_name?(split_name, method=:get_treatment)
|
48
|
+
if split_name.nil?
|
49
|
+
log_nil(:split_name, method)
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
|
53
|
+
unless string?(split_name)
|
54
|
+
log_string(:split_name, method)
|
55
|
+
return false
|
56
|
+
end
|
57
|
+
|
58
|
+
return true
|
59
|
+
end
|
60
|
+
|
61
|
+
def valid_key?(key)
|
62
|
+
if key.nil?
|
63
|
+
log_nil(:key, :get_treatment)
|
64
|
+
return false
|
65
|
+
end
|
66
|
+
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
|
70
|
+
def valid_matching_key?(matching_key)
|
71
|
+
if matching_key.nil?
|
72
|
+
log_nil(:matching_key, :get_treatment)
|
73
|
+
return false
|
74
|
+
end
|
75
|
+
|
76
|
+
unless number_or_string?(matching_key)
|
77
|
+
log_number_or_string(:matching_key, :get_treatment)
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
|
81
|
+
if matching_key.is_a? Numeric
|
82
|
+
log_convert_numeric(:matching_key, :get_treatment)
|
83
|
+
end
|
84
|
+
|
85
|
+
return true
|
86
|
+
end
|
87
|
+
|
88
|
+
def valid_bucketing_key?(bucketing_key)
|
89
|
+
if bucketing_key.nil?
|
90
|
+
SplitIoClient.configuration.logger.warn('get_treatment: key object should have bucketing_key set')
|
91
|
+
return true
|
92
|
+
end
|
93
|
+
|
94
|
+
unless number_or_string?(bucketing_key)
|
95
|
+
log_number_or_string(:bucketing_key, :get_treatment)
|
96
|
+
return false
|
97
|
+
end
|
98
|
+
|
99
|
+
if bucketing_key.is_a? Numeric
|
100
|
+
log_convert_numeric(:bucketing_key, :get_treatment)
|
101
|
+
end
|
102
|
+
|
103
|
+
return true
|
104
|
+
end
|
105
|
+
|
106
|
+
def valid_split_names?(split_names)
|
107
|
+
if split_names.nil?
|
108
|
+
log_nil(:split_names, :get_treatments)
|
109
|
+
return false
|
110
|
+
end
|
111
|
+
|
112
|
+
unless split_names.is_a? Array
|
113
|
+
SplitIoClient.configuration.logger.warn('get_treatments: split_names must be an Array')
|
114
|
+
return false
|
115
|
+
end
|
116
|
+
|
117
|
+
return true
|
118
|
+
end
|
119
|
+
|
120
|
+
def valid_track_key?(key)
|
121
|
+
if key.nil?
|
122
|
+
log_nil(:key, :track)
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
|
126
|
+
unless number_or_string?(key)
|
127
|
+
log_number_or_string(:key, :track)
|
128
|
+
return false
|
129
|
+
end
|
130
|
+
|
131
|
+
if key.is_a? Numeric
|
132
|
+
log_convert_numeric(:key, :track)
|
133
|
+
end
|
134
|
+
|
135
|
+
return true
|
136
|
+
end
|
137
|
+
|
138
|
+
def valid_event_type?(event_type)
|
139
|
+
if event_type.nil?
|
140
|
+
log_nil(:event_type, :track)
|
141
|
+
return false
|
142
|
+
end
|
143
|
+
|
144
|
+
unless string?(event_type)
|
145
|
+
log_string(:event_type, :track)
|
146
|
+
return false
|
147
|
+
end
|
148
|
+
|
149
|
+
if (event_type.to_s =~ /[a-zA-Z0-9][-_\.a-zA-Z0-9]{0,62}/).nil?
|
150
|
+
SplitIoClient.configuration.logger.error('track: event_type must adhere to [a-zA-Z0-9][-_\.a-zA-Z0-9]{0,62}')
|
151
|
+
return false
|
152
|
+
end
|
153
|
+
|
154
|
+
return true
|
155
|
+
end
|
156
|
+
|
157
|
+
def valid_traffic_type_name?(traffic_type_name)
|
158
|
+
if traffic_type_name.nil?
|
159
|
+
log_nil(:traffic_type_name, :track)
|
160
|
+
return false
|
161
|
+
end
|
162
|
+
|
163
|
+
unless string?(traffic_type_name)
|
164
|
+
log_string(:traffic_type_name, :track)
|
165
|
+
return false
|
166
|
+
end
|
167
|
+
|
168
|
+
if traffic_type_name.empty?
|
169
|
+
SplitIoClient.configuration.logger.error('track: traffic_type_name must not be an empty String')
|
170
|
+
return false
|
171
|
+
end
|
172
|
+
|
173
|
+
return true
|
174
|
+
end
|
175
|
+
|
176
|
+
def valid_value?(value)
|
177
|
+
unless value.is_a?(Numeric) || value.nil?
|
178
|
+
SplitIoClient.configuration.logger.error('track: value must be a number')
|
179
|
+
return false
|
180
|
+
end
|
181
|
+
|
182
|
+
return true
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
data/splitclient-rb.gemspec
CHANGED
@@ -46,11 +46,13 @@ Gem::Specification.new do |spec|
|
|
46
46
|
spec.add_development_dependency 'rspec'
|
47
47
|
spec.add_development_dependency 'rubocop', '0.59.0'
|
48
48
|
spec.add_development_dependency 'simplecov'
|
49
|
+
spec.add_development_dependency 'timecop'
|
49
50
|
spec.add_development_dependency 'webmock'
|
50
51
|
|
51
52
|
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
|
52
53
|
spec.add_runtime_dependency 'faraday', '>= 0.8'
|
53
54
|
spec.add_runtime_dependency 'json', '>= 1.8'
|
55
|
+
spec.add_runtime_dependency 'lru_redux'
|
54
56
|
spec.add_runtime_dependency 'net-http-persistent', '~> 2.9'
|
55
57
|
spec.add_runtime_dependency 'redis', '>= 3.2'
|
56
58
|
spec.add_runtime_dependency 'thread_safe', '>= 0.3'
|
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: 5.1.
|
4
|
+
version: 5.1.3.pre.rc1
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Split Software
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
name: timecop
|
146
|
+
prerelease: false
|
147
|
+
type: :development
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
139
153
|
- !ruby/object:Gem::Dependency
|
140
154
|
requirement: !ruby/object:Gem::Requirement
|
141
155
|
requirements:
|
@@ -192,6 +206,20 @@ dependencies:
|
|
192
206
|
- - ">="
|
193
207
|
- !ruby/object:Gem::Version
|
194
208
|
version: '1.8'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
requirement: !ruby/object:Gem::Requirement
|
211
|
+
requirements:
|
212
|
+
- - ">="
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: '0'
|
215
|
+
name: lru_redux
|
216
|
+
prerelease: false
|
217
|
+
type: :runtime
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
195
223
|
- !ruby/object:Gem::Dependency
|
196
224
|
requirement: !ruby/object:Gem::Requirement
|
197
225
|
requirements:
|
@@ -257,6 +285,7 @@ files:
|
|
257
285
|
- lib/murmurhash/murmurhash.jar
|
258
286
|
- lib/murmurhash/murmurhash_mri.rb
|
259
287
|
- lib/splitclient-rb.rb
|
288
|
+
- lib/splitclient-rb/cache/adapters/cache_adapter.rb
|
260
289
|
- lib/splitclient-rb/cache/adapters/memory_adapter.rb
|
261
290
|
- lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb
|
262
291
|
- lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb
|
@@ -321,8 +350,7 @@ files:
|
|
321
350
|
- lib/splitclient-rb/engine/parser/evaluator.rb
|
322
351
|
- lib/splitclient-rb/engine/parser/partition.rb
|
323
352
|
- lib/splitclient-rb/engine/parser/split_adapter.rb
|
324
|
-
- lib/splitclient-rb/exceptions
|
325
|
-
- lib/splitclient-rb/exceptions/sdk_blocker_timeout_expired_exception.rb
|
353
|
+
- lib/splitclient-rb/exceptions.rb
|
326
354
|
- lib/splitclient-rb/localhost_split_factory.rb
|
327
355
|
- lib/splitclient-rb/localhost_utils.rb
|
328
356
|
- lib/splitclient-rb/managers/localhost_split_manager.rb
|
@@ -332,6 +360,7 @@ files:
|
|
332
360
|
- lib/splitclient-rb/split_factory_builder.rb
|
333
361
|
- lib/splitclient-rb/split_logger.rb
|
334
362
|
- lib/splitclient-rb/utilitites.rb
|
363
|
+
- lib/splitclient-rb/validators.rb
|
335
364
|
- lib/splitclient-rb/version.rb
|
336
365
|
- splitclient-rb.gemspec
|
337
366
|
- splitio.yml.example
|