splitclient-rb 2.0.1 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.txt +12 -0
- data/NEWS +4 -0
- data/README.md +45 -11
- data/lib/cache/adapters/adapter.rb +23 -0
- data/lib/cache/adapters/memory_adapter.rb +46 -0
- data/lib/cache/repositories/repository.rb +25 -0
- data/lib/cache/repositories/segments_repository.rb +52 -0
- data/lib/cache/repositories/splits_repository.rb +51 -0
- data/lib/cache/stores/sdk_blocker.rb +47 -0
- data/lib/cache/stores/segment_store.rb +71 -0
- data/lib/cache/stores/split_store.rb +64 -0
- data/lib/engine/api/client.rb +29 -0
- data/lib/engine/api/segments.rb +60 -0
- data/lib/engine/api/splits.rb +58 -0
- data/lib/{splitclient-engine → engine}/evaluator/splitter.rb +0 -0
- data/lib/{splitclient-engine → engine}/impressions/impressions.rb +0 -0
- data/lib/{splitclient-engine → engine}/matchers/all_keys_matcher.rb +0 -0
- data/lib/{splitclient-engine → engine}/matchers/between_matcher.rb +2 -0
- data/lib/{splitclient-engine → engine}/matchers/combiners.rb +0 -0
- data/lib/{splitclient-engine → engine}/matchers/combining_matcher.rb +1 -1
- data/lib/{splitclient-engine → engine}/matchers/equal_to_matcher.rb +0 -0
- data/lib/{splitclient-engine → engine}/matchers/greater_than_or_equal_to_matcher.rb +0 -0
- data/lib/{splitclient-engine → engine}/matchers/less_than_or_equal_to_matcher.rb +0 -0
- data/lib/{splitclient-engine → engine}/matchers/negation_matcher.rb +0 -0
- data/lib/{splitclient-engine → engine}/matchers/user_defined_segment_matcher.rb +4 -21
- data/lib/{splitclient-engine → engine}/matchers/whitelist_matcher.rb +0 -0
- data/lib/{splitclient-engine → engine}/metrics/binary_search_latency_tracker.rb +0 -0
- data/lib/{splitclient-engine → engine}/metrics/metrics.rb +0 -0
- data/lib/{splitclient-engine → engine}/parser/condition.rb +5 -7
- data/lib/{splitclient-engine → engine}/parser/partition.rb +0 -0
- data/lib/{splitclient-engine → engine}/parser/split.rb +11 -3
- data/lib/{splitclient-engine → engine}/parser/split_adapter.rb +20 -184
- data/lib/engine/parser/split_treatment.rb +65 -0
- data/lib/{splitclient-engine → engine}/partitions/treatments.rb +0 -0
- data/lib/exceptions/sdk_blocker_timeout_expired_exception.rb +4 -0
- data/lib/splitclient-rb.rb +31 -23
- data/lib/splitclient-rb/split_config.rb +41 -4
- data/lib/splitclient-rb/split_factory.rb +50 -20
- data/lib/splitclient-rb/version.rb +1 -1
- data/splitclient-rb.gemspec +2 -0
- metadata +62 -25
- data/lib/splitclient-cache/local_store.rb +0 -45
- data/lib/splitclient-engine/parser/segment.rb +0 -84
- data/lib/splitclient-engine/parser/segment_parser.rb +0 -46
- data/lib/splitclient-engine/parser/split_parser.rb +0 -122
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'thread_safe'
|
2
|
-
|
3
|
-
module SplitIoClient
|
4
|
-
# A thread-safe in-memory store suitable for use
|
5
|
-
# with the Faraday caching HTTP client, uses the
|
6
|
-
# Threadsafe gem as the underlying cache.
|
7
|
-
#
|
8
|
-
class LocalStore
|
9
|
-
#
|
10
|
-
# Default constructor
|
11
|
-
#
|
12
|
-
# @return [ThreadSafeMemoryStore] a new store
|
13
|
-
def initialize
|
14
|
-
@cache = ThreadSafe::Cache.new
|
15
|
-
end
|
16
|
-
|
17
|
-
#
|
18
|
-
# Read a value from the cache
|
19
|
-
# @param key [Object] the cache key
|
20
|
-
#
|
21
|
-
# @return [Object] the cache value
|
22
|
-
def read(key)
|
23
|
-
@cache[key]
|
24
|
-
end
|
25
|
-
|
26
|
-
#
|
27
|
-
# Store a value in the cache
|
28
|
-
# @param key [Object] the cache key
|
29
|
-
# @param value [Object] the value to associate with the key
|
30
|
-
#
|
31
|
-
# @return [Object] the value
|
32
|
-
def write(key, value)
|
33
|
-
@cache[key] = value
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
# deletes value from cache by given key
|
38
|
-
# @param key [Object] the cache key
|
39
|
-
def delete(key)
|
40
|
-
@cache[key] = nil
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
module SplitIoClient
|
2
|
-
|
3
|
-
#
|
4
|
-
# acts as dto for a segment structure
|
5
|
-
#
|
6
|
-
class Segment < NoMethodError
|
7
|
-
#
|
8
|
-
# definition of the segment
|
9
|
-
#
|
10
|
-
# @returns [object] segment values
|
11
|
-
attr_accessor :data
|
12
|
-
|
13
|
-
#
|
14
|
-
# users for the segment
|
15
|
-
#
|
16
|
-
# @returns [object] array of user keys
|
17
|
-
attr_accessor :users
|
18
|
-
|
19
|
-
#
|
20
|
-
# added users for the segment in a given time
|
21
|
-
#
|
22
|
-
# @returns [object] array of user keys that were added after the last segment fetch
|
23
|
-
attr_accessor :added
|
24
|
-
|
25
|
-
#
|
26
|
-
# removed users for the segment in a given time
|
27
|
-
#
|
28
|
-
# @returns [object] array of user keys that were removed after the last segment fetch
|
29
|
-
attr_accessor :removed
|
30
|
-
|
31
|
-
def initialize(segment)
|
32
|
-
@data = segment
|
33
|
-
@added = @data[:added]
|
34
|
-
@removed = @data[:removed]
|
35
|
-
end
|
36
|
-
|
37
|
-
#
|
38
|
-
# @returns [string] name of the segment
|
39
|
-
def name
|
40
|
-
@data[:name]
|
41
|
-
end
|
42
|
-
|
43
|
-
#
|
44
|
-
# @returns [int] since value fo the segment
|
45
|
-
def since
|
46
|
-
@data[:since]
|
47
|
-
end
|
48
|
-
|
49
|
-
#
|
50
|
-
# @returns [int] till value fo the segment
|
51
|
-
def till
|
52
|
-
@data[:till]
|
53
|
-
end
|
54
|
-
|
55
|
-
#
|
56
|
-
# @return [boolean] true if the condition is empty false otherwise
|
57
|
-
def is_empty?
|
58
|
-
@data.empty? ? true : false
|
59
|
-
end
|
60
|
-
|
61
|
-
#
|
62
|
-
# updates the array of user keys valid for the segment, it's used after each segment fetch
|
63
|
-
#
|
64
|
-
# @param added [object] array of added user keys
|
65
|
-
# @param removed [object] array of removed user keys
|
66
|
-
#
|
67
|
-
# @return [void]
|
68
|
-
def refresh_users(added, removed)
|
69
|
-
if @users.nil?
|
70
|
-
@users = self.added
|
71
|
-
else
|
72
|
-
@added = added unless added.empty?
|
73
|
-
@removed = removed unless removed.empty?
|
74
|
-
self.removed.each do |r|
|
75
|
-
@users.delete_if { |u| u == r }
|
76
|
-
end
|
77
|
-
self.added.each do |a|
|
78
|
-
@users << a unless @users.include?(a)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module SplitIoClient
|
2
|
-
#
|
3
|
-
# helper class to parse fetched segments
|
4
|
-
#
|
5
|
-
class SegmentParser < NoMethodError
|
6
|
-
#
|
7
|
-
# segments data
|
8
|
-
attr_accessor :segments
|
9
|
-
|
10
|
-
#
|
11
|
-
# since value for segments
|
12
|
-
attr_accessor :since
|
13
|
-
|
14
|
-
def initialize(logger)
|
15
|
-
@segments = []
|
16
|
-
@since = -1
|
17
|
-
@logger = logger
|
18
|
-
end
|
19
|
-
|
20
|
-
#
|
21
|
-
# method to get a segment by name
|
22
|
-
#
|
23
|
-
# @param name [string] segment name
|
24
|
-
#
|
25
|
-
# @return [object] segment object
|
26
|
-
def get_segment(name)
|
27
|
-
@segments.find { |s| s.name == name }
|
28
|
-
end
|
29
|
-
|
30
|
-
#
|
31
|
-
# method to get all segment names within the structure
|
32
|
-
#
|
33
|
-
# @return [object] array of segment names
|
34
|
-
def get_segment_names
|
35
|
-
@segments.map { |seg| seg.name }
|
36
|
-
end
|
37
|
-
|
38
|
-
#
|
39
|
-
# @return [boolean] true if the segment parser data is empty false otherwise
|
40
|
-
def is_empty?
|
41
|
-
@segments.empty? ? true : false
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
@@ -1,122 +0,0 @@
|
|
1
|
-
module SplitIoClient
|
2
|
-
#
|
3
|
-
# helper class to parse fetched splits
|
4
|
-
#
|
5
|
-
class SplitParser < NoMethodError
|
6
|
-
#
|
7
|
-
# since value for splitChanges last fetch
|
8
|
-
attr_accessor :since
|
9
|
-
|
10
|
-
#
|
11
|
-
# till value for splitChanges last fetch
|
12
|
-
attr_accessor :till
|
13
|
-
|
14
|
-
#
|
15
|
-
# splits data
|
16
|
-
attr_accessor :splits
|
17
|
-
|
18
|
-
#
|
19
|
-
# splits segments data
|
20
|
-
attr_accessor :segments
|
21
|
-
|
22
|
-
def initialize(logger)
|
23
|
-
@splits = []
|
24
|
-
@since = -1
|
25
|
-
@till = -1
|
26
|
-
@logger = logger
|
27
|
-
end
|
28
|
-
|
29
|
-
#
|
30
|
-
# gets all the split names retrived from the endpoint
|
31
|
-
#
|
32
|
-
# @return [object] array of split names
|
33
|
-
def get_split_names
|
34
|
-
@splits.map { |s| s.name }
|
35
|
-
end
|
36
|
-
|
37
|
-
#
|
38
|
-
# @return [boolean] true if the splits content is empty false otherwise
|
39
|
-
def is_empty?
|
40
|
-
@splits.empty? ? true : false
|
41
|
-
end
|
42
|
-
|
43
|
-
#
|
44
|
-
# gets all the segment names that are used within the retrieved splits
|
45
|
-
#
|
46
|
-
# @return [object] array of segment names
|
47
|
-
def get_used_segments
|
48
|
-
segment_names = []
|
49
|
-
|
50
|
-
@splits.each { |s|
|
51
|
-
s.conditions.each { |c|
|
52
|
-
c.matchers.each { |m|
|
53
|
-
m[:userDefinedSegmentMatcherData].each { |seg, name|
|
54
|
-
segment_names << name
|
55
|
-
} unless m[:userDefinedSegmentMatcherData].nil?
|
56
|
-
} unless c.matchers.nil?
|
57
|
-
}
|
58
|
-
}
|
59
|
-
segment_names.uniq
|
60
|
-
end
|
61
|
-
|
62
|
-
#
|
63
|
-
# gets a split parsed object by name
|
64
|
-
#
|
65
|
-
# @param name [string] name of the split
|
66
|
-
#
|
67
|
-
# @return split [object] split object
|
68
|
-
def get_split(name)
|
69
|
-
@splits.find { |s| s.name == name }
|
70
|
-
end
|
71
|
-
|
72
|
-
#
|
73
|
-
# gets the treatment for the given combination of user key and split name
|
74
|
-
# using all parsed data for the splits
|
75
|
-
#
|
76
|
-
# @param id [string] user key
|
77
|
-
# @param name [string] split name
|
78
|
-
# @param default_treatment [string] default treatment value to be returned
|
79
|
-
#
|
80
|
-
# @return treatment [object] treatment for this user key, split pair
|
81
|
-
def get_split_treatment(id, name, default_treatment, attributes = nil)
|
82
|
-
split = get_split(name)
|
83
|
-
if !split.is_empty? && split.status == 'ACTIVE' && !split.killed?
|
84
|
-
split.conditions.each do |condit|
|
85
|
-
unless condit.is_empty?
|
86
|
-
matcher = get_matcher_type condit
|
87
|
-
matches = matcher.match? id, attributes
|
88
|
-
if matches
|
89
|
-
treatment = Splitter.get_treatment id, split.seed, condit.partitions
|
90
|
-
result = treatment.nil? ? default_treatment : treatment
|
91
|
-
return result
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
elsif !split.is_empty? && split.status == 'ARCHIVED'
|
96
|
-
return Treatments::CONTROL
|
97
|
-
end
|
98
|
-
default_treatment
|
99
|
-
end
|
100
|
-
|
101
|
-
#
|
102
|
-
# gets the matcher type from a condition object
|
103
|
-
#
|
104
|
-
# @param contidion [object] a condition object
|
105
|
-
#
|
106
|
-
# @return matcher [object] the matcher object for the given condition
|
107
|
-
def get_matcher_type(condit)
|
108
|
-
matchers = []
|
109
|
-
condit.matchers.each do |matcher|
|
110
|
-
matchers << condit.send("matcher_#{matcher[:matcherType].downcase}", {matcher: matcher, segments: @segments})
|
111
|
-
end
|
112
|
-
final_matcher = condit.create_condition_matcher matchers
|
113
|
-
|
114
|
-
if final_matcher.nil?
|
115
|
-
@logger.error('Invalid matcher type')
|
116
|
-
else
|
117
|
-
final_matcher
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|