absmartly-sdk 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +180 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +5 -0
  6. data/CODE_OF_CONDUCT.md +84 -0
  7. data/Gemfile +21 -0
  8. data/Gemfile.lock +92 -0
  9. data/LICENSE.txt +21 -0
  10. data/README +180 -0
  11. data/Rakefile +12 -0
  12. data/example/example.rb +48 -0
  13. data/lib/a_b_smartly.rb +92 -0
  14. data/lib/a_b_smartly_config.rb +49 -0
  15. data/lib/absmartly/md5.rb +178 -0
  16. data/lib/absmartly/variant_assigner.rb +36 -0
  17. data/lib/absmartly/version.rb +5 -0
  18. data/lib/absmartly.rb +57 -0
  19. data/lib/audience_deserializer.rb +8 -0
  20. data/lib/audience_matcher.rb +38 -0
  21. data/lib/client.rb +80 -0
  22. data/lib/client_config.rb +43 -0
  23. data/lib/context.rb +528 -0
  24. data/lib/context_config.rb +70 -0
  25. data/lib/context_data_deserializer.rb +8 -0
  26. data/lib/context_data_provider.rb +8 -0
  27. data/lib/context_event_handler.rb +8 -0
  28. data/lib/context_event_logger.rb +9 -0
  29. data/lib/context_event_serializer.rb +8 -0
  30. data/lib/default_audience_deserializer.rb +13 -0
  31. data/lib/default_context_data_deserializer.rb +16 -0
  32. data/lib/default_context_data_provider.rb +15 -0
  33. data/lib/default_context_event_handler.rb +15 -0
  34. data/lib/default_context_event_serializer.rb +58 -0
  35. data/lib/default_http_client.rb +61 -0
  36. data/lib/default_http_client_config.rb +19 -0
  37. data/lib/default_variable_parser.rb +13 -0
  38. data/lib/hashing.rb +9 -0
  39. data/lib/http_client.rb +20 -0
  40. data/lib/json/attribute.rb +30 -0
  41. data/lib/json/context_data.rb +31 -0
  42. data/lib/json/experiment.rb +83 -0
  43. data/lib/json/experiment_application.rb +27 -0
  44. data/lib/json/experiment_variant.rb +29 -0
  45. data/lib/json/exposure.rb +60 -0
  46. data/lib/json/goal_achievement.rb +32 -0
  47. data/lib/json/publish_event.rb +42 -0
  48. data/lib/json/unit.rb +30 -0
  49. data/lib/json_expr/evaluator.rb +27 -0
  50. data/lib/json_expr/expr_evaluator.rb +122 -0
  51. data/lib/json_expr/json_expr.rb +37 -0
  52. data/lib/json_expr/operator.rb +8 -0
  53. data/lib/json_expr/operators/and_combinator.rb +14 -0
  54. data/lib/json_expr/operators/binary_operator.rb +22 -0
  55. data/lib/json_expr/operators/boolean_combinator.rb +15 -0
  56. data/lib/json_expr/operators/equals_operator.rb +12 -0
  57. data/lib/json_expr/operators/greater_than_operator.rb +12 -0
  58. data/lib/json_expr/operators/greater_than_or_equal_operator.rb +12 -0
  59. data/lib/json_expr/operators/in_operator.rb +23 -0
  60. data/lib/json_expr/operators/less_than_operator.rb +12 -0
  61. data/lib/json_expr/operators/less_than_or_equal_operator.rb +12 -0
  62. data/lib/json_expr/operators/match_operator.rb +17 -0
  63. data/lib/json_expr/operators/nil_operator.rb +11 -0
  64. data/lib/json_expr/operators/not_operator.rb +11 -0
  65. data/lib/json_expr/operators/or_combinator.rb +14 -0
  66. data/lib/json_expr/operators/unary_operator.rb +13 -0
  67. data/lib/json_expr/operators/value_operator.rb +11 -0
  68. data/lib/json_expr/operators/var_operator.rb +21 -0
  69. data/lib/scheduled_executor_service.rb +8 -0
  70. data/lib/scheduled_thread_pool_executor.rb +14 -0
  71. data/lib/string.rb +30 -0
  72. data/lib/variable_parser.rb +8 -0
  73. data/lib/variant_assigner.rb +47 -0
  74. data/sig/absmartly.rbs +4 -0
  75. metadata +120 -0
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+ require_relative "context"
5
+ require_relative "audience_matcher"
6
+ require_relative "default_context_data_provider"
7
+ require_relative "default_context_event_handler"
8
+ require_relative "default_variable_parser"
9
+ require_relative "default_audience_deserializer"
10
+ require_relative "scheduled_thread_pool_executor"
11
+
12
+ class ABSmartly
13
+ attr_accessor :context_data_provider, :context_event_handler,
14
+ :variable_parser, :scheduler, :context_event_logger,
15
+ :audience_deserializer, :client
16
+
17
+ def self.configure_client(&block)
18
+ @@init_http = block
19
+ end
20
+
21
+ def self.create(config)
22
+ ABSmartly.new(config)
23
+ end
24
+
25
+ def initialize(config)
26
+ @@init_http = nil
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
46
+
47
+ if @variable_parser.nil?
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
57
+ end
58
+
59
+ def create_context(config)
60
+ validate_params(config)
61
+ Context.create(get_utc_format, config, @scheduler, @context_data_provider.context_data,
62
+ @context_data_provider, @context_event_handler, @context_event_logger, @variable_parser,
63
+ AudienceMatcher.new(@audience_deserializer))
64
+ end
65
+
66
+ def create_context_with(config, data)
67
+ Context.create(get_utc_format, config, scheduler, data,
68
+ @context_data_provider, @context_event_handler, @context_event_logger, @variable_parser,
69
+ AudienceMatcher.new(@audience_deserializer))
70
+ end
71
+
72
+ def context_data
73
+ @context_data_provider.context_data
74
+ end
75
+
76
+ private
77
+ def get_utc_format
78
+ Time.now.utc.iso8601(3)
79
+ 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
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ABSmartlyConfig
4
+ attr_accessor :context_data_provider, :context_event_handler,
5
+ :variable_parser, :scheduler, :context_event_logger,
6
+ :client, :audience_deserializer
7
+ def self.create
8
+ ABSmartlyConfig.new
9
+ end
10
+
11
+ def context_data_provider=(context_data_provider)
12
+ @context_data_provider = context_data_provider
13
+ self
14
+ end
15
+
16
+ def context_event_handler=(context_event_handler)
17
+ @context_event_handler = context_event_handler
18
+ self
19
+ end
20
+
21
+ def context_data_provide
22
+ @context_event_handler
23
+ end
24
+
25
+ def variable_parser=(variable_parser)
26
+ @variable_parser = variable_parser
27
+ self
28
+ end
29
+
30
+ def scheduler=(scheduler)
31
+ @scheduler = scheduler
32
+ self
33
+ end
34
+
35
+ def context_event_logger=(context_event_logger)
36
+ @context_event_logger = context_event_logger
37
+ self
38
+ end
39
+
40
+ def audience_deserializer=(audience_deserializer)
41
+ @audience_deserializer = audience_deserializer
42
+ self
43
+ end
44
+
45
+ def client=(client)
46
+ @client = client
47
+ self
48
+ end
49
+ end
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "arraybuffer"
4
+
5
+ module Absmartly
6
+ class Md5
7
+ def self.cmn (q, a, b, x, s, t)
8
+ a = a + q + (x >> 0) + t # TODO >>>
9
+ ((a << s) | (a >> (32 - s))) + b # TODO >>>
10
+ end
11
+
12
+ def self.ff(a, b, c, d, x, s, t)
13
+ cmn((b & c) | (~b & d), a, b, x, s, t)
14
+ end
15
+
16
+ def self.gg(a, b, c, d, x, s, t)
17
+ cmn((b & d) | (c & ~d), a, b, x, s, t)
18
+ end
19
+
20
+ def self.hh(a, b, c, d, x, s, t)
21
+ cmn(b ^ c ^ d, a, b, x, s, t)
22
+ end
23
+
24
+ def self.ii(a, b, c, d, x, s, t)
25
+ cmn(c ^ (b | ~d), a, b, x, s, t)
26
+ end
27
+
28
+ def self.md5_cycle(x, k)
29
+ a = x[0]
30
+ b = x[1]
31
+ c = x[2]
32
+ d = x[3]
33
+
34
+ a = ff(a, b, c, d, k[0], 7, -680876936)
35
+ d = ff(d, a, b, c, k[1], 12, -389564586)
36
+ c = ff(c, d, a, b, k[2], 17, 606105819)
37
+ b = ff(b, c, d, a, k[3], 22, -1044525330)
38
+ a = ff(a, b, c, d, k[4], 7, -176418897)
39
+ d = ff(d, a, b, c, k[5], 12, 1200080426)
40
+ c = ff(c, d, a, b, k[6], 17, -1473231341)
41
+ b = ff(b, c, d, a, k[7], 22, -45705983)
42
+ a = ff(a, b, c, d, k[8], 7, 1770035416)
43
+ d = ff(d, a, b, c, k[9], 12, -1958414417)
44
+ c = ff(c, d, a, b, k[10], 17, -42063)
45
+ b = ff(b, c, d, a, k[11], 22, -1990404162)
46
+ a = ff(a, b, c, d, k[12], 7, 1804603682)
47
+ d = ff(d, a, b, c, k[13], 12, -40341101)
48
+ c = ff(c, d, a, b, k[14], 17, -1502002290)
49
+ b = ff(b, c, d, a, k[15], 22, 1236535329)
50
+
51
+ a = gg(a, b, c, d, k[1], 5, -165796510)
52
+ d = gg(d, a, b, c, k[6], 9, -1069501632)
53
+ c = gg(c, d, a, b, k[11], 14, 643717713)
54
+ b = gg(b, c, d, a, k[0], 20, -373897302)
55
+ a = gg(a, b, c, d, k[5], 5, -701558691)
56
+ d = gg(d, a, b, c, k[10], 9, 38016083)
57
+ c = gg(c, d, a, b, k[15], 14, -660478335)
58
+ b = gg(b, c, d, a, k[4], 20, -405537848)
59
+ a = gg(a, b, c, d, k[9], 5, 568446438)
60
+ d = gg(d, a, b, c, k[14], 9, -1019803690)
61
+ c = gg(c, d, a, b, k[3], 14, -187363961)
62
+ b = gg(b, c, d, a, k[8], 20, 1163531501)
63
+ a = gg(a, b, c, d, k[13], 5, -1444681467)
64
+ d = gg(d, a, b, c, k[2], 9, -51403784)
65
+ c = gg(c, d, a, b, k[7], 14, 1735328473)
66
+ b = gg(b, c, d, a, k[12], 20, -1926607734)
67
+
68
+ a = hh(a, b, c, d, k[5], 4, -378558)
69
+ d = hh(d, a, b, c, k[8], 11, -2022574463)
70
+ c = hh(c, d, a, b, k[11], 16, 1839030562)
71
+ b = hh(b, c, d, a, k[14], 23, -35309556)
72
+ a = hh(a, b, c, d, k[1], 4, -1530992060)
73
+ d = hh(d, a, b, c, k[4], 11, 1272893353)
74
+ c = hh(c, d, a, b, k[7], 16, -155497632)
75
+ b = hh(b, c, d, a, k[10], 23, -1094730640)
76
+ a = hh(a, b, c, d, k[13], 4, 681279174)
77
+ d = hh(d, a, b, c, k[0], 11, -358537222)
78
+ c = hh(c, d, a, b, k[3], 16, -722521979)
79
+ b = hh(b, c, d, a, k[6], 23, 76029189)
80
+ a = hh(a, b, c, d, k[9], 4, -640364487)
81
+ d = hh(d, a, b, c, k[12], 11, -421815835)
82
+ c = hh(c, d, a, b, k[15], 16, 530742520)
83
+ b = hh(b, c, d, a, k[2], 23, -995338651)
84
+
85
+ a = ii(a, b, c, d, k[0], 6, -198630844)
86
+ d = ii(d, a, b, c, k[7], 10, 1126891415)
87
+ c = ii(c, d, a, b, k[14], 15, -1416354905)
88
+ b = ii(b, c, d, a, k[5], 21, -57434055)
89
+ a = ii(a, b, c, d, k[12], 6, 1700485571)
90
+ d = ii(d, a, b, c, k[3], 10, -1894986606)
91
+ c = ii(c, d, a, b, k[10], 15, -1051523)
92
+ b = ii(b, c, d, a, k[1], 21, -2054922799)
93
+ a = ii(a, b, c, d, k[8], 6, 1873313359)
94
+ d = ii(d, a, b, c, k[15], 10, -30611744)
95
+ c = ii(c, d, a, b, k[6], 15, -1560198380)
96
+ b = ii(b, c, d, a, k[13], 21, 1309151649)
97
+ a = ii(a, b, c, d, k[4], 6, -145523070)
98
+ d = ii(d, a, b, c, k[11], 10, -1120210379)
99
+ c = ii(c, d, a, b, k[2], 15, 718787259)
100
+ b = ii(b, c, d, a, k[9], 21, -343485551)
101
+
102
+ x[0] = (a + x[0]) >> 0 # TODO >>>
103
+ x[1] = (b + x[1]) >> 0 # TODO >>>
104
+ x[2] = (c + x[2]) >> 0 # TODO >>>
105
+ x[3] = (d + x[3]) >> 0 # TODO >>>
106
+ end
107
+
108
+ def self.process(new_bytes_buffer)
109
+ key = DataView.new new_bytes_buffer, 0, new_bytes_buffer.length
110
+
111
+ l = new_bytes_buffer.length
112
+ n = l & ~63
113
+ i = 0
114
+ block = ArrayBuffer.new(16)
115
+ state = ArrayBuffer.new(4)
116
+
117
+ [1732584193, -271733879, -1732584194, 271733878].each_with_index do |el, index|
118
+ state[index] = el
119
+ end
120
+
121
+ (0...n).step(64).each do |val|
122
+ (0...16).each do |w|
123
+ block[w] = key.getU32(val + (w << 2))
124
+ end
125
+
126
+ md5_cycle(state, block)
127
+
128
+ i += 64
129
+ end
130
+
131
+ w = 0
132
+ m = l & ~3
133
+
134
+ (i...m).step(4).each do |val|
135
+ block[w] = key.getU32(val)
136
+ w += 1
137
+ end
138
+
139
+ p = l & 3
140
+
141
+ case p
142
+ when 3
143
+ block[w] = 0x80000000 | key.getU8(i) | (key.getU8(i + 1) << 8) | (key.getU8(i + 2) << 16)
144
+ w += 1
145
+ when 2
146
+ block[w] = 0x800000 | key.getUint8(i) | (key.getUint8(i + 1) << 8)
147
+ w += 1
148
+
149
+ when 1
150
+ block[w] = 0x8000 | key.getUint8(i)
151
+ w += 1
152
+
153
+ else
154
+ block[w] = 0x80
155
+ w += 1
156
+
157
+ end
158
+
159
+ if w > 14
160
+ (w...16).each do |v|
161
+ block[v] = 0
162
+ end
163
+
164
+ md5_cycle(state, block)
165
+ w = 0
166
+ end
167
+
168
+ (w...16).each do |v|
169
+ block[v] = 0
170
+ end
171
+
172
+ block[14] = l << 3
173
+ md5_cycle(state, block)
174
+
175
+ state
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "arraybuffer"
4
+ require "murmurhash3"
5
+
6
+ module Absmartly
7
+ # VariantAssigner
8
+ class VariantAssigner
9
+ def initialize(_unit)
10
+ # this._unitHash = murmur3_32(stringToUint8Array(unit).buffer);
11
+ end
12
+
13
+ def assign(split, seed_hi, seed_lo)
14
+ prob = probability(seed_hi, seed_lo)
15
+ chooseVariant(split, prob)
16
+ end
17
+
18
+ # private
19
+
20
+ # def chooseVariant(split, prob)
21
+ #
22
+ # end
23
+ #
24
+ # def probability(seedHi, seedLo)
25
+ # const key = this._unitHash;
26
+ # const buffer = new ArrayBuffer(12)
27
+ # const view = new DataView(buffer)
28
+ # view.setUint32(0, seedLo, true)
29
+ # view.setUint32(4, seedHi, true)
30
+ # view.setUint32(8, key, true)
31
+ #
32
+ # murmur3_32(buffer) * (1.0 / 0xffffffff)
33
+ # end
34
+ end
35
+ end
36
+ # DataView.new(new_bytes_buffer, src_offset, new_bytes.length)
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Absmartly
4
+ VERSION = "0.1.2"
5
+ end
data/lib/absmartly.rb ADDED
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "absmartly/version"
4
+ require_relative "absmartly/variant_assigner"
5
+ require_relative "absmartly/md5"
6
+ require_relative "a_b_smartly"
7
+ require_relative "a_b_smartly_config"
8
+ require_relative "client"
9
+ require_relative "client_config"
10
+ require_relative "context_config"
11
+
12
+ module Absmartly
13
+ @@init_config = nil
14
+
15
+ class Error < StandardError
16
+ end
17
+
18
+ class << self
19
+ attr_accessor :endpoint, :api_key, :application, :environment
20
+
21
+ def configure_client
22
+ yield self
23
+ end
24
+
25
+ def create
26
+ ABSmartly.create(sdk_config)
27
+ end
28
+
29
+ def create_context_config
30
+ ContextConfig.create
31
+ end
32
+
33
+ def create_context(context_config)
34
+ sdk.create_context(context_config)
35
+ end
36
+
37
+ private
38
+ def client_config
39
+ @client_config = ClientConfig.create
40
+ @client_config.endpoint = @endpoint
41
+ @client_config.api_key = @api_key
42
+ @client_config.application = @application
43
+ @client_config.environment = @environment
44
+ @client_config
45
+ end
46
+
47
+ def sdk_config
48
+ @sdk_config = ABSmartlyConfig.create
49
+ @sdk_config.client = Client.create(client_config)
50
+ @sdk_config
51
+ end
52
+
53
+ def sdk
54
+ @sdk ||= create
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AudienceDeserializer
4
+ # @interface method
5
+ def deserialize(bytes, offset, length)
6
+ raise NotImplementedError.new("You must implement deserialize method.")
7
+ end
8
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require_relative "json_expr/json_expr"
5
+
6
+ class AudienceMatcher
7
+ attr_accessor :deserializer, :json_expr
8
+
9
+ def initialize(deserializer)
10
+ @deserializer = deserializer
11
+ @json_expr = JsonExpr.new
12
+ end
13
+
14
+ class Result
15
+ attr_accessor :result
16
+
17
+ def initialize(result)
18
+ @result = result
19
+ end
20
+
21
+ def get
22
+ @result
23
+ end
24
+ end
25
+
26
+ def evaluate(audience, attributes)
27
+ audience_map = JSON.parse(audience, symbolize_names: true)
28
+
29
+ unless audience_map.nil?
30
+ filter = audience_map[:filter]
31
+ if filter.is_a?(Hash) || filter.is_a?(Array)
32
+ Result.new(@json_expr.evaluate_boolean_expr(filter, attributes))
33
+ end
34
+ end
35
+ rescue
36
+ nil
37
+ end
38
+ end
data/lib/client.rb ADDED
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "default_http_client"
4
+ require_relative "default_http_client_config"
5
+ require_relative "default_context_data_deserializer"
6
+ require_relative "default_context_event_serializer"
7
+
8
+ class Client
9
+ attr_accessor :url, :query, :headers, :http_client, :executor, :deserializer, :serializer
10
+ attr_reader :data_future, :promise, :exception
11
+
12
+ def self.create(config, http_client = nil)
13
+ Client.new(config, http_client || DefaultHttpClient.create(DefaultHttpClientConfig.create))
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?
28
+
29
+ @url = "#{endpoint}/context"
30
+ @http_client = http_client
31
+ @deserializer = config.context_data_deserializer
32
+ @serializer = config.context_event_serializer
33
+ @executor = config.executor
34
+
35
+ @deserializer = DefaultContextDataDeserializer.new if @deserializer.nil?
36
+ @serializer = DefaultContextEventSerializer.new if @serializer.nil?
37
+
38
+ @headers = {
39
+ "Content-Type": "application/json",
40
+ "X-API-Key": api_key,
41
+ "X-Application": application,
42
+ "X-Environment": environment,
43
+ "X-Application-Version": "0",
44
+ "X-Agent": "absmartly-ruby-sdk"
45
+ }
46
+
47
+ @query = {
48
+ "application": application,
49
+ "environment": environment
50
+ }
51
+ end
52
+
53
+ def context_data
54
+ @promise = @http_client.get(@url, @query, @headers)
55
+ unless @promise.success?
56
+ @exception = Exception.new(@promise.body)
57
+ return self
58
+ end
59
+
60
+ content = (@promise.body || {}).to_s
61
+ @data_future = @deserializer.deserialize(content, 0, content.size)
62
+ self
63
+ end
64
+
65
+ def publish(event)
66
+ content = @serializer.serialize(event)
67
+ response = @http_client.put(@url, nil, @headers, content)
68
+ return Exception.new(response.body) unless response.success?
69
+
70
+ response
71
+ end
72
+
73
+ def close
74
+ @http_client.close
75
+ end
76
+
77
+ def success?
78
+ @promise.success?
79
+ end
80
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ClientConfig
4
+ attr_accessor :endpoint, :api_key, :environment, :application, :deserializer,
5
+ :serializer, :executor
6
+
7
+ def self.create
8
+ ClientConfig.new
9
+ end
10
+
11
+ def self.create_from_properties(properties, prefix)
12
+ properties = properties.transform_keys(&:to_sym)
13
+ client_config = create
14
+ client_config.endpoint = properties["#{prefix}endpoint".to_sym]
15
+ client_config.environment = properties["#{prefix}environment".to_sym]
16
+ client_config.application = properties["#{prefix}application".to_sym]
17
+ client_config.api_key = properties["#{prefix}apikey".to_sym]
18
+ client_config
19
+ end
20
+
21
+ def initialize(endpoint: nil, environment: nil, application: nil, api_key: nil)
22
+ @endpoint = endpoint
23
+ @environment = environment
24
+ @application = application
25
+ @api_key = api_key
26
+ end
27
+
28
+ def context_data_deserializer
29
+ @deserializer
30
+ end
31
+
32
+ def context_data_deserializer=(deserializer)
33
+ @deserializer = deserializer
34
+ end
35
+
36
+ def context_event_serializer
37
+ @serializer
38
+ end
39
+
40
+ def context_event_serializer=(serializer)
41
+ @serializer = serializer
42
+ end
43
+ end