absmartly-sdk 1.1.1 → 1.2.1
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/.ruby-version +1 -1
- data/Gemfile.lock +5 -5
- data/example/example.rb +35 -0
- data/lib/a_b_smartly.rb +23 -64
- data/lib/a_b_smartly_config.rb +43 -27
- data/lib/absmartly/version.rb +1 -1
- data/lib/absmartly.rb +16 -18
- data/lib/client.rb +18 -49
- data/lib/client_config.rb +68 -17
- data/lib/context.rb +5 -2
- data/lib/context_config.rb +2 -4
- data/lib/default_context_event_handler.rb +2 -2
- data/lib/default_http_client.rb +1 -1
- data/lib/json_expr/expr_evaluator.rb +0 -1
- metadata +17 -8
- data/absmartly.gemspec +0 -41
- data/lib/absmartly/variant_assigner.rb +0 -35
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7cc6b910c683119e99ad8800165f98b47b280ccd5f9e44a915d1043e1256888c
|
|
4
|
+
data.tar.gz: 8d8d61b7f4f8ed27280a4c3aa4ea7cf9bf8519b5b6743a809c3a799bd38e6c5f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c6a4e6f5e52ffeb1f29a60d0a9a08474c460c28355dfd6c1471c3c756254248cac33c2c7fe0760e8b415e1b699cbee882217177f32a9aeffdbfe5fa2e65a0b45
|
|
7
|
+
data.tar.gz: 1d714b5d6288e2a87982fec2e45f76ff2ef3aaeb2d227e43c3dbaaeafb419f9a33bff7acdd615326454067bee3dcce7682caf11e7ba3a921229d065eb4d51ee0
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3.0.6
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
absmartly-sdk (1.
|
|
4
|
+
absmartly-sdk (1.2.1)
|
|
5
|
+
base64 (~> 0.2)
|
|
5
6
|
faraday (~> 2.0)
|
|
6
7
|
faraday-retry (~> 2.0)
|
|
7
8
|
murmurhash3 (~> 0.1.7)
|
|
@@ -10,13 +11,14 @@ GEM
|
|
|
10
11
|
remote: https://rubygems.org/
|
|
11
12
|
specs:
|
|
12
13
|
ast (2.4.2)
|
|
14
|
+
base64 (0.3.0)
|
|
13
15
|
byebug (11.1.3)
|
|
14
16
|
diff-lcs (1.5.0)
|
|
15
17
|
faraday (2.7.4)
|
|
16
18
|
faraday-net_http (>= 2.0, < 3.1)
|
|
17
19
|
ruby2_keywords (>= 0.0.4)
|
|
18
20
|
faraday-net_http (3.0.2)
|
|
19
|
-
faraday-retry (2.
|
|
21
|
+
faraday-retry (2.4.0)
|
|
20
22
|
faraday (~> 2.0)
|
|
21
23
|
io-console (0.5.6)
|
|
22
24
|
irb (1.2.6)
|
|
@@ -31,8 +33,7 @@ GEM
|
|
|
31
33
|
regexp_parser (2.5.0)
|
|
32
34
|
reline (0.1.5)
|
|
33
35
|
io-console (~> 0.5)
|
|
34
|
-
rexml (3.
|
|
35
|
-
strscan (>= 3.0.9)
|
|
36
|
+
rexml (3.4.4)
|
|
36
37
|
rspec (3.11.0)
|
|
37
38
|
rspec-core (~> 3.11.0)
|
|
38
39
|
rspec-expectations (~> 3.11.0)
|
|
@@ -60,7 +61,6 @@ GEM
|
|
|
60
61
|
parser (>= 3.1.1.0)
|
|
61
62
|
ruby-progressbar (1.11.0)
|
|
62
63
|
ruby2_keywords (0.0.5)
|
|
63
|
-
strscan (3.1.0)
|
|
64
64
|
unicode-display_width (2.2.0)
|
|
65
65
|
|
|
66
66
|
PLATFORMS
|
data/example/example.rb
CHANGED
|
@@ -48,3 +48,38 @@ properties = {
|
|
|
48
48
|
ctx.track("payment", properties)
|
|
49
49
|
|
|
50
50
|
ctx.close
|
|
51
|
+
|
|
52
|
+
context_data = Absmartly.context_data
|
|
53
|
+
ctx2 = Absmartly.create_context_with(context_config, context_data)
|
|
54
|
+
|
|
55
|
+
treatment = ctx2.treatment("exp_test_ab")
|
|
56
|
+
puts(treatment) # 0
|
|
57
|
+
treatment1 = ctx2.treatment("net_seasons")
|
|
58
|
+
puts(treatment1) # 1
|
|
59
|
+
treatment2 = ctx2.treatment("Experimento!")
|
|
60
|
+
puts(treatment2) # 1
|
|
61
|
+
treatment3 = ctx2.treatment("test")
|
|
62
|
+
puts(treatment3) # 1
|
|
63
|
+
|
|
64
|
+
ctx2.set_unit("db_user_id", 1000013)
|
|
65
|
+
ctx2.set_units(db_user_id2: 1000013, session_id2: 12311)
|
|
66
|
+
|
|
67
|
+
ctx2.set_attribute("user_agent", "Chrome 2022")
|
|
68
|
+
ctx2.set_attributes(
|
|
69
|
+
customer_age: "new_customer",
|
|
70
|
+
customer_point: 20,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
ctx2.set_override("new_exp", 3)
|
|
74
|
+
ctx2.set_overrides(
|
|
75
|
+
exp_test_experiment: 1,
|
|
76
|
+
exp_another_experiment: 0,
|
|
77
|
+
)
|
|
78
|
+
ctx2.publish
|
|
79
|
+
properties = {
|
|
80
|
+
value: 125,
|
|
81
|
+
fee: 125
|
|
82
|
+
}
|
|
83
|
+
ctx2.track("payment", properties)
|
|
84
|
+
|
|
85
|
+
ctx2.close
|
data/lib/a_b_smartly.rb
CHANGED
|
@@ -1,92 +1,51 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "time"
|
|
4
|
+
require "singleton"
|
|
5
|
+
require "forwardable"
|
|
4
6
|
require_relative "context"
|
|
5
7
|
require_relative "audience_matcher"
|
|
6
|
-
require_relative "
|
|
7
|
-
require_relative "
|
|
8
|
-
require_relative "default_variable_parser"
|
|
9
|
-
require_relative "default_audience_deserializer"
|
|
10
|
-
require_relative "scheduled_thread_pool_executor"
|
|
8
|
+
require_relative "a_b_smartly_config"
|
|
9
|
+
require_relative "absmartly/version"
|
|
11
10
|
|
|
12
11
|
class ABSmartly
|
|
13
|
-
|
|
14
|
-
:variable_parser, :scheduler, :context_event_logger,
|
|
15
|
-
:audience_deserializer, :client
|
|
12
|
+
extend Forwardable
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
attr_reader :config
|
|
15
|
+
|
|
16
|
+
def_delegators :@config, :context_data_provider, :context_event_handler, :variable_parser, :context_event_logger,
|
|
17
|
+
:audience_deserializer, :client
|
|
18
|
+
|
|
19
|
+
def_delegators :@config, :endpoint, :api_key, :application, :environment
|
|
20
20
|
|
|
21
21
|
def self.create(config)
|
|
22
|
-
|
|
22
|
+
new(config)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def initialize(config)
|
|
26
|
-
|
|
27
|
-
@context_data_provider = config.context_data_provider
|
|
28
|
-
@context_event_handler = config.context_event_handler
|
|
29
|
-
@context_event_logger = config.context_event_logger
|
|
30
|
-
@variable_parser = config.variable_parser
|
|
31
|
-
@audience_deserializer = config.audience_deserializer
|
|
32
|
-
@scheduler = config.scheduler
|
|
33
|
-
|
|
34
|
-
if @context_data_provider.nil? || @context_event_handler.nil?
|
|
35
|
-
@client = config.client
|
|
36
|
-
raise ArgumentError.new("Missing Client instance configuration") if @client.nil?
|
|
37
|
-
|
|
38
|
-
if @context_data_provider.nil?
|
|
39
|
-
@context_data_provider = DefaultContextDataProvider.new(@client)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
if @context_event_handler.nil?
|
|
43
|
-
@context_event_handler = DefaultContextEventHandler.new(@client)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
26
|
+
config.validate!
|
|
46
27
|
|
|
47
|
-
|
|
48
|
-
@variable_parser = DefaultVariableParser.new
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
if @audience_deserializer.nil?
|
|
52
|
-
@audience_deserializer = DefaultAudienceDeserializer.new
|
|
53
|
-
end
|
|
54
|
-
if @scheduler.nil?
|
|
55
|
-
@scheduler = ScheduledThreadPoolExecutor.new(1)
|
|
56
|
-
end
|
|
28
|
+
@config = config
|
|
57
29
|
end
|
|
58
30
|
|
|
59
|
-
def create_context(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
AudienceMatcher.new(@audience_deserializer))
|
|
31
|
+
def create_context(context_config)
|
|
32
|
+
Context.create(get_utc_format, context_config, context_data,
|
|
33
|
+
context_data_provider, context_event_handler, context_event_logger, variable_parser,
|
|
34
|
+
AudienceMatcher.new(audience_deserializer))
|
|
64
35
|
end
|
|
65
36
|
|
|
66
|
-
def create_context_with(
|
|
67
|
-
Context.create(get_utc_format,
|
|
68
|
-
|
|
69
|
-
AudienceMatcher.new(
|
|
37
|
+
def create_context_with(context_config, data)
|
|
38
|
+
Context.create(get_utc_format, context_config, data,
|
|
39
|
+
context_data_provider, context_event_handler, context_event_logger, variable_parser,
|
|
40
|
+
AudienceMatcher.new(audience_deserializer))
|
|
70
41
|
end
|
|
71
42
|
|
|
72
43
|
def context_data
|
|
73
|
-
|
|
44
|
+
context_data_provider.context_data
|
|
74
45
|
end
|
|
75
46
|
|
|
76
47
|
private
|
|
77
48
|
def get_utc_format
|
|
78
49
|
Time.now.utc.iso8601(3)
|
|
79
50
|
end
|
|
80
|
-
|
|
81
|
-
def validate_params(params)
|
|
82
|
-
params.units.each do |key, value|
|
|
83
|
-
unless value.is_a?(String) || value.is_a?(Numeric)
|
|
84
|
-
raise ArgumentError.new("Unit '#{key}' UID is of unsupported type '#{value.class}'. UID must be one of ['string', 'number']")
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
if value.to_s.size.zero?
|
|
88
|
-
raise ArgumentError.new("Unit '#{key}' UID length must be >= 1")
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
51
|
end
|
data/lib/a_b_smartly_config.rb
CHANGED
|
@@ -1,49 +1,65 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "forwardable"
|
|
4
|
+
|
|
5
|
+
require_relative "client"
|
|
6
|
+
require_relative "client_config"
|
|
7
|
+
require_relative "default_context_data_provider"
|
|
8
|
+
require_relative "default_context_event_handler"
|
|
9
|
+
require_relative "default_variable_parser"
|
|
10
|
+
require_relative "default_audience_deserializer"
|
|
11
|
+
|
|
3
12
|
class ABSmartlyConfig
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
13
|
+
extend Forwardable
|
|
14
|
+
|
|
15
|
+
attr_accessor :scheduler
|
|
16
|
+
|
|
17
|
+
attr_writer :context_data_provider, :context_event_handler, :audience_deserializer, :variable_parser, :client
|
|
18
|
+
|
|
19
|
+
attr_reader :client_config, :context_event_logger
|
|
20
|
+
|
|
21
|
+
def_delegators :@client_config, :endpoint, :api_key, :application, :environment
|
|
22
|
+
def_delegators :@client_config, :connect_timeout, :connection_request_timeout, :retry_interval, :max_retries
|
|
23
|
+
|
|
7
24
|
def self.create
|
|
8
|
-
|
|
25
|
+
new
|
|
9
26
|
end
|
|
10
27
|
|
|
11
|
-
def
|
|
12
|
-
@
|
|
13
|
-
self
|
|
28
|
+
def initialize
|
|
29
|
+
@client_config = ClientConfig.new
|
|
14
30
|
end
|
|
15
31
|
|
|
16
|
-
def
|
|
17
|
-
|
|
18
|
-
|
|
32
|
+
def validate!
|
|
33
|
+
raise ArgumentError.new("event logger not configured") if context_event_logger.nil?
|
|
34
|
+
raise ArgumentError.new("failed to initialize client") if client.nil?
|
|
35
|
+
raise ArgumentError.new("failed to initialize context_data_provider") if context_data_provider.nil?
|
|
19
36
|
end
|
|
20
37
|
|
|
21
|
-
def
|
|
22
|
-
|
|
38
|
+
def context_event_logger=(context_event_logger)
|
|
39
|
+
if context_event_logger.is_a?(Proc)
|
|
40
|
+
@context_event_logger = ContextEventLoggerCallback.new(context_event_logger)
|
|
41
|
+
else
|
|
42
|
+
@context_event_logger = context_event_logger
|
|
43
|
+
end
|
|
23
44
|
end
|
|
24
45
|
|
|
25
|
-
def variable_parser
|
|
26
|
-
@variable_parser
|
|
27
|
-
self
|
|
46
|
+
def variable_parser
|
|
47
|
+
@variable_parser ||= DefaultVariableParser.new
|
|
28
48
|
end
|
|
29
49
|
|
|
30
|
-
def
|
|
31
|
-
@
|
|
32
|
-
self
|
|
50
|
+
def audience_deserializer
|
|
51
|
+
@audience_deserializer ||= DefaultAudienceDeserializer.new
|
|
33
52
|
end
|
|
34
53
|
|
|
35
|
-
def
|
|
36
|
-
@
|
|
37
|
-
self
|
|
54
|
+
def context_data_provider
|
|
55
|
+
@context_data_provider ||= DefaultContextDataProvider.new(client)
|
|
38
56
|
end
|
|
39
57
|
|
|
40
|
-
def
|
|
41
|
-
@
|
|
42
|
-
self
|
|
58
|
+
def context_event_handler
|
|
59
|
+
@context_event_handler ||= DefaultContextEventHandler.new(client)
|
|
43
60
|
end
|
|
44
61
|
|
|
45
|
-
def client
|
|
46
|
-
@client
|
|
47
|
-
self
|
|
62
|
+
def client
|
|
63
|
+
@client ||= Client.new(client_config)
|
|
48
64
|
end
|
|
49
65
|
end
|
data/lib/absmartly/version.rb
CHANGED
data/lib/absmartly.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "absmartly/version"
|
|
4
|
-
require_relative "absmartly/variant_assigner"
|
|
5
4
|
require_relative "a_b_smartly"
|
|
6
5
|
require_relative "a_b_smartly_config"
|
|
7
6
|
require_relative "client"
|
|
@@ -9,16 +8,16 @@ require_relative "client_config"
|
|
|
9
8
|
require_relative "context_config"
|
|
10
9
|
|
|
11
10
|
module Absmartly
|
|
12
|
-
@@init_config = nil
|
|
13
|
-
|
|
14
11
|
class Error < StandardError
|
|
15
12
|
end
|
|
16
13
|
|
|
17
14
|
class << self
|
|
18
|
-
|
|
15
|
+
MUTEX = Thread::Mutex.new
|
|
19
16
|
|
|
20
17
|
def configure_client
|
|
21
|
-
yield
|
|
18
|
+
yield sdk_config
|
|
19
|
+
|
|
20
|
+
sdk_config.validate!
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
def create
|
|
@@ -33,24 +32,23 @@ module Absmartly
|
|
|
33
32
|
sdk.create_context(context_config)
|
|
34
33
|
end
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@client_config.endpoint = @endpoint
|
|
40
|
-
@client_config.api_key = @api_key
|
|
41
|
-
@client_config.application = @application
|
|
42
|
-
@client_config.environment = @environment
|
|
43
|
-
@client_config
|
|
44
|
-
end
|
|
35
|
+
def create_context_with(context_config, data)
|
|
36
|
+
sdk.create_context_with(context_config, data)
|
|
37
|
+
end
|
|
45
38
|
|
|
39
|
+
def context_data
|
|
40
|
+
sdk.context_data
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private_constant :MUTEX
|
|
44
|
+
|
|
45
|
+
private
|
|
46
46
|
def sdk_config
|
|
47
|
-
@sdk_config
|
|
48
|
-
@sdk_config.client = Client.create(client_config)
|
|
49
|
-
@sdk_config
|
|
47
|
+
MUTEX.synchronize { @sdk_config ||= ABSmartlyConfig.create }
|
|
50
48
|
end
|
|
51
49
|
|
|
52
50
|
def sdk
|
|
53
|
-
@sdk ||= create
|
|
51
|
+
MUTEX.synchronize { @sdk ||= create }
|
|
54
52
|
end
|
|
55
53
|
end
|
|
56
54
|
end
|
data/lib/client.rb
CHANGED
|
@@ -1,80 +1,49 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "forwardable"
|
|
3
4
|
require_relative "default_http_client"
|
|
4
5
|
require_relative "default_http_client_config"
|
|
5
6
|
require_relative "default_context_data_deserializer"
|
|
6
7
|
require_relative "default_context_event_serializer"
|
|
7
8
|
|
|
8
9
|
class Client
|
|
9
|
-
|
|
10
|
-
attr_reader :data_future, :promise, :exception
|
|
10
|
+
extend Forwardable
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def initialize(config = nil, http_client = nil)
|
|
17
|
-
endpoint = config.endpoint
|
|
18
|
-
raise ArgumentError.new("Missing Endpoint configuration") if endpoint.nil? || endpoint.empty?
|
|
19
|
-
|
|
20
|
-
api_key = config.api_key
|
|
21
|
-
raise ArgumentError.new("Missing APIKey configuration") if api_key.nil? || api_key.empty?
|
|
22
|
-
|
|
23
|
-
application = config.application
|
|
24
|
-
raise ArgumentError.new("Missing Application configuration") if application.nil? || application.empty?
|
|
25
|
-
|
|
26
|
-
environment = config.environment
|
|
27
|
-
raise ArgumentError.new("Missing Environment configuration") if environment.nil? || environment.empty?
|
|
12
|
+
attr_accessor :http_client
|
|
13
|
+
attr_reader :config, :data_future, :promise, :exception
|
|
28
14
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@serializer = config.context_event_serializer
|
|
33
|
-
@executor = config.executor
|
|
15
|
+
def_delegators :@config, :url, :query, :headers, :deserializer, :serializer
|
|
16
|
+
def_delegator :@http_client, :close
|
|
17
|
+
def_delegator :@promise, :success?
|
|
34
18
|
|
|
35
|
-
|
|
36
|
-
|
|
19
|
+
def self.create(config = nil, http_client = nil)
|
|
20
|
+
new(config, http_client)
|
|
21
|
+
end
|
|
37
22
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"X-Application": application,
|
|
42
|
-
"X-Environment": environment,
|
|
43
|
-
"X-Application-Version": "0",
|
|
44
|
-
"X-Agent": "absmartly-ruby-sdk"
|
|
45
|
-
}
|
|
23
|
+
def initialize(config = nil, http_client = nil)
|
|
24
|
+
@config = config || ClientConfig.new
|
|
25
|
+
@config.validate!
|
|
46
26
|
|
|
47
|
-
@
|
|
48
|
-
"application": application,
|
|
49
|
-
"environment": environment
|
|
50
|
-
}
|
|
27
|
+
@http_client = http_client || DefaultHttpClient.create(@config.http_client_config)
|
|
51
28
|
end
|
|
52
29
|
|
|
53
30
|
def context_data
|
|
54
|
-
@promise =
|
|
31
|
+
@promise = http_client.get(config.url, config.query, config.headers)
|
|
55
32
|
unless @promise.success?
|
|
56
33
|
@exception = Exception.new(@promise.body)
|
|
57
34
|
return self
|
|
58
35
|
end
|
|
59
36
|
|
|
60
37
|
content = (@promise.body || {}).to_s
|
|
61
|
-
@data_future =
|
|
38
|
+
@data_future = deserializer.deserialize(content, 0, content.size)
|
|
62
39
|
self
|
|
63
40
|
end
|
|
64
41
|
|
|
65
42
|
def publish(event)
|
|
66
|
-
content =
|
|
67
|
-
response =
|
|
43
|
+
content = serializer.serialize(event)
|
|
44
|
+
response = http_client.put(config.url, nil, config.headers, content)
|
|
68
45
|
return Exception.new(response.body) unless response.success?
|
|
69
46
|
|
|
70
47
|
response
|
|
71
48
|
end
|
|
72
|
-
|
|
73
|
-
def close
|
|
74
|
-
@http_client.close
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def success?
|
|
78
|
-
@promise.success?
|
|
79
|
-
end
|
|
80
49
|
end
|
data/lib/client_config.rb
CHANGED
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "forwardable"
|
|
4
|
+
require_relative "default_context_data_deserializer"
|
|
5
|
+
require_relative "default_context_event_serializer"
|
|
6
|
+
require_relative "default_http_client_config"
|
|
7
|
+
|
|
3
8
|
class ClientConfig
|
|
4
|
-
|
|
5
|
-
|
|
9
|
+
extend Forwardable
|
|
10
|
+
|
|
11
|
+
attr_accessor :endpoint, :api_key, :environment, :application
|
|
12
|
+
|
|
13
|
+
attr_reader :http_client_config
|
|
14
|
+
|
|
15
|
+
attr_writer :context_data_deserializer, :context_event_serializer
|
|
16
|
+
|
|
17
|
+
def_delegators :@http_client_config, :connect_timeout, :connection_request_timeout, :retry_interval, :max_retries
|
|
6
18
|
|
|
7
|
-
def self.create
|
|
8
|
-
|
|
19
|
+
def self.create(endpoint: nil, environment: nil, application: nil, api_key: nil)
|
|
20
|
+
new(endpoint: endpoint, environment: environment, application: application, api_key: api_key)
|
|
9
21
|
end
|
|
10
22
|
|
|
11
23
|
def self.create_from_properties(properties, prefix)
|
|
12
24
|
properties = properties.transform_keys(&:to_sym)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
create(
|
|
26
|
+
endpoint: properties["#{prefix}endpoint".to_sym],
|
|
27
|
+
environment: properties["#{prefix}environment".to_sym],
|
|
28
|
+
application: properties["#{prefix}application".to_sym],
|
|
29
|
+
api_key: properties["#{prefix}apikey".to_sym]
|
|
30
|
+
)
|
|
19
31
|
end
|
|
20
32
|
|
|
21
33
|
def initialize(endpoint: nil, environment: nil, application: nil, api_key: nil)
|
|
@@ -23,21 +35,60 @@ class ClientConfig
|
|
|
23
35
|
@environment = environment
|
|
24
36
|
@application = application
|
|
25
37
|
@api_key = api_key
|
|
38
|
+
|
|
39
|
+
@http_client_config = DefaultHttpClientConfig.new
|
|
26
40
|
end
|
|
27
41
|
|
|
28
42
|
def context_data_deserializer
|
|
29
|
-
@
|
|
43
|
+
@context_data_deserializer ||= DefaultContextDataDeserializer.new
|
|
30
44
|
end
|
|
31
45
|
|
|
32
|
-
def
|
|
33
|
-
@
|
|
46
|
+
def context_event_serializer
|
|
47
|
+
@context_event_serializer ||= DefaultContextEventSerializer.new
|
|
34
48
|
end
|
|
35
49
|
|
|
36
|
-
def
|
|
37
|
-
@
|
|
50
|
+
def deserializer=(deserializer)
|
|
51
|
+
@context_data_deserializer = deserializer
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def serializer=(serializer)
|
|
55
|
+
@context_event_serializer = serializer
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def deserializer
|
|
59
|
+
context_data_deserializer
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def serializer
|
|
63
|
+
context_event_serializer
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def url
|
|
67
|
+
@url ||= "#{endpoint}/context"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def headers
|
|
71
|
+
@headers ||= {
|
|
72
|
+
"Content-Type": "application/json",
|
|
73
|
+
"X-API-Key": api_key,
|
|
74
|
+
"X-Application": application,
|
|
75
|
+
"X-Environment": environment,
|
|
76
|
+
"X-Application-Version": "0",
|
|
77
|
+
"X-Agent": "absmartly-ruby-sdk"
|
|
78
|
+
}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def query
|
|
82
|
+
@query ||= {
|
|
83
|
+
"application": application,
|
|
84
|
+
"environment": environment
|
|
85
|
+
}
|
|
38
86
|
end
|
|
39
87
|
|
|
40
|
-
def
|
|
41
|
-
|
|
88
|
+
def validate!
|
|
89
|
+
raise ArgumentError.new("Missing Endpoint configuration") if endpoint.nil? || endpoint.empty?
|
|
90
|
+
raise ArgumentError.new("Missing APIKey configuration") if api_key.nil? || api_key.empty?
|
|
91
|
+
raise ArgumentError.new("Missing Application configuration") if application.nil? || application.empty?
|
|
92
|
+
raise ArgumentError.new("Missing Environment configuration") if environment.nil? || environment.empty?
|
|
42
93
|
end
|
|
43
94
|
end
|
data/lib/context.rb
CHANGED
|
@@ -10,7 +10,7 @@ require_relative "json/publish_event"
|
|
|
10
10
|
require_relative "json/goal_achievement"
|
|
11
11
|
|
|
12
12
|
class Context
|
|
13
|
-
attr_reader :
|
|
13
|
+
attr_reader :pending_count
|
|
14
14
|
|
|
15
15
|
def self.create(clock, config, data_future, data_provider,
|
|
16
16
|
event_handler, event_logger, variable_parser, audience_matcher)
|
|
@@ -114,6 +114,10 @@ class Context
|
|
|
114
114
|
def set_unit(unit_type, uid)
|
|
115
115
|
check_not_closed?
|
|
116
116
|
|
|
117
|
+
unless uid.is_a?(String) || uid.is_a?(Numeric)
|
|
118
|
+
raise IllegalStateException.new("Unit '#{unit_type}' UID is of unsupported type '#{uid.class}'. UID must be one of ['string', 'number']")
|
|
119
|
+
end
|
|
120
|
+
|
|
117
121
|
previous = @units[unit_type.to_sym]
|
|
118
122
|
if !previous.nil? && previous != uid
|
|
119
123
|
raise IllegalStateException.new("Unit '#{unit_type}' already set.")
|
|
@@ -541,7 +545,6 @@ class Context
|
|
|
541
545
|
@experimentCustomFieldValues[custom_field_value.name] = value
|
|
542
546
|
|
|
543
547
|
end
|
|
544
|
-
|
|
545
548
|
end
|
|
546
549
|
end
|
|
547
550
|
|
data/lib/context_config.rb
CHANGED
|
@@ -29,7 +29,8 @@ class ContextConfig
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def set_attributes(attributes)
|
|
32
|
-
@attributes
|
|
32
|
+
@attributes.merge!(attributes.transform_keys(&:to_sym))
|
|
33
|
+
self
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
def set_attribute(name, value)
|
|
@@ -68,11 +69,8 @@ class ContextConfig
|
|
|
68
69
|
@custom_assignments[experiment_name.to_sym]
|
|
69
70
|
end
|
|
70
71
|
|
|
71
|
-
|
|
72
72
|
def set_event_logger(event_logger)
|
|
73
73
|
@event_logger = event_logger
|
|
74
74
|
self
|
|
75
75
|
end
|
|
76
|
-
|
|
77
|
-
attr_reader :event_logger
|
|
78
76
|
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative "
|
|
3
|
+
require_relative "context_event_handler"
|
|
4
4
|
|
|
5
|
-
class DefaultContextEventHandler <
|
|
5
|
+
class DefaultContextEventHandler < ContextEventHandler
|
|
6
6
|
attr_accessor :client
|
|
7
7
|
|
|
8
8
|
def initialize(client)
|
data/lib/default_http_client.rb
CHANGED
metadata
CHANGED
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: absmartly-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- absmartly
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: base64
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.2'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.2'
|
|
13
26
|
- !ruby/object:Gem::Dependency
|
|
14
27
|
name: faraday
|
|
15
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -70,12 +83,10 @@ files:
|
|
|
70
83
|
- LICENSE.txt
|
|
71
84
|
- README.md
|
|
72
85
|
- Rakefile
|
|
73
|
-
- absmartly.gemspec
|
|
74
86
|
- example/example.rb
|
|
75
87
|
- lib/a_b_smartly.rb
|
|
76
88
|
- lib/a_b_smartly_config.rb
|
|
77
89
|
- lib/absmartly.rb
|
|
78
|
-
- lib/absmartly/variant_assigner.rb
|
|
79
90
|
- lib/absmartly/version.rb
|
|
80
91
|
- lib/audience_deserializer.rb
|
|
81
92
|
- lib/audience_matcher.rb
|
|
@@ -142,7 +153,6 @@ metadata:
|
|
|
142
153
|
homepage_uri: https://github.com/absmartly/ruby-sdk
|
|
143
154
|
source_code_uri: https://github.com/absmartly/ruby-sdk
|
|
144
155
|
changelog_uri: https://github.com/absmartly/ruby-sdk
|
|
145
|
-
post_install_message:
|
|
146
156
|
rdoc_options: []
|
|
147
157
|
require_paths:
|
|
148
158
|
- lib
|
|
@@ -157,8 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
157
167
|
- !ruby/object:Gem::Version
|
|
158
168
|
version: '0'
|
|
159
169
|
requirements: []
|
|
160
|
-
rubygems_version: 3.
|
|
161
|
-
signing_key:
|
|
170
|
+
rubygems_version: 3.7.1
|
|
162
171
|
specification_version: 4
|
|
163
172
|
summary: Absmartly gem
|
|
164
173
|
test_files: []
|
data/absmartly.gemspec
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# $:.push File.expand_path("../lib", __FILE__)
|
|
4
|
-
require File.expand_path("lib/absmartly/version", __dir__)
|
|
5
|
-
Gem::Specification.new do |spec|
|
|
6
|
-
spec.name = "absmartly-sdk"
|
|
7
|
-
spec.version = Absmartly::VERSION
|
|
8
|
-
spec.authors = ["absmartly"]
|
|
9
|
-
spec.email = ["sdks@absmartly.com"]
|
|
10
|
-
|
|
11
|
-
spec.summary = "Absmartly gem"
|
|
12
|
-
spec.description = "Absmartly gem"
|
|
13
|
-
|
|
14
|
-
spec.homepage = "https://github.com/absmartly/ruby-sdk"
|
|
15
|
-
|
|
16
|
-
spec.license = "MIT"
|
|
17
|
-
spec.required_ruby_version = ">= 2.7.0"
|
|
18
|
-
spec.extra_rdoc_files = ["README.md"]
|
|
19
|
-
|
|
20
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
21
|
-
spec.metadata["source_code_uri"] = "https://github.com/absmartly/ruby-sdk"
|
|
22
|
-
spec.metadata["changelog_uri"] = "https://github.com/absmartly/ruby-sdk"
|
|
23
|
-
|
|
24
|
-
# Specify which files should be added to the gem when it is released.
|
|
25
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
26
|
-
spec.files = Dir.chdir(__dir__) do
|
|
27
|
-
`git ls-files -z`.split("\x0").reject do |f|
|
|
28
|
-
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
spec.bindir = "exe"
|
|
32
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
33
|
-
spec.require_paths = ["lib"]
|
|
34
|
-
|
|
35
|
-
spec.add_dependency "faraday", "~> 2.0"
|
|
36
|
-
spec.add_dependency "faraday-retry", "~> 2.0"
|
|
37
|
-
spec.add_dependency "murmurhash3", "~> 0.1.7"
|
|
38
|
-
|
|
39
|
-
# For more information and examples about making a new gem, check out our
|
|
40
|
-
# guide at: https://bundler.io/guides/creating_gem.html
|
|
41
|
-
end
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "murmurhash3"
|
|
4
|
-
|
|
5
|
-
module Absmartly
|
|
6
|
-
# VariantAssigner
|
|
7
|
-
class VariantAssigner
|
|
8
|
-
def initialize(_unit)
|
|
9
|
-
# this._unitHash = murmur3_32(stringToUint8Array(unit).buffer);
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def assign(split, seed_hi, seed_lo)
|
|
13
|
-
prob = probability(seed_hi, seed_lo)
|
|
14
|
-
chooseVariant(split, prob)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
# private
|
|
18
|
-
|
|
19
|
-
# def chooseVariant(split, prob)
|
|
20
|
-
#
|
|
21
|
-
# end
|
|
22
|
-
#
|
|
23
|
-
# def probability(seedHi, seedLo)
|
|
24
|
-
# const key = this._unitHash;
|
|
25
|
-
# const buffer = new ArrayBuffer(12)
|
|
26
|
-
# const view = new DataView(buffer)
|
|
27
|
-
# view.setUint32(0, seedLo, true)
|
|
28
|
-
# view.setUint32(4, seedHi, true)
|
|
29
|
-
# view.setUint32(8, key, true)
|
|
30
|
-
#
|
|
31
|
-
# murmur3_32(buffer) * (1.0 / 0xffffffff)
|
|
32
|
-
# end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
# DataView.new(new_bytes_buffer, src_offset, new_bytes.length)
|