splitclient-rb 2.0.1 → 3.0.2
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/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
|