absmartly-sdk 0.1.2 → 1.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16d7c8f31de8bdbceddf60618c90ddfc81ab73381403d957a7bd8a3fbdb43d3a
4
- data.tar.gz: 2145b7d168f0e425164e1fcccb14d3efbd1ac4d91ddc3c5ebc120fca32734cdf
3
+ metadata.gz: 85cc6f9a1f752cedc113e346ddd7fbbe885e18a571d94cb4696fbeb65afcfaf3
4
+ data.tar.gz: 7a16ba9a23c51f82030beb5cc25e0bff6da063bacdecfef24d506a843d63c29d
5
5
  SHA512:
6
- metadata.gz: 840d40d52e3878321a7d08ebfe1bb38e9db8994a3296afc2d3de43383ca01b8b0cc0513a2a0e4480b679ef38a8c3edda3688bd0bbcbb7b5a82c39a7f979ba595
7
- data.tar.gz: cb15ab60ca2a4cd40e736b8b69b5a32b131f9a92ac8942cb3b48d16fb20b67915636035b30dd2b8d5c7039ec787509fcd3080773aa902fe23988742cce027269
6
+ metadata.gz: 7ce160a8e6898a17504f4292f87443ba8c8b18c15f953464ba04e16388a98dc091c73854cebc7e18fa0d6cce02be73969a5b3979d9a2e281913ce6753e592bca
7
+ data.tar.gz: 6e057f2dcdaa1a7d1b5916baf6f28eaec66b8240433d6c28ea776238e87b39f179ca0084f30ed7bef1dda372d7e8dc0a42b3e5bac090ebe8ad1ad6ea1edb0cc7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- absmartly (0.1.0)
4
+ absmartly-sdk (1.0.5)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -78,7 +78,7 @@ PLATFORMS
78
78
  x86_64-darwin-20
79
79
 
80
80
  DEPENDENCIES
81
- absmartly!
81
+ absmartly-sdk!
82
82
  arraybuffer
83
83
  byebug
84
84
  faraday
data/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # A/B Smartly SDK
2
+
3
+ A/B Smartly Ruby SDK
4
+
5
+ ## Compatibility
6
+
7
+ The A/B Smartly Ruby SDK is compatible with Ruby versions 2.7 and later. For the best performance and code readability, Ruby 3 or later is recommended. This SDK is being constantly tested with the nightly builds of Ruby, to ensure it is compatible with the latest Ruby version.
8
+
9
+
10
+ ## Getting Started
11
+
12
+ ### Install the SDK
13
+
14
+ Install the gem and add to the application's Gemfile by executing:
15
+
16
+ $ bundle add absmartly-sdk
17
+
18
+ If bundler is not being used to manage dependencies, install the gem by executing:
19
+
20
+ $ gem install absmartly-sdk
21
+
22
+ ## Import and Initialize the SDK
23
+
24
+ Once the SDK is installed, it can be initialized in your project.
25
+
26
+ ```ruby
27
+ Absmartly.configure_client do |config|
28
+ config.endpoint = "https://your-company.absmartly.io/v1"
29
+ config.api_key = "YOUR-API-KEY"
30
+ config.application = "website"
31
+ config.environment = "development"
32
+ end
33
+ ```
34
+
35
+ **SDK Options**
36
+
37
+ | Config | Type | Required? | Default | Description |
38
+ | :---------- | :----------------------------------- | :-------: | :-------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
39
+ | endpoint | `string` | ✅ | `undefined` | The URL to your API endpoint. Most commonly `"your-company.absmartly.io"` |
40
+ | apiKey | `string` | ✅ | `undefined` | Your API key which can be found on the Web Console. |
41
+ | environment | `"production"` or `"development"` | ✅ | `undefined` | The environment of the platform where the SDK is installed. Environments are created on the Web Console and should match the available environments in your infrastructure. |
42
+ | application | `string` | ✅ | `undefined` | The name of the application where the SDK is installed. Applications are created on the Web Console and should match the applications where your experiments will be running. |
43
+ | retries | `number` | ❌ | `5` | The number of retries before the SDK stops trying to connect. |
44
+ | timeout | `number` | ❌ | `3000` | An amount of time, in milliseconds, before the SDK will stop trying to connect. |
45
+ | eventLogger | `(context, eventName, data) => void` | ❌ | See "Using a Custom Event Logger" below | A callback function which runs after SDK events. |
46
+
47
+ ### Using a Custom Event Logger
48
+
49
+ The A/B Smartly SDK can be instantiated with an event logger used for all
50
+ contexts. In addition, an event logger can be specified when creating a
51
+ particular context, in the `[CONTEXT_CONFIG_VARIABLE]`.
52
+
53
+ ```
54
+ Custom Event Logger Code
55
+ ```
56
+
57
+ The data parameter depends on the type of event. Currently, the SDK logs the
58
+ following events:
59
+
60
+ | eventName | when | data |
61
+ | ------------ | ------------------------------------------------------- | -------------------------------------------- |
62
+ | `"error"` | `Context` receives an error | error object thrown |
63
+ | `"ready"` | `Context` turns ready | data used to initialize the context |
64
+ | `"refresh"` | `Context.refresh()` method succeeds | data used to refresh the context |
65
+ | `"publish"` | `Context.publish()` method succeeds | data sent to the A/B Smartly event collector |
66
+ | `"exposure"` | `Context.treatment()` method succeeds on first exposure | exposure data enqueued for publishing |
67
+ | `"goal"` | `Context.track()` method succeeds | goal data enqueued for publishing |
68
+ | `"close"` | `Context.close()` method succeeds the first time | nil |
69
+
70
+ ## Create a New Context Request
71
+
72
+
73
+ ```ruby
74
+ context_config = Absmartly.create_context_config
75
+ ```
76
+
77
+ **With Prefetched Data**
78
+
79
+ ```ruby
80
+ client_config = ClientConfig.new(
81
+ endpoint: 'https://your-company.absmartly.io/v1',
82
+ api_key: 'YOUR-API-KEY',
83
+ application: 'website',
84
+ environment: 'development')
85
+
86
+ sdk_config = ABSmartlyConfig.create
87
+ sdk_config.client = Client.create(client_config)
88
+
89
+ sdk = Absmartly.create(sdk_config)
90
+ ```
91
+
92
+ **Refreshing the Context with Fresh Experiment Data**
93
+
94
+ For long-running contexts, the context is usually created once when the
95
+ application is first started. However, any experiments being tracked in your
96
+ production code, but started after the context was created, will not be
97
+ triggered.
98
+
99
+ Alternatively, the `refresh` method can be called manually. The
100
+ `refresh` method pulls updated experiment data from the A/B
101
+ Smartly collector and will trigger recently started experiments when
102
+ `treatment` is called again.
103
+
104
+ **Setting Extra Units**
105
+
106
+ You can add additional units to a context by calling the `set_unit()` or
107
+ `set_units()` methods. These methods may be used, for example, when a user
108
+ logs in to your application and you want to use the new unit type in the
109
+ context.
110
+
111
+ Please note, you cannot override an already set unit type as that would be
112
+ a change of identity and would throw an exception. In this case, you must
113
+ create a new context instead. The `set_unit()` and
114
+ `set_units()` methods can be called before the context is ready.
115
+
116
+ ```ruby
117
+ context_config.set_unit('session_id', 'bf06d8cb5d8137290c4abb64155584fbdb64d8')
118
+ context_config.set_unit('user_id', '123456')
119
+ context = Absmartly.create_context(context_config)
120
+ ```
121
+ or
122
+ ```ruby
123
+ context_config.set_units(
124
+ session_id: 'bf06d8cb5d8137290c4abb64155584fbdb64d8',
125
+ user_id: '123456'
126
+ )
127
+ context = Absmartly.create_context(context_config)
128
+ ```
129
+
130
+ ## Basic Usage
131
+
132
+ ### Selecting A Treatment
133
+
134
+ ```ruby
135
+ treatment = context.treatment('exp_test_experiment')
136
+
137
+ if treatment.zero?
138
+ # user is in control group (variant 0)
139
+ else
140
+ # user is in treatment group
141
+ end
142
+ ```
143
+
144
+ ### Treatment Variables
145
+
146
+ ```ruby
147
+ default_button_color_value = 'red'
148
+
149
+ context.variable_value('experiment_name', default_button_color_value)
150
+ ```
151
+
152
+ ### Peek at Treatment Variants
153
+
154
+ Although generally not recommended, it is sometimes necessary to peek at
155
+ a treatment or variable without triggering an exposure. The A/B Smartly
156
+ SDK provides a `peek_treatment()` method for that.
157
+
158
+ ```ruby
159
+ treatment = context.peek_treatment('exp_test_experiment')
160
+ ```
161
+
162
+ #### Peeking at variables
163
+
164
+ ```ruby
165
+ treatment = context.peek_variable_value('exp_test_experiment')
166
+ ```
167
+
168
+ ### Overriding Treatment Variants
169
+
170
+ During development, for example, it is useful to force a treatment for an
171
+ experiment. This can be achieved with the `set_override()` and/or `set_overrides()`
172
+ methods. These methods can be called before the context is ready.
173
+
174
+ ```ruby
175
+ context.set_override("exp_test_experiment", 1) # force variant 1 of treatment
176
+
177
+ context.set_overrides(
178
+ 'exp_test_experiment' => 1,
179
+ 'exp_another_experiment' => 0,
180
+ )
181
+ ```
182
+
183
+ ## Advanced
184
+
185
+ ### Context Attributes
186
+
187
+ Attributes are used to pass meta-data about the user and/or the request.
188
+ They can be used later in the Web Console to create segments or audiences.
189
+ They can be set using the `set_attribute()` or `set_attributes()`
190
+ methods, before or after the context is ready.
191
+
192
+ ```ruby
193
+ context.set_attribute('session_id', session_id)
194
+ context.set_attributes(
195
+ 'customer_age' => 'new_customer'
196
+ )
197
+ ```
198
+
199
+ ### Custom Assignments
200
+
201
+ Sometimes it may be necessary to override the automatic selection of a
202
+ variant. For example, if you wish to have your variant chosen based on
203
+ data from an API call. This can be accomplished using the
204
+ `set_custom_assignment()` method.
205
+
206
+ ```ruby
207
+ chosen_variant = 1
208
+ context.set_custom_assignment('experiment_name', chosen_variant)
209
+ ```
210
+
211
+ If you are running multiple experiments and need to choose different
212
+ custom assignments for each one, you can do so using the
213
+ `set_custom_assignments()` method.
214
+
215
+ ```ruby
216
+ assignments = [
217
+ 'experiment_name' => 1,
218
+ 'another_experiment_name' => 0,
219
+ 'a_third_experiment_name' => 2
220
+ ]
221
+
222
+ context.set_custom_assignments(assignments)
223
+ ```
224
+
225
+ ### Publish
226
+
227
+ Sometimes it is necessary to ensure all events have been published to the
228
+ A/B Smartly collector, before proceeding. You can explicitly call the
229
+ `publish()` methods.
230
+
231
+ ```
232
+ context.publish
233
+ ```
234
+
235
+ ### Finalize
236
+
237
+ The `close()` method will ensure all events have been
238
+ published to the A/B Smartly collector, like `publish()`, and will also
239
+ "seal" the context, throwing an error if any method that could generate
240
+ an event is called.
241
+
242
+ ```
243
+ context.close
244
+ ```
245
+
246
+ ### Tracking Goals
247
+
248
+ ```ruby
249
+ context.track(
250
+ 'payment',
251
+ { item_count: 1, total_amount: 1999.99 }
252
+ )
253
+ ```
data/absmartly.gemspec ADDED
@@ -0,0 +1,40 @@
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
+ # Uncomment to register a new dependency of your gem
36
+ # spec.add_dependency "example-gem", "~> 1.0"
37
+
38
+ # For more information and examples about making a new gem, check out our
39
+ # guide at: https://bundler.io/guides/creating_gem.html
40
+ end
data/example/example.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "../lib/absmartly"
2
4
 
3
5
  # config file
@@ -25,7 +27,7 @@ treatment3 = ctx.treatment("test")
25
27
  puts(treatment3) # 1
26
28
 
27
29
  ctx.set_unit("db_user_id", 1000013)
28
- ctx.set_units(db_user_id2: 1000013, session_id: 12311)
30
+ ctx.set_units(db_user_id2: 1000013, session_id2: 12311)
29
31
 
30
32
  ctx.set_attribute("user_agent", "Chrome 2022")
31
33
  ctx.set_attributes(
data/lib/a_b_smartly.rb CHANGED
@@ -58,7 +58,7 @@ class ABSmartly
58
58
 
59
59
  def create_context(config)
60
60
  validate_params(config)
61
- Context.create(get_utc_format, config, @scheduler, @context_data_provider.context_data,
61
+ Context.create(get_utc_format, config, @context_data_provider.context_data,
62
62
  @context_data_provider, @context_event_handler, @context_event_logger, @variable_parser,
63
63
  AudienceMatcher.new(@audience_deserializer))
64
64
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Absmartly
4
- VERSION = "0.1.2"
4
+ VERSION = "1.0.5"
5
5
  end
data/lib/context.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "hashing"
4
4
  require_relative "variant_assigner"
5
+ require_relative "context_event_logger"
5
6
  require_relative "json/unit"
6
7
  require_relative "json/attribute"
7
8
  require_relative "json/exposure"
@@ -11,13 +12,13 @@ require_relative "json/goal_achievement"
11
12
  class Context
12
13
  attr_reader :data, :pending_count
13
14
 
14
- def self.create(clock, config, scheduler, data_future, data_provider,
15
+ def self.create(clock, config, data_future, data_provider,
15
16
  event_handler, event_logger, variable_parser, audience_matcher)
16
- Context.new(clock, config, scheduler, data_future, data_provider,
17
+ Context.new(clock, config, data_future, data_provider,
17
18
  event_handler, event_logger, variable_parser, audience_matcher)
18
19
  end
19
20
 
20
- def initialize(clock, config, scheduler, data_future, data_provider,
21
+ def initialize(clock, config, data_future, data_provider,
21
22
  event_handler, event_logger, variable_parser, audience_matcher)
22
23
  @index = []
23
24
  @achievements = []
@@ -31,7 +32,6 @@ class Context
31
32
  @data_provider = data_provider
32
33
  @variable_parser = variable_parser
33
34
  @audience_matcher = audience_matcher
34
- @scheduler = scheduler
35
35
  @closed = false
36
36
 
37
37
  @units = {}
@@ -49,8 +49,10 @@ class Context
49
49
  set_custom_assignments(config.custom_assignments) if config.custom_assignments
50
50
  if data_future.success?
51
51
  assign_data(data_future.data_future)
52
+ log_event(ContextEventLogger::EVENT_TYPE::READY, data_future.data_future)
52
53
  else
53
54
  set_data_failed(data_future.exception)
55
+ log_error(data_future.exception)
54
56
  end
55
57
  end
56
58
 
@@ -157,11 +159,11 @@ class Context
157
159
  assignment.exposed = true
158
160
 
159
161
  exposure = Exposure.new
160
- exposure.id = assignment.id
162
+ exposure.id = assignment.id || 0
161
163
  exposure.name = assignment.name
162
164
  exposure.unit = assignment.unit_type
163
165
  exposure.variant = assignment.variant
164
- exposure.exposed_at = @clock
166
+ exposure.exposed_at = @clock.to_i
165
167
  exposure.assigned = assignment.assigned
166
168
  exposure.eligible = assignment.eligible
167
169
  exposure.overridden = assignment.overridden
@@ -171,6 +173,7 @@ class Context
171
173
 
172
174
  @pending_count += 1
173
175
  @exposures.push(exposure)
176
+ log_event(ContextEventLogger::EVENT_TYPE::EXPOSURE, exposure)
174
177
  end
175
178
  end
176
179
 
@@ -221,6 +224,7 @@ class Context
221
224
 
222
225
  @pending_count += 1
223
226
  @achievements.push(achievement)
227
+ log_event(ContextEventLogger::EVENT_TYPE::GOAL, achievement)
224
228
  end
225
229
 
226
230
  def publish
@@ -236,8 +240,10 @@ class Context
236
240
  data_future = @data_provider.context_data
237
241
  if data_future.success?
238
242
  assign_data(data_future.data_future)
243
+ log_event(ContextEventLogger::EVENT_TYPE::REFRESH, data_future.data_future)
239
244
  else
240
245
  set_data_failed(data_future.exception)
246
+ log_error(data_future.exception)
241
247
  end
242
248
  end
243
249
  end
@@ -248,6 +254,7 @@ class Context
248
254
  flush
249
255
  end
250
256
  @closed = true
257
+ log_event(ContextEventLogger::EVENT_TYPE::CLOSE, nil)
251
258
  end
252
259
  end
253
260
 
@@ -282,18 +289,20 @@ class Context
282
289
  event.hashed = true
283
290
  event.published_at = @clock.to_i
284
291
  event.units = @units.map do |key, value|
285
- Unit.new(key, unit_hash(key, value))
292
+ Unit.new(key.to_s, unit_hash(key, value))
286
293
  end
287
- event.attributes = @attributes.empty? ? nil : @attributes
288
294
  event.exposures = exposures
289
- event.goals = achievements
290
- return @event_handler.publish(self, event)
295
+ event.attributes = @attributes unless @attributes.empty?
296
+ event.goals = achievements unless achievements.nil?
297
+ log_event(ContextEventLogger::EVENT_TYPE::PUBLISH, event)
298
+ @event_handler.publish(self, event)
291
299
  end
292
300
  end
293
301
  else
294
302
  @exposures = []
295
303
  @achievements = []
296
304
  @pending_count = 0
305
+ @data_failed
297
306
  end
298
307
  end
299
308
 
@@ -365,7 +374,7 @@ class Context
365
374
  hash
366
375
  end
367
376
  match = @audience_matcher.evaluate(experiment.data.audience, attrs)
368
- if match.nil? || !match.result
377
+ if match && !match.result
369
378
  assignment.audience_mismatch = true
370
379
  end
371
380
  end
@@ -471,6 +480,18 @@ class Context
471
480
  @failed = true
472
481
  end
473
482
 
483
+ def log_event(event, data)
484
+ unless @event_logger.nil?
485
+ @event_logger.handle_event(event, data)
486
+ end
487
+ end
488
+
489
+ def log_error(error)
490
+ unless @event_logger.nil?
491
+ @event_logger.handle_event(ContextEventLogger::EVENT_TYPE::ERROR, error.message)
492
+ end
493
+ end
494
+
474
495
  attr_accessor :clock,
475
496
  :publish_delay,
476
497
  :event_handler,
@@ -478,7 +499,6 @@ class Context
478
499
  :data_provider,
479
500
  :variable_parser,
480
501
  :audience_matcher,
481
- :scheduler,
482
502
  :units,
483
503
  :failed,
484
504
  :data_lock,
@@ -67,4 +67,12 @@ class ContextConfig
67
67
  def custom_assignment(experiment_name)
68
68
  @custom_assignments[experiment_name.to_sym]
69
69
  end
70
+
71
+
72
+ def set_event_logger(event_logger)
73
+ @event_logger = event_logger
74
+ self
75
+ end
76
+
77
+ attr_reader :event_logger
70
78
  end
@@ -1,9 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ContextEventLogger
4
- EVENT_TYPE = %w[error ready refresh publish exposure goal close]
5
- # @interface method
6
- def handle_event
7
- raise NotImplementedError.new("You must implement handleEvent method.")
4
+ module EVENT_TYPE
5
+ ERROR = "error"
6
+ READY = "ready"
7
+ REFRESH = "refresh"
8
+ PUBLISH = "publish"
9
+ EXPOSURE = "exposure"
10
+ GOAL = "goal"
11
+ CLOSE = "close"
12
+ end
13
+
14
+ def handle_event(event, data)
15
+ raise NotImplementedError.new("You must implement handle_event method.")
8
16
  end
9
17
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ContextEventLoggerCallback < ContextEventLogger
4
+ attr_accessor :callable
5
+
6
+ def initialize(callable)
7
+ @callable = callable
8
+ end
9
+
10
+ def handle_event(event, data)
11
+ @callable.call(event, data) if @callable.present?
12
+ end
13
+ end
data/lib/json/exposure.rb CHANGED
@@ -8,7 +8,7 @@ class Exposure
8
8
  exposed_at = nil, assigned = nil, eligible = nil,
9
9
  overridden = nil, full_on = nil, custom = nil,
10
10
  audience_mismatch = nil)
11
- @id = id
11
+ @id = id || 0
12
12
  @name = name
13
13
  @unit = unit
14
14
  @variant = variant
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: absmartly-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 1.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - absmartly
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-12-04 00:00:00.000000000 Z
11
+ date: 2023-04-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Absmartly gem
14
14
  email:
@@ -16,7 +16,7 @@ email:
16
16
  executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files:
19
- - README
19
+ - README.md
20
20
  files:
21
21
  - ".rspec"
22
22
  - ".rubocop.yml"
@@ -26,8 +26,9 @@ files:
26
26
  - Gemfile
27
27
  - Gemfile.lock
28
28
  - LICENSE.txt
29
- - README
29
+ - README.md
30
30
  - Rakefile
31
+ - absmartly.gemspec
31
32
  - example/example.rb
32
33
  - lib/a_b_smartly.rb
33
34
  - lib/a_b_smartly_config.rb
@@ -45,6 +46,7 @@ files:
45
46
  - lib/context_data_provider.rb
46
47
  - lib/context_event_handler.rb
47
48
  - lib/context_event_logger.rb
49
+ - lib/context_event_logger_callback.rb
48
50
  - lib/context_event_serializer.rb
49
51
  - lib/default_audience_deserializer.rb
50
52
  - lib/default_context_data_deserializer.rb
@@ -113,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
115
  - !ruby/object:Gem::Version
114
116
  version: '0'
115
117
  requirements: []
116
- rubygems_version: 3.1.6
118
+ rubygems_version: 3.4.10
117
119
  signing_key:
118
120
  specification_version: 4
119
121
  summary: Absmartly gem
data/README DELETED
@@ -1,180 +0,0 @@
1
- # A/B Smartly SDK
2
-
3
- A/B Smartly Ruby SDK
4
-
5
- ## Compatibility
6
-
7
- The A/B Smartly Ruby SDK is compatible with Ruby versions 2.7 and later. For the best performance and code readability, Ruby 3 or later is recommended. This SDK is being constantly tested with the nightly builds of Ruby, to ensure it is compatible with the latest Ruby version.
8
-
9
- ## Getting Started
10
-
11
- ### Install the SDK
12
-
13
- Install the gem and add to the application's Gemfile by executing:
14
-
15
- $ bundle add absmartly
16
-
17
- If bundler is not being used to manage dependencies, install the gem by executing:
18
-
19
- $ gem install absmartly
20
-
21
- ## Basic Usage
22
-
23
- Once the SDK is installed, it can be initialized in your project.
24
-
25
- You can create an SDK instance using the API key, application name, environment, and the endpoint URL obtained from A/B Smartly.
26
-
27
- ```Ruby
28
- require 'absmartly'
29
-
30
- Absmartly.configure_client do |config|
31
- config.endpoint = "https://your-company.absmartly.io/v1"
32
- config.api_key = "YOUR-API-KEY"
33
- config.application = "website"
34
- config.environment = "development"
35
- end
36
- ```
37
- #### Creating a new Context with raw promises
38
-
39
- ```Ruby
40
- # define a new context request
41
- context_config = Absmartly.create_context_config
42
- context_config.set_unit("session_id", "bf06d8cb5d8137290c4abb64155584fbdb64d8")
43
- context_config.set_unit("user_id", "123456")
44
-
45
- context = Absmartly.create_context(context_config)
46
- ```
47
-
48
- ### Selecting A Treatment
49
-
50
- ```Ruby
51
- treatment = context.treatment('exp_test_experiment')
52
-
53
- if treatment.zero?
54
- # user is in control group (variant 0)
55
- else
56
- # user is in treatment group
57
- end
58
- ```
59
-
60
- ### Treatment Variables
61
-
62
- ```Ruby
63
- default_button_color_value = 'red'
64
- button_color = context.variable_value('button.color')
65
- ```
66
-
67
- ### Peek at Treatment Variants
68
-
69
- Although generally not recommended, it is sometimes necessary to peek at a treatment or variable without triggering an exposure. The A/B Smartly SDK provides a `Context.peek_treatment()` method for that.
70
-
71
- ```Ruby
72
- treatment = context.peek_treatment('exp_test_experiment')
73
-
74
- if treatment.zero?
75
- # user is in control group (variant 0)
76
- else
77
- # user is in treatment group
78
- end
79
- ```
80
-
81
- #### Peeking at variables
82
-
83
- ```Ruby
84
- button_color = context.peek_variable_value('button.color', 'red')
85
- ```
86
-
87
- ### Overriding Treatment Variants
88
-
89
- During development, for example, it is useful to force a treatment for an
90
- experiment. This can be achieved with the `Context.set_override()` and/or `Context.set_overrides()` methods. These methods can be called before the context is ready.
91
-
92
- ```Ruby
93
- context.set_override("exp_test_experiment", 1) # force variant 1 of treatment
94
-
95
- context.set_overrides(
96
- 'exp_test_experiment' => 1,
97
- 'exp_another_experiment' => 0,
98
- )
99
- ```
100
-
101
- ## Advanced
102
-
103
- ### Context Attributes
104
-
105
- Attributes are used to pass meta-data about the user and/or the request.
106
- They can be used later in the Web Console to create segments or audiences.
107
- They can be set using the `context.set_attribute()` or `context.set_attributes()` methods, before or after the context is ready.
108
-
109
- ```Ruby
110
- context.set_attribute('session_id', session_id)
111
- context.set_attributes(
112
- 'customer_age' => 'new_customer'
113
- )
114
- ```
115
-
116
- ### Custom Assignments
117
-
118
- Sometimes it may be necessary to override the automatic selection of a variant. For example, if you wish to have your variant chosen based on data from an API call. This can be accomplished using the `Context.set_custom_assignment()` method.
119
-
120
- ```Ruby
121
- chosen_variant = 1
122
- context.set_custom_assignment("experiment_name", chosen_variant)
123
- ```
124
-
125
- If you are running multiple experiments and need to choose different custom assignments for each one, you can do so using the `Context->setCustomAssignments()` method.
126
-
127
- ```Ruby
128
- assignments = [
129
- "experiment_name" => 1,
130
- "another_experiment_name" => 0,
131
- "a_third_experiment_name" => 2
132
- ]
133
-
134
- context.set_custom_assignments(assignments)
135
- ```
136
-
137
- ### Publish
138
-
139
- Sometimes it is necessary to ensure all events have been published to the A/B Smartly collector, before proceeding. You can explicitly call the `context.publish()` method.
140
-
141
- ```Ruby
142
- context.publish
143
- ```
144
-
145
- ### Finalize
146
-
147
- The `close()` method will ensure all events have been published to the A/B Smartly collector, like `context.publish()`, and will also "seal" the context, throwing an error if any method that could generate an event is called.
148
-
149
- ```Ruby
150
- context.close
151
- ```
152
-
153
- ### Tracking Goals
154
-
155
- ```Ruby
156
- context.track(
157
- 'payment',
158
- { item_count: 1, total_amount: 1999.99 }
159
- )
160
- ```
161
-
162
-
163
-
164
- ## Development
165
-
166
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
167
-
168
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
169
-
170
- ## Contributing
171
-
172
- Bug reports and pull requests are welcome on GitHub at https://github.com/omairazam/absmartly. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/omairazam/absmartly/blob/master/CODE_OF_CONDUCT.md).
173
-
174
- ## License
175
-
176
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
177
-
178
- ## Code of Conduct
179
-
180
- Everyone interacting in the Absmartly project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/omairazam/absmartly/blob/master/CODE_OF_CONDUCT.md).