optimizely-sdk 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 78af637c6334c098627f0f83824494fb30fb0de4
4
- data.tar.gz: d9d32f68014ec5866e521e274ac384fef1e22e81
3
+ metadata.gz: 388b7be07d59d027ef5f08ebce2fa43d62be0513
4
+ data.tar.gz: 0288d19e852dce6a860ceac8c35c6b508ed3363a
5
5
  SHA512:
6
- metadata.gz: 09fdf5e75b3fb050d43f627af4f81225d8bdd2ed0f10c89b8dfe8b485f1849b669497315645e54d7eb8fdcec7209892ebdb9a5a5af68805bd7f3873051738eb7
7
- data.tar.gz: 1bd6b64f56ef37dc6c2c38af651fce3c967832da5cf22a05e67683befb0bd3aeaec61c441a8d4ca6a961b97a6654f1362a8d5ea1d4a63b568c55a0858ff72d15
6
+ metadata.gz: 02cd29fbf79181021dae6d19aae905e4304dc8ce6d338e7d1df2e2086fd7d381b65232ed188f41ef005a1afaefa6de610d195162b144e7c6eccd05b084f9be9f
7
+ data.tar.gz: 281090b33e4e89c8ea7a32276d259a307fa9a3001ce532cc8b373a70d7cc70ec19d7e62c52a360e29e1bbabb5f44786739d05214d276558c5d0b060772ab5488
@@ -18,6 +18,11 @@ module Optimizely
18
18
  attr_accessor :logger
19
19
  attr_accessor :error_handler
20
20
 
21
+ EVENT_BUILDERS_BY_VERSION = {
22
+ Optimizely::V1_CONFIG_VERSION => EventBuilderV1,
23
+ Optimizely::V2_CONFIG_VERSION => EventBuilderV2
24
+ }
25
+
21
26
  def initialize(datafile, event_dispatcher = nil, logger = nil, error_handler = nil, skip_json_validation = false)
22
27
  # Constructor for Projects.
23
28
  #
@@ -35,7 +40,7 @@ module Optimizely
35
40
 
36
41
  @config = ProjectConfig.new(datafile, @logger, @error_handler)
37
42
  @bucketer = Bucketer.new(@config)
38
- @event_builder = EventBuilder.new(@config, @bucketer)
43
+ @event_builder = EVENT_BUILDERS_BY_VERSION[@config.version].new(@config, @bucketer)
39
44
  end
40
45
 
41
46
  def activate(experiment_key, user_id, attributes = nil)
@@ -70,7 +75,7 @@ module Optimizely
70
75
  @logger.log(Logger::INFO,
71
76
  'Dispatching impression event to URL %s with params %s.' % [impression_event.url,
72
77
  impression_event.params])
73
- @event_dispatcher.dispatch_event(impression_event.url, impression_event.params)
78
+ @event_dispatcher.dispatch_event(impression_event)
74
79
 
75
80
  @config.get_variation_key_from_id(experiment_key, variation_id)
76
81
  end
@@ -136,7 +141,7 @@ module Optimizely
136
141
  @logger.log(Logger::INFO,
137
142
  'Dispatching conversion event to URL %s with params %s.' % [conversion_event.url,
138
143
  conversion_event.params])
139
- @event_dispatcher.dispatch_event(conversion_event.url, conversion_event.params)
144
+ @event_dispatcher.dispatch_event(conversion_event)
140
145
  end
141
146
 
142
147
  private
@@ -6,28 +6,198 @@ module Optimizely
6
6
  class Event
7
7
  # Representation of an event which can be sent to the Optimizely logging endpoint.
8
8
 
9
- # Event API format
10
- OFFLINE_API_PATH = 'https://%{project_id}.log.optimizely.com/event'
9
+ attr_reader :http_verb
10
+ attr_reader :params
11
+ attr_reader :url
12
+ attr_reader :headers
13
+
14
+ def initialize(http_verb, url, params, headers)
15
+ @http_verb = http_verb
16
+ @url = url
17
+ @params = params
18
+ @headers = headers
19
+ end
20
+
21
+ # Override equality operator to make two events with the same contents equal for testing purposes
22
+ def ==(event)
23
+ @http_verb == event.http_verb && @url == event.url && @params == event.params && @headers == event.headers
24
+ end
25
+ end
11
26
 
12
- # Gets/Sets event params.
27
+ class BaseEventBuilder
28
+ attr_reader :config
29
+ attr_reader :bucketer
13
30
  attr_accessor :params
14
31
 
15
- def initialize(params)
16
- @params = params
32
+ def initialize(config, bucketer)
33
+ @config = config
34
+ @bucketer = bucketer
35
+ @params = {}
17
36
  end
18
37
 
19
- def url
20
- # URL for sending impression/conversion event.
38
+ private
39
+
40
+ def add_common_params(user_id, attributes)
41
+ # Add params which are used in both conversion and impression events.
21
42
  #
22
- # project_id - ID for the project.
43
+ # user_id - ID for user.
44
+ # attributes - Hash representing user attributes and values which need to be recorded.
45
+
46
+ add_project_id
47
+ add_account_id
48
+ add_user_id(user_id)
49
+ add_attributes(attributes)
50
+ add_source
51
+ add_time
52
+ end
53
+ end
54
+
55
+ class EventBuilderV2 < BaseEventBuilder
56
+ CONVERSION_EVENT_ENDPOINT = 'https://p13nlog.dz.optimizely.com/log/event'
57
+ IMPRESSION_EVENT_ENDPOINT = 'https://p13nlog.dz.optimizely.com/log/decision'
58
+ POST_HEADERS = { 'Content-Type' => 'application/json' }
59
+
60
+ def create_impression_event(experiment_key, variation_id, user_id, attributes)
61
+ # Create conversion Event to be sent to the logging endpoint.
62
+ #
63
+ # experiment_key - Experiment for which impression needs to be recorded.
64
+ # variation_id - ID for variation which would be presented to user.
65
+ # user_id - ID for user.
66
+ # attributes - Hash representing user attributes and values which need to be recorded.
67
+ #
68
+ # Returns event hash encapsulating the impression event.
69
+
70
+ @params = {}
71
+ add_common_params(user_id, attributes)
72
+ add_decision(experiment_key, variation_id)
73
+ add_attributes(attributes)
74
+ Event.new(:post, IMPRESSION_EVENT_ENDPOINT, @params, POST_HEADERS)
75
+ end
76
+
77
+ def create_conversion_event(event_key, user_id, attributes, event_value, experiment_keys)
78
+ # Create conversion Event to be sent to the logging endpoint.
79
+ #
80
+ # event_key - Event key representing the event which needs to be recorded.
81
+ # user_id - ID for user.
82
+ # attributes - Hash representing user attributes and values which need to be recorded.
83
+ # event_value - Value associated with the event. Can be used to represent revenue in cents.
84
+ # experiment_keys - Array of valid experiment keys for the event
85
+ #
86
+ # Returns event hash encapsulating the conversion event.
87
+
88
+ @params = {}
89
+ add_common_params(user_id, attributes)
90
+ add_conversion_event(event_key, event_value)
91
+ add_layer_states(user_id, experiment_keys)
92
+ Event.new(:post, CONVERSION_EVENT_ENDPOINT, @params, POST_HEADERS)
93
+ end
94
+
95
+ private
96
+
97
+ def add_common_params(user_id, attributes)
98
+ super
99
+ @params['isGlobalHoldback'] = false
100
+ end
101
+
102
+ def add_project_id
103
+ @params['projectId'] = @config.project_id
104
+ end
105
+
106
+ def add_account_id
107
+ @params['accountId'] = @config.account_id
108
+ end
109
+
110
+ def add_user_id(user_id)
111
+ @params['visitorId'] = user_id
112
+ end
113
+
114
+ def add_attributes(attributes)
115
+ @params['userFeatures'] = []
116
+
117
+ return if attributes.nil?
118
+
119
+ attributes.keys.each do |attribute_key|
120
+ # Omit falsy attribute values
121
+ attribute_value = attributes[attribute_key]
122
+ next unless attribute_value
123
+
124
+ # Skip attributes not in the datafile
125
+ attribute_id = @config.get_attribute_id(attribute_key)
126
+ next unless attribute_id
127
+
128
+ feature = {
129
+ 'id' => attribute_id,
130
+ 'name' => attribute_key,
131
+ 'type' => 'custom',
132
+ 'value' => attribute_value,
133
+ 'shouldIndex' => true,
134
+ }
135
+ @params['userFeatures'].push(feature)
136
+ end
137
+ end
138
+
139
+ def add_decision(experiment_key, variation_id)
140
+ experiment_id = @config.get_experiment_id(experiment_key)
141
+ @params['layerId'] = @config.experiment_key_map[experiment_key]['layerId']
142
+ @params['decision'] = {
143
+ 'variationId' => variation_id,
144
+ 'experimentId' => experiment_id,
145
+ 'isLayerHoldback' => false,
146
+ }
147
+ end
148
+
149
+ def add_conversion_event(event_key, event_value)
150
+ # Add conversion event information to the event.
23
151
  #
24
- # Returns URL for event API.
152
+ # event_key - Event key representing the event which needs to be recorded.
153
+ # event_value - Value associated with the event. Can be used to represent revenue in cents.
154
+
155
+ event_id = @config.event_key_map[event_key]['id']
156
+ event_name = @config.event_key_map[event_key]['key']
157
+
158
+ @params['eventEntityId'] = event_id
159
+ @params['eventFeatures'] = []
160
+ @params['eventName'] = event_name
161
+ @params['eventMetrics'] = []
25
162
 
26
- sprintf(OFFLINE_API_PATH, project_id: @params[Params::PROJECT_ID])
163
+ if event_value
164
+ @params['eventMetrics'].push({
165
+ 'name' => 'revenue',
166
+ 'value' => event_value,
167
+ })
168
+ end
169
+ end
170
+
171
+ def add_layer_states(user_id, experiment_keys)
172
+ @params['layerStates'] = []
173
+
174
+ experiment_keys.each do |experiment_key|
175
+ variation_id = @bucketer.bucket(experiment_key, user_id)
176
+ experiment_id = @config.experiment_key_map[experiment_key]['id']
177
+ layer_state = {
178
+ 'layerId' => @config.experiment_key_map[experiment_key]['layerId'],
179
+ 'decision' => {
180
+ 'variationId' => variation_id,
181
+ 'experimentId' => experiment_id,
182
+ 'isLayerHoldback' => false,
183
+ },
184
+ 'actionTriggered' => true,
185
+ }
186
+ @params['layerStates'].push(layer_state)
187
+ end
188
+ end
189
+
190
+ def add_source
191
+ @params['clientEngine'] = 'ruby-sdk'
192
+ @params['clientVersion'] = VERSION
193
+ end
194
+
195
+ def add_time
196
+ @params['timestamp'] = (Time.now.to_f * 1000).to_i
27
197
  end
28
198
  end
29
199
 
30
- class EventBuilder
200
+ class EventBuilderV1 < BaseEventBuilder
31
201
  # Class which encapsulates methods to build events for tracking impressions and conversions.
32
202
 
33
203
  # Attribute mapping format
@@ -36,15 +206,8 @@ module Optimizely
36
206
  # Experiment mapping format
37
207
  EXPERIMENT_PARAM_FORMAT = '%{experiment_prefix}%{experiment_id}'
38
208
 
39
- attr_accessor :config
40
- attr_accessor :bucketer
41
- attr_accessor :params
42
-
43
- def initialize(config, bucketer)
44
- @config = config
45
- @bucketer = bucketer
46
- @params = {}
47
- end
209
+ # Event endpoint path
210
+ OFFLINE_API_PATH = 'https://%{project_id}.log.optimizely.com/event'
48
211
 
49
212
  def create_impression_event(experiment_key, variation_id, user_id, attributes)
50
213
  # Create conversion Event to be sent to the logging endpoint.
@@ -60,7 +223,7 @@ module Optimizely
60
223
  add_common_params(user_id, attributes)
61
224
  add_impression_goal(experiment_key)
62
225
  add_experiment(experiment_key, variation_id)
63
- Event.new(@params)
226
+ Event.new(:get, sprintf(OFFLINE_API_PATH, project_id: @params[Params::PROJECT_ID]), @params, {})
64
227
  end
65
228
 
66
229
  def create_conversion_event(event_key, user_id, attributes, event_value, experiment_keys)
@@ -71,12 +234,14 @@ module Optimizely
71
234
  # attributes - Hash representing user attributes and values which need to be recorded.
72
235
  # event_value - Value associated with the event. Can be used to represent revenue in cents.
73
236
  # experiment_keys - Array of valid experiment keys for the goal
237
+ #
238
+ # Returns event hash encapsulating the conversion event.
74
239
 
75
240
  @params = {}
76
241
  add_common_params(user_id, attributes)
77
242
  add_conversion_goal(event_key, event_value)
78
243
  add_experiment_variation_params(user_id, experiment_keys)
79
- Event.new(@params)
244
+ Event.new(:get, sprintf(OFFLINE_API_PATH, project_id: @params[Params::PROJECT_ID]), @params, {})
80
245
  end
81
246
 
82
247
  private
@@ -128,20 +293,6 @@ module Optimizely
128
293
  @params[Params::TIME] = Time.now.strftime('%s').to_i
129
294
  end
130
295
 
131
- def add_common_params(user_id, attributes)
132
- # Add params which are used same in both conversion and impression events.
133
- #
134
- # user_id - ID for user.
135
- # attributes - Hash representing user attributes and values which need to be recorded.
136
-
137
- add_project_id
138
- add_account_id
139
- add_user_id(user_id)
140
- add_attributes(attributes)
141
- add_source
142
- add_time
143
- end
144
-
145
296
  def add_impression_goal(experiment_key)
146
297
  # Add impression goal information to the event.
147
298
  #
@@ -1,18 +1,37 @@
1
1
  require 'httparty'
2
2
 
3
3
  module Optimizely
4
+ class NoOpEventDispatcher
5
+ # Class providing dispatch_event method which does nothing.
6
+
7
+ def dispatch_event(event)
8
+ end
9
+ end
10
+
4
11
  class EventDispatcher
5
12
  REQUEST_TIMEOUT = 10
6
13
 
7
- def dispatch_event(url, params)
14
+ def dispatch_event(event)
8
15
  # Dispatch the event being represented by the Event object.
9
16
  #
10
- # url - URL to send impression/conversion event to.
11
- # params - Params to be sent to the impression/conversion event.
17
+ # event - Event object
12
18
 
13
- HTTParty.get(url, query: params, timeout: REQUEST_TIMEOUT)
14
- rescue Timeout::Error => e
15
- return e
19
+ if event.http_verb == :get
20
+ begin
21
+ HTTParty.get(event.url, headers: event.headers, query: event.params, timeout: REQUEST_TIMEOUT)
22
+ rescue Timeout::Error => e
23
+ return e
24
+ end
25
+ elsif event.http_verb == :post
26
+ begin
27
+ HTTParty.post(event.url,
28
+ body: event.params.to_json,
29
+ headers: event.headers,
30
+ timeout: REQUEST_TIMEOUT)
31
+ rescue Timeout::Error => e
32
+ return e
33
+ end
34
+ end
16
35
  end
17
36
  end
18
37
  end
@@ -1,7 +1,7 @@
1
1
  module Optimizely
2
2
  module Helpers
3
3
  module Constants
4
- JSON_SCHEMA = {
4
+ JSON_SCHEMA_V1 = {
5
5
  'type' => 'object',
6
6
  'properties' => {
7
7
  'projectId' => {
@@ -186,7 +186,7 @@ module Optimizely
186
186
  'trafficAllocation',
187
187
  'audienceIds',
188
188
  'forcedVariations',
189
- 'status'
189
+ 'status',
190
190
  ]
191
191
  }
192
192
  },
@@ -278,6 +278,288 @@ module Optimizely
278
278
  'revision'
279
279
  ]
280
280
  }
281
+
282
+ JSON_SCHEMA_V2 = {
283
+ 'type' => 'object',
284
+ 'properties' => {
285
+ 'projectId' => {
286
+ 'type' => 'string'
287
+ },
288
+ 'accountId' => {
289
+ 'type' => 'string'
290
+ },
291
+ 'groups' => {
292
+ 'type' => 'array',
293
+ 'items' => {
294
+ 'type' => 'object',
295
+ 'properties' => {
296
+ 'id' => {
297
+ 'type' => 'string'
298
+ },
299
+ 'policy' => {
300
+ 'type' => 'string'
301
+ },
302
+ 'trafficAllocation' => {
303
+ 'type' => 'array',
304
+ 'items' => {
305
+ 'type' => 'object',
306
+ 'properties' => {
307
+ 'entityId' => {
308
+ 'type' => 'string'
309
+ },
310
+ 'endOfRange' => {
311
+ 'type' => 'integer'
312
+ }
313
+ },
314
+ 'required' => [
315
+ 'entityId',
316
+ 'endOfRange'
317
+ ]
318
+ }
319
+ },
320
+ 'experiments' => {
321
+ 'type' => 'array',
322
+ 'items' => {
323
+ 'type' => 'object',
324
+ 'properties' => {
325
+ 'id' => {
326
+ 'type' => 'string'
327
+ },
328
+ 'layerId' => {
329
+ 'type' => 'string'
330
+ },
331
+ 'key' => {
332
+ 'type' => 'string'
333
+ },
334
+ 'status' => {
335
+ 'type' => 'string'
336
+ },
337
+ 'variations' => {
338
+ 'type' => 'array',
339
+ 'items' => {
340
+ 'type' => 'object',
341
+ 'properties' => {
342
+ 'id' => {
343
+ 'type' => 'string'
344
+ },
345
+ 'key' => {
346
+ 'type' => 'string'
347
+ }
348
+ },
349
+ 'required' => [
350
+ 'id',
351
+ 'key'
352
+ ]
353
+ }
354
+ },
355
+ 'trafficAllocation' => {
356
+ 'type' => 'array',
357
+ 'items' => {
358
+ 'type' => 'object',
359
+ 'properties' => {
360
+ 'entityId' => {
361
+ 'type' => 'string'
362
+ },
363
+ 'endOfRange' => {
364
+ 'type' => 'integer'
365
+ }
366
+ },
367
+ 'required' => [
368
+ 'entityId',
369
+ 'endOfRange'
370
+ ]
371
+ }
372
+ },
373
+ 'audienceIds' => {
374
+ 'type' => 'array',
375
+ 'items' => {
376
+ 'type' => 'string'
377
+ }
378
+ },
379
+ 'forcedVariations' => {
380
+ 'type' => 'object'
381
+ }
382
+ },
383
+ 'required' => [
384
+ 'id',
385
+ 'layerId',
386
+ 'key',
387
+ 'status',
388
+ 'variations',
389
+ 'trafficAllocation',
390
+ 'audienceIds',
391
+ 'forcedVariations'
392
+ ]
393
+ }
394
+ }
395
+ },
396
+ 'required' => [
397
+ 'id',
398
+ 'policy',
399
+ 'trafficAllocation',
400
+ 'experiments'
401
+ ]
402
+ }
403
+ },
404
+ 'experiments' => {
405
+ 'type' => 'array',
406
+ 'items' => {
407
+ 'type' => 'object',
408
+ 'properties' => {
409
+ 'id' => {
410
+ 'type' => 'string'
411
+ },
412
+ 'key' => {
413
+ 'type' => 'string'
414
+ },
415
+ 'status' => {
416
+ 'type' => 'string'
417
+ },
418
+ 'layerId' => {
419
+ 'type' => 'string'
420
+ },
421
+ 'variations' => {
422
+ 'type' => 'array',
423
+ 'items' => {
424
+ 'type' => 'object',
425
+ 'properties' => {
426
+ 'id' => {
427
+ 'type' => 'string'
428
+ },
429
+ 'key' => {
430
+ 'type' => 'string'
431
+ }
432
+ },
433
+ 'required' => [
434
+ 'id',
435
+ 'key'
436
+ ]
437
+ }
438
+ },
439
+ 'trafficAllocation' => {
440
+ 'type' => 'array',
441
+ 'items' => {
442
+ 'type' => 'object',
443
+ 'properties' => {
444
+ 'entityId' => {
445
+ 'type' => 'string'
446
+ },
447
+ 'endOfRange' => {
448
+ 'type' => 'integer'
449
+ }
450
+ },
451
+ 'required' => [
452
+ 'entityId',
453
+ 'endOfRange'
454
+ ]
455
+ }
456
+ },
457
+ 'audienceIds' => {
458
+ 'type' => 'array',
459
+ 'items' => {
460
+ 'type' => 'string'
461
+ }
462
+ },
463
+ 'forcedVariations' => {
464
+ 'type' => 'object'
465
+ }
466
+ },
467
+ 'required' => [
468
+ 'id',
469
+ 'key',
470
+ 'variations',
471
+ 'trafficAllocation',
472
+ 'audienceIds',
473
+ 'forcedVariations',
474
+ 'status',
475
+ 'layerId'
476
+ ]
477
+ }
478
+ },
479
+ 'events' => {
480
+ 'type' => 'array',
481
+ 'items' => {
482
+ 'type' => 'object',
483
+ 'properties' => {
484
+ 'key' => {
485
+ 'type' => 'string'
486
+ },
487
+ 'experimentIds' => {
488
+ 'type' => 'array',
489
+ 'items' => {
490
+ 'type' => 'string'
491
+ }
492
+ },
493
+ 'id' => {
494
+ 'type' => 'string'
495
+ }
496
+ },
497
+ 'required' => [
498
+ 'key',
499
+ 'experimentIds',
500
+ 'id'
501
+ ]
502
+ }
503
+ },
504
+ 'audiences' => {
505
+ 'type' => 'array',
506
+ 'items' => {
507
+ 'type' => 'object',
508
+ 'properties' => {
509
+ 'id' => {
510
+ 'type' => 'string'
511
+ },
512
+ 'name' => {
513
+ 'type' => 'string'
514
+ },
515
+ 'conditions' => {
516
+ 'type' => 'string'
517
+ }
518
+ },
519
+ 'required' => [
520
+ 'id',
521
+ 'name',
522
+ 'conditions'
523
+ ]
524
+ }
525
+ },
526
+ 'attributes' => {
527
+ 'type' => 'array',
528
+ 'items' => {
529
+ 'type' => 'object',
530
+ 'properties' => {
531
+ 'id' => {
532
+ 'type' => 'string'
533
+ },
534
+ 'key' => {
535
+ 'type' => 'string'
536
+ },
537
+ },
538
+ 'required' => [
539
+ 'id',
540
+ 'key',
541
+ ]
542
+ }
543
+ },
544
+ 'version' => {
545
+ 'type' => 'string'
546
+ },
547
+ 'revision' => {
548
+ 'type' => 'string'
549
+ }
550
+ },
551
+ 'required' => [
552
+ 'projectId',
553
+ 'accountId',
554
+ 'experiments',
555
+ 'events',
556
+ 'groups',
557
+ 'audiences',
558
+ 'attributes',
559
+ 'version',
560
+ 'revision'
561
+ ]
562
+ }
281
563
  end
282
564
  end
283
565
  end
@@ -1,4 +1,5 @@
1
1
  require_relative 'constants'
2
+ require 'json'
2
3
  require 'json-schema'
3
4
 
4
5
  module Optimizely
@@ -23,7 +24,19 @@ module Optimizely
23
24
  #
24
25
  # Returns boolean depending on validity of datafile.
25
26
 
26
- JSON::Validator.validate(Helpers::Constants::JSON_SCHEMA, datafile)
27
+ begin
28
+ datafile = JSON.load(datafile)
29
+ rescue
30
+ return false
31
+ end
32
+
33
+ version = datafile['version']
34
+
35
+ if version == Optimizely::V1_CONFIG_VERSION
36
+ JSON::Validator.validate(Helpers::Constants::JSON_SCHEMA_V1, datafile)
37
+ else
38
+ JSON::Validator.validate(Helpers::Constants::JSON_SCHEMA_V2, datafile)
39
+ end
27
40
  end
28
41
 
29
42
  def error_handler_valid?(error_handler)
@@ -1,6 +1,10 @@
1
1
  require 'json'
2
2
 
3
3
  module Optimizely
4
+
5
+ V1_CONFIG_VERSION = '1'
6
+ V2_CONFIG_VERSION = '2'
7
+
4
8
  class ProjectConfig
5
9
  # Representation of the Optimizely project config.
6
10
 
@@ -11,8 +15,9 @@ module Optimizely
11
15
 
12
16
  # Gets project config attributes.
13
17
  attr_reader :error_handler
14
- attr_accessor :logger
18
+ attr_reader :logger
15
19
 
20
+ attr_reader :version
16
21
  attr_reader :account_id
17
22
  attr_reader :project_id
18
23
  attr_reader :attributes
@@ -41,9 +46,14 @@ module Optimizely
41
46
 
42
47
  @error_handler = error_handler
43
48
  @logger = logger
49
+ @version = config['version']
44
50
  @account_id = config['accountId']
45
51
  @project_id = config['projectId']
46
- @attributes = config['dimensions']
52
+ if @version == V1_CONFIG_VERSION
53
+ @attributes = config['dimensions']
54
+ else
55
+ @attributes = config['attributes']
56
+ end
47
57
  @events = config['events']
48
58
  @experiments = config['experiments']
49
59
  @revision = config['revision']
@@ -73,7 +83,7 @@ module Optimizely
73
83
  end
74
84
 
75
85
  def experiment_running?(experiment_key)
76
- # Determine if experiment coresponding to given key is running
86
+ # Determine if experiment corresponding to given key is running
77
87
  #
78
88
  # experiment_key - String key representing the experiment
79
89
  #
@@ -239,6 +249,14 @@ module Optimizely
239
249
  @error_handler.handle_error InvalidExperimentError
240
250
  end
241
251
 
252
+ def get_attribute_id(attribute_key)
253
+ attribute = @attribute_key_map[attribute_key]
254
+ return attribute['id'] if attribute
255
+ @logger.log Logger::ERROR, "Attribute key '#{attribute_key}' is not in datafile."
256
+ @error_handler.handle_error InvalidAttributeError
257
+ nil
258
+ end
259
+
242
260
  private
243
261
 
244
262
  def generate_key_map(array, key)
@@ -1,3 +1,3 @@
1
1
  module Optimizely
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.1.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: optimizely-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Delikat
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2016-08-03 00:00:00.000000000 Z
13
+ date: 2016-09-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -133,7 +133,6 @@ files:
133
133
  - lib/optimizely/params.rb
134
134
  - lib/optimizely/project_config.rb
135
135
  - lib/optimizely/version.rb
136
- - lib/start.rb
137
136
  homepage: https://www.optimizely.com/
138
137
  licenses:
139
138
  - Apache-2.0
@@ -154,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
153
  version: '0'
155
154
  requirements: []
156
155
  rubyforge_project:
157
- rubygems_version: 2.4.8
156
+ rubygems_version: 2.6.6
158
157
  signing_key:
159
158
  specification_version: 4
160
159
  summary: Ruby SDK for Optimizely's testing framework
@@ -1,131 +0,0 @@
1
- require './optimizely'
2
- require 'benchmark'
3
-
4
- class PerformanceTests
5
- @error_handler = Optimizely::NoOpErrorHandler.new
6
- @logger = Optimizely::NoOpLogger.new
7
-
8
- def self.test_initialize(testdata, optly)
9
- Optimizely::Project.new(testdata)
10
- end
11
-
12
- def self.test_initialize_logger(testdata, optly)
13
- Optimizely::Project.new(testdata, nil, @logger)
14
- end
15
-
16
- def self.test_initialize_logger_and_error_handler(testdata, optly)
17
- Optimizely::Project.new(testdata, nil, @logger, @error_handler)
18
- end
19
-
20
- def self.test_initialize_no_schema_validation(testdata, optly)
21
- Optimizely::Project.new(testdata, nil, nil, nil, true)
22
- end
23
-
24
- def self.test_initialize_logger_no_schema_validation(testdata, optly)
25
- Optimizely::Project.new(testdata, nil, @logger, nil, true)
26
- end
27
-
28
- def self.test_initialize_error_handler_no_schema_validation(testdata, optly)
29
- Optimizely::Project.new(testdata, nil, nil, @error_handler, true)
30
- end
31
-
32
- def self.test_initialize_logger_error_handler_no_schema_validation(testdata, optly)
33
- Optimizely::Project.new(testdata, nil, @logger, @error_handler, true)
34
- end
35
-
36
- def self.test_initialize_error_handler_no_schema_validation(testdata, optly)
37
- Optimizely::Project.new(testdata, nil, nil, @error_handler, true)
38
- end
39
-
40
- def self.test_activate(testdata, optly)
41
- optly.activate('testExperiment2', 'optimizely_user')
42
- end
43
-
44
- def self.test_activate_with_attributes(testdata, optly)
45
- optly.activate('testExperimentWithFirefoxAudience', 'optimizely_user', {'browser_type' => 'firefox'})
46
- end
47
-
48
- def self.test_activate_with_forced_variation(testdata, optly)
49
- optly.activate('testExperiment2', 'variation_user')
50
- end
51
-
52
- def self.test_activate_grouped_exp(testdata, optly)
53
- optly.activate('mutex_exp2', 'optimizely_user')
54
- end
55
-
56
- def self.test_activate_grouped_exp_with_attributes(testdata, optly)
57
- optly.activate('mutex_exp1', 'optimizely_user', {'browser_type' => 'firefox'})
58
- end
59
-
60
- def self.test_get_variation(testdata, optly)
61
- optly.get_variation('testExperiment2', 'optimizely_user')
62
- end
63
-
64
- def self.test_get_variation_with_attributes(testdata, optly)
65
- optly.get_variation('testExperimentWithFirefoxAudience', 'optimizely_user', {'browser_type' => 'firefox'})
66
- end
67
-
68
- def self.test_get_variation_with_forced_variation(testdata, optly)
69
- optly.get_variation('testExperiment2', 'variation_user')
70
- end
71
-
72
- def self.test_get_variation_grouped_exp(testdata, optly)
73
- optly.get_variation('mutex_exp2', 'optimizely_user')
74
- end
75
-
76
- def self.test_get_variation_grouped_exp_with_attributes(testdata, optly)
77
- optly.get_variation('mutex_exp1', 'optimizely_user')
78
- end
79
-
80
- def self.test_track(testdata, optly)
81
- optly.track('testEvent', 'optimizely_user')
82
- end
83
-
84
- def self.test_track_with_attributes(testdata, optly)
85
- optly.track('testEventWithAudiences' 'optimizely_user', {'browser_type' => 'firefox'})
86
- end
87
-
88
- def self.test_track_with_revenue(testdata, optly)
89
- optly.track('testEvent', 'optimizely_user', nil, 666)
90
- end
91
-
92
- def self.test_track_with_attributes_and_revenue(testdata, optly)
93
- optly.track('testEventWithAudiences', 'optimizely_user', {'browser_type' => 'firefox'}, 666)
94
- end
95
-
96
- def self.test_track_grouped_exp(testdata, optly)
97
- optly.track('testEventWithMultipleGroupedExperiments', 'optimizely_user')
98
- end
99
-
100
- def self.test_track_grouped_exp_with_attributes(testdata, optly)
101
- optly.track('testEventWithMultipleExperiments', 'optimizely_user', {'browser_type' => 'firefox'})
102
- end
103
-
104
- def self.test_track_grouped_exp_with_revenue(testdata, optly)
105
- optly.track('testEventWithMultipleGroupedExperiments', 'optimizely_user', nil, 666)
106
- end
107
-
108
- def self.test_track_grouped_exp_with_attributes_and_revenue(testdata, optly)
109
- optly.track('testEventWithMultipleExperiments', 'optimizely_user', {'browser_type' => 'firefox'}, 666)
110
- end
111
- end
112
-
113
- def run_tests
114
- testdata10 = File.read('testdata_10.json')
115
- testdata25 = File.read('testdata_25.json')
116
- testdata50 = File.read('testdata_50.json')
117
- optly10 = Optimizely::Project.new(testdata10)
118
- optly25 = Optimizely::Project.new(testdata25)
119
- optly50 = Optimizely::Project.new(testdata50)
120
-
121
- tests = PerformanceTests.methods(false)
122
- tests.each do |test|
123
- puts '', test
124
- Benchmark.bmbm do |x|
125
- x.report('10 exps') { PerformanceTests.send(test, testdata10, optly10) }
126
- x.report('25 exps') { PerformanceTests.send(test, testdata25, optly25) }
127
- x.report('50 exps') { PerformanceTests.send(test, testdata50, optly50) }
128
- end
129
- end
130
- end
131
-