vwo-sdk 1.15.0 → 1.23.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.
data/lib/vwo/enums.rb CHANGED
@@ -106,13 +106,14 @@ class VWO
106
106
  IMPRESSION_FOR_TRACK_USER = '(%<file>s): Impression built for track-user - %<properties>s'
107
107
  IMPRESSION_FOR_TRACK_GOAL = '(%<file>s): Impression built for track-goal - %<properties>s'
108
108
  GOT_VARIATION_FOR_USER = '(%<file>s): userId:%<user_id>s for campaign:%<campaign_key>s got variationName:%<variation_name>s'
109
- SEGMENTATION_STATUS = '(%<file>s): In API: %<api_name>s, for UserId:%<user_id>s of campaign:%<campaign_key>s with variables:%<custom_variables>s %<status>s %<segmentation_type>s for %<variation_name>s'
109
+ SEGMENTATION_STATUS = '(%<file>s): In API: %<api_name>s, for UserId:%<user_id>s of campaign:%<campaign_key>s with variables:%<custom_variables>s %<status>s %<segmentation_type>s %<variation_name>s'
110
110
  PARAMS_FOR_PUSH_CALL = '(%<file>s): Params for push call - %<properties>s'
111
111
  CAMPAIGN_NOT_ACTIVATED = '(%<file>s): Campaign:%<campaign_key>s for User ID:%<user_id>s is not yet activated for API:%<api_name>s. Use activate API to activate A/B test or isFeatureEnabled API to activate Feature Test.'
112
112
  BATCH_EVENT_LIMIT_EXCEEDED = '(%<file>s): Impression event - %<end_point>s failed due to exceeding payload size. Parameter eventsPerRequest in batchEvents config in launch API has value:%<eventsPerRequest>s for accountId:%<accountId>s. Please read the official documentation for knowing the size limits.'
113
113
  BULK_NOT_PROCESSED = "(%<file>s): Batch events couldn't be received by VWO. Calling Flush Callback with error and data."
114
114
  BEFORE_FLUSHING = '(%<file>s): Flushing events queue %<manually>s having %<length>s events %<timer>s queue summary: %<queue_metadata>s'
115
115
  EVENT_BATCHING_INSUFFICIENT = '(%<file>s): %<key>s not provided, assigning default value'
116
+ GOT_ELIGIBLE_CAMPAIGNS = "(%<file>s): Campaigns:%<eligible_campaigns_key>s are eligible, %<ineligible_campaigns_log_text>s are ineligible from the Group:%<group_name>s for the User ID:%<user_id>s"
116
117
  end
117
118
 
118
119
  # Info Messages
@@ -142,7 +143,7 @@ class VWO
142
143
  USER_PASSED_SEGMENTATION = '(%<file>s): UserId:%<user_id>s of campaign:%<campaign_key>s with custom_variables:%<custom_variables>s passed segmentation'
143
144
  USER_FAILED_SEGMENTATION = '(%<file>s): UserId:%<user_id>s of campaign:%<campaign_key>s with custom_variables:%<custom_variables>s failed segmentation'
144
145
 
145
- NO_CUSTOM_VARIABLES = '(%<file>s): In API: %<api_name>s, for UserId:%<user_id>s preSegments/customVariables are not passed for campaign:%<campaign_key>s and campaign has pre-segmentation'
146
+ NO_CUSTOM_VARIABLES = '(%<file>s): In API: %<api_name>s, for UserId:%<user_id>s customVariables are not passed for campaign:%<campaign_key>s and campaign has pre-segmentation'
146
147
  SKIPPING_SEGMENTATION = '(%<file>s): In API: %<api_name>s, Skipping segmentation:%<variation>s for UserId:%<user_id>s as no valid segments found in campaign:%<campaign_key>s'
147
148
 
148
149
  SEGMENTATION_STATUS = '(%<file>s): In API: %<api_name>s, for UserId:%<user_id>s of campaign:%<campaign_key>s with variables:%<custom_variables>s %<status>s %<segmentation_type>s %<variation_name>s'
@@ -152,9 +153,13 @@ class VWO
152
153
  CAMPAIGN_NOT_ACTIVATED = '(%<file>s): Activate the campaign:%<campaign_key>s for User ID:%<user_id>s to %<reason>s.'
153
154
  GOAL_ALREADY_TRACKED = '(%<file>s): Goal:%<goal_identifier>s of Campaign:%<campaign_key>s for User ID:%<user_id>s has already been tracked earlier. Skipping now'
154
155
  USER_ALREADY_TRACKED = '(%<file>s): User ID:%<user_id>s for Campaign:%<campaign_key>s has already been tracked earlier for "%<api_name>s" API. Skipping now'
155
- API_CALLED = '(%<file>s): API: {api_name} called for UserId:%<user_id>s'
156
+ API_CALLED = '(%<file>s): API: %<api_name>s called for UserId:%<user_id>s'
156
157
  BULK_IMPRESSION_SUCCESS = '(%<file>s): Impression event - %<end_point>s was successfully received by VWO having accountId:%<a>s'
157
158
  AFTER_FLUSHING = '(%<file>s): Events queue having %<length>s events has been flushed %<manually>s queue summary: %<queue_metadata>s'
159
+ GOT_WINNER_CAMPAIGN = "(%<file>s): Campaign:%<campaign_key>s is selected from the mutually exclusive group:%<group_name>s for the User ID:%<user_id>s"
160
+ GOT_ELIGIBLE_CAMPAIGNS = "(%<file>s): Got %<no_of_eligible_campaigns>s eligible winners out of %<no_of_group_campaigns>s from the Group:%<group_name>s and for User ID:%<user_id>s"
161
+ CALLED_CAMPAIGN_NOT_WINNER = "(%<file>s): Campaign:%<campaign_key>s does not qualify from the mutually exclusive group:%<group_name>s for User ID:%<user_id>s"
162
+ OTHER_CAMPAIGN_SATISFIES_WHITELISTING_OR_STORAGE = "(%<file>s): Campaign:%<campaign_key>s of Group:%<group_name>s satisfies %<type>s for User ID:%<user_id>s"
158
163
  end
159
164
 
160
165
  # Warning Messages
data/lib/vwo/logger.rb CHANGED
@@ -28,8 +28,10 @@ class VWO
28
28
  end
29
29
 
30
30
  # Override this method to handle logs in a custom manner
31
- def log(level, message)
32
- @@logger_instance.log(level, message)
31
+ def log(level, message, disable_logs = false)
32
+ unless disable_logs
33
+ @@logger_instance.log(level, message)
34
+ end
33
35
  end
34
36
 
35
37
  def instance
@@ -54,7 +54,13 @@ class VWO
54
54
  },
55
55
  weight: {
56
56
  type: %w[number string]
57
- }
57
+ },
58
+ variables: {
59
+ type: 'array',
60
+ items: {
61
+ '$ref' => '#/definitions/variables_schema'
62
+ }
63
+ }
58
64
  },
59
65
  required: %w[id name weight]
60
66
  },
@@ -79,9 +85,34 @@ class VWO
79
85
  '$ref' => '#/definitions/campaign_variation_schema'
80
86
  }
81
87
  },
88
+ variables: {
89
+ type: 'array',
90
+ items: {
91
+ '$ref' => '#/definitions/variables_schema'
92
+ }
93
+ },
94
+ isBucketingSeedEnabled: ['boolean'],
82
95
  minItems: 2
83
96
  }
84
97
  },
98
+ variables_schema: {
99
+ type: 'object',
100
+ properties: {
101
+ id: {
102
+ type: %w[number string]
103
+ },
104
+ key: {
105
+ type: ['string']
106
+ },
107
+ type: {
108
+ type: ['string']
109
+ },
110
+ value: {
111
+ type: %w[number string boolean double object]
112
+ }
113
+ },
114
+ required: %w[id key type value]
115
+ },
85
116
  required: %w[
86
117
  id
87
118
  key
@@ -91,11 +91,10 @@ class VWO
91
91
  # @return [Boolean]
92
92
  def evaluate_custom_variable?(operand, custom_variables)
93
93
  # Extract custom_variable_key and custom_variables_value from operand
94
-
95
94
  operand_key, operand = get_key_value(operand)
96
95
 
97
96
  # Retrieve corresponding custom_variable value from custom_variables
98
- custom_variables_value = custom_variables[operand_key]
97
+ custom_variables_value = custom_variables[operand_key.to_sym]
99
98
 
100
99
  # Pre process custom_variable value
101
100
  custom_variables_value = process_custom_variables_value(custom_variables_value)
@@ -113,7 +112,7 @@ class VWO
113
112
  def evaluate_user?(operand, custom_variables)
114
113
  users = operand.split(',')
115
114
  users.each do |user|
116
- return true if user.strip == custom_variables['_vwo_user_id']
115
+ return true if user.strip == custom_variables[:_vwo_user_id]
117
116
  end
118
117
  false
119
118
  end
@@ -63,10 +63,11 @@ class VWO
63
63
  # @param[String] :user_id Unique user identifier
64
64
  # @param[Hash] :dsl Segments provided in the settings_file
65
65
  # @param[Hash] :custom_variables Custom variables provided in the apis
66
+ # @param[Boolean] :disable_logs disable logs if True
66
67
  #
67
68
  # @return[Boolean] true if user passed pre-segmentation, else false
68
69
  #
69
- def evaluate(campaign_key, user_id, dsl, custom_variables)
70
+ def evaluate(campaign_key, user_id, dsl, custom_variables, disable_logs = false)
70
71
  result = evaluate_util(dsl, custom_variables) if valid_value?(dsl)
71
72
  result
72
73
  rescue StandardError => e
@@ -79,7 +80,8 @@ class VWO
79
80
  campaign_key: campaign_key,
80
81
  custom_variables: custom_variables,
81
82
  error_message: e
82
- )
83
+ ),
84
+ disable_logs
83
85
  )
84
86
  false
85
87
  end
@@ -57,6 +57,26 @@ class VWO
57
57
  end
58
58
  end
59
59
 
60
+ # Sets campaign allocation range in the provided campaigns list
61
+ #
62
+ # @param [Array]: Array of Campaigns
63
+ def set_campaign_allocation(campaigns)
64
+ current_allocation = 0
65
+ campaigns.each do |campaign|
66
+ step_factor = get_variation_bucketing_range(campaign['weight'])
67
+ if step_factor > 0
68
+ start_range = current_allocation + 1
69
+ end_range = current_allocation + step_factor
70
+ campaign['min_range'] = start_range
71
+ campaign['max_range'] = end_range
72
+ current_allocation += step_factor
73
+ else
74
+ campaign['min_range'] = -1
75
+ campaign['max_range'] = -1
76
+ end
77
+ end
78
+ end
79
+
60
80
  # Returns goal from given campaign_key and gaol_identifier.
61
81
  # @param[String] :campaign Campaign object
62
82
  # @param[String] :goal_identifier Goal identifier
@@ -249,6 +269,44 @@ class VWO
249
269
  return campaign
250
270
  end
251
271
 
272
+ # Checks whether a campaign is part of a group.
273
+ #
274
+ # @param[Hash] :settings_file Settings file for the project
275
+ # @param[Integer] :campaign_id Id of campaign which is to be checked
276
+ # @return[Boolean]
277
+ def is_part_of_group(settings_file, campaign_id)
278
+ if settings_file["campaignGroups"] && (settings_file["campaignGroups"].has_key?(campaign_id.to_s))
279
+ return true
280
+ end
281
+ false
282
+ end
283
+
284
+ # Returns campaigns which are part of given group using group_id.
285
+ #
286
+ # @param[Hash] :settings_file Settings file for the project
287
+ # @param[Integer] :group_id id of group whose campaigns are to be return
288
+ # @return[Array]
289
+ def get_group_campaigns(settings_file, group_id)
290
+ group_campaign_ids = []
291
+ group_campaigns = []
292
+ groups = settings_file["groups"]
293
+
294
+ if groups && groups.has_key?(group_id.to_s)
295
+ group_campaign_ids = groups[group_id.to_s]["campaigns"]
296
+ end
297
+
298
+ if group_campaign_ids
299
+ group_campaign_ids.each do |campaign_id|
300
+ settings_file["campaigns"].each do |campaign|
301
+ if campaign["id"] == campaign_id && campaign["status"] == STATUS_RUNNING
302
+ group_campaigns.push(campaign)
303
+ end
304
+ end
305
+ end
306
+ end
307
+ group_campaigns
308
+ end
309
+
252
310
  end
253
311
  end
254
312
  end
@@ -38,6 +38,8 @@ class VWO
38
38
  return value.to_f if variable_type == VariableTypes::DOUBLE
39
39
 
40
40
  return !value || value == 0 ? false : true if variable_type == VariableTypes.BOOLEAN
41
+
42
+ return value if variable_type == VariableTypes::JSON
41
43
  rescue StandardError => _e
42
44
  VWO::Logger.get_instance.log(
43
45
  LogLevelEnum::ERROR,
@@ -0,0 +1,40 @@
1
+ # Copyright 2019-2021 Wingify Software Pvt. Ltd.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'json'
16
+ require_relative './validations'
17
+
18
+ # Generic utility module
19
+ class VWO
20
+ module Utils
21
+ module Utility
22
+ include Validations
23
+
24
+ # converting hash with keys as strings into hash with keys as strings
25
+ # @param[Hash]
26
+ # @return[Hash]
27
+ def convert_to_symbol_hash(hashObject)
28
+ convertedHash = {}
29
+ hashObject.each do |key, value|
30
+ if valid_hash?(value)
31
+ convertedHash[key.to_sym] = convert_to_symbol_hash(value)
32
+ else
33
+ convertedHash[key.to_sym] = value
34
+ end
35
+ end
36
+ convertedHash
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/vwo.rb CHANGED
@@ -23,6 +23,7 @@ require_relative 'vwo/utils/campaign'
23
23
  require_relative 'vwo/utils/impression'
24
24
  require_relative 'vwo/utils/feature'
25
25
  require_relative 'vwo/utils/custom_dimensions'
26
+ require_relative 'vwo/utils/utility'
26
27
  require_relative 'vwo/constants'
27
28
  require_relative 'vwo/core/variation_decider'
28
29
  require_relative 'vwo/services/batch_events_dispatcher'
@@ -39,6 +40,7 @@ class VWO
39
40
  include Utils::CustomDimensions
40
41
  include Utils::Campaign
41
42
  include Utils::Impression
43
+ include Utils::Utility
42
44
  include CONSTANTS
43
45
 
44
46
  FILE = FileNameEnum::VWO
@@ -62,6 +64,7 @@ class VWO
62
64
  settings_file = nil,
63
65
  options = {}
64
66
  )
67
+ options = convert_to_symbol_hash(options)
65
68
  @account_id = account_id
66
69
  @sdk_key = sdk_key
67
70
  @user_storage = user_storage
@@ -295,9 +298,10 @@ class VWO
295
298
  return
296
299
  end
297
300
 
301
+ options = convert_to_symbol_hash(options)
298
302
  # Retrieve custom variables
299
- custom_variables = options['custom_variables'] || options[:custom_variables]
300
- variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
303
+ custom_variables = options[:custom_variables]
304
+ variation_targeting_variables = options[:variation_targeting_variables]
301
305
 
302
306
  should_track_returning_user = get_should_track_returning_user(options)
303
307
  # Validate input parameters
@@ -413,7 +417,6 @@ class VWO
413
417
  )
414
418
  end
415
419
  end
416
- variation['name']
417
420
  else
418
421
  @logger.log(
419
422
  LogLevelEnum::INFO,
@@ -425,8 +428,8 @@ class VWO
425
428
  api_name: ApiMethods::ACTIVATE
426
429
  )
427
430
  )
428
- nil
429
431
  end
432
+ variation['name']
430
433
  rescue StandardError => e
431
434
  @logger.log(
432
435
  LogLevelEnum::ERROR,
@@ -469,9 +472,10 @@ class VWO
469
472
  )
470
473
  return
471
474
  end
475
+ options = convert_to_symbol_hash(options)
472
476
  # Retrieve custom variables
473
- custom_variables = options['custom_variables'] || options[:custom_variables]
474
- variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
477
+ custom_variables = options[:custom_variables]
478
+ variation_targeting_variables = options[:variation_targeting_variables]
475
479
 
476
480
  # Validate input parameters
477
481
  unless valid_string?(campaign_key) && valid_string?(user_id) && (custom_variables.nil? || valid_hash?(custom_variables)) &&
@@ -580,9 +584,10 @@ class VWO
580
584
  return false
581
585
  end
582
586
 
583
- revenue_value = options['revenue_value'] || options[:revenue_value]
584
- custom_variables = options['custom_variables'] || options[:custom_variables]
585
- variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
587
+ options = convert_to_symbol_hash(options)
588
+ revenue_value = options[:revenue_value]
589
+ custom_variables = options[:custom_variables]
590
+ variation_targeting_variables = options[:variation_targeting_variables]
586
591
  should_track_returning_user = get_should_track_returning_user(options)
587
592
  goal_type_to_track = get_goal_type_to_track(options)
588
593
 
@@ -676,7 +681,7 @@ class VWO
676
681
  if !identifiers.include? goal_identifier
677
682
  updated_goal_identifier = variation['goal_identifier']
678
683
  updated_goal_identifier += VWO_DELIMITER + goal_identifier
679
- @variation_decider.save_user_storage(user_id, campaign['key'], variation['name'], updated_goal_identifier) if variation['name']
684
+ @variation_decider.save_user_storage(user_id, campaign['key'], campaign['name'], variation['name'], updated_goal_identifier) if variation['name']
680
685
  # set variation at user storage
681
686
  elsif !should_track_returning_user
682
687
  @logger.log(
@@ -800,9 +805,10 @@ class VWO
800
805
  return false
801
806
  end
802
807
 
808
+ options = convert_to_symbol_hash(options)
803
809
  # Retrieve custom variables
804
- custom_variables = options['custom_variables'] || options[:custom_variables]
805
- variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
810
+ custom_variables = options[:custom_variables]
811
+ variation_targeting_variables = options[:variation_targeting_variables]
806
812
  should_track_returning_user = get_should_track_returning_user(options)
807
813
  @logger.log(
808
814
  LogLevelEnum::INFO,
@@ -870,80 +876,85 @@ class VWO
870
876
  return false unless variation
871
877
 
872
878
  # if campaign type is feature_test Send track call to server
873
- if campaign_type == CampaignTypes::FEATURE_TEST
874
- if is_eligible_to_send_impression(should_track_returning_user)
875
- if defined?(@batch_events)
876
- impression = create_bulk_event_impression(
877
- @settings_file,
878
- campaign['id'],
879
- variation['id'],
880
- user_id
881
- )
882
- @batch_events_queue.enqueue(impression)
883
- else
884
- impression = create_impression(
885
- @settings_file,
886
- campaign['id'],
887
- variation['id'],
888
- user_id,
889
- @sdk_key,
890
- goal_id: nil,
891
- revenue: nil,
892
- usage_stats: @usage_stats.usage_stats
893
- )
894
879
 
895
- @event_dispatcher.dispatch(impression)
896
- @logger.log(
897
- LogLevelEnum::INFO,
898
- format(
899
- LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
900
- file: FILE,
901
- campaign_id: impression[:experiment_id],
902
- sdk_key: @sdk_key,
903
- account_id: impression[:account_id],
904
- variation_id: impression[:combination]
905
- )
906
- )
907
- end
908
- result = variation['isFeatureEnabled']
909
- if result
910
- @logger.log(
911
- LogLevelEnum::INFO,
912
- format(
913
- LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
914
- file: FILE,
915
- user_id: user_id,
916
- feature_key: campaign_key,
917
- api_name: ApiMethods::IS_FEATURE_ENABLED
918
- )
919
- )
920
- else
921
- @logger.log(
922
- LogLevelEnum::INFO,
923
- format(
924
- LogMessageEnum::InfoMessages::FEATURE_NOT_ENABLED_FOR_USER,
925
- file: FILE,
926
- user_id: user_id,
927
- feature_key: campaign_key,
928
- api_name: ApiMethods::IS_FEATURE_ENABLED
929
- )
930
- )
931
- end
932
- return result
880
+ if is_eligible_to_send_impression(should_track_returning_user)
881
+ if defined?(@batch_events)
882
+ impression = create_bulk_event_impression(
883
+ @settings_file,
884
+ campaign['id'],
885
+ variation['id'],
886
+ user_id
887
+ )
888
+ @batch_events_queue.enqueue(impression)
933
889
  else
890
+ impression = create_impression(
891
+ @settings_file,
892
+ campaign['id'],
893
+ variation['id'],
894
+ user_id,
895
+ @sdk_key,
896
+ nil,
897
+ nil,
898
+ usage_stats: @usage_stats.usage_stats
899
+ )
900
+
901
+ @event_dispatcher.dispatch(impression)
934
902
  @logger.log(
935
903
  LogLevelEnum::INFO,
936
904
  format(
937
- LogMessageEnum::InfoMessages::USER_ALREADY_TRACKED,
905
+ LogMessageEnum::InfoMessages::MAIN_KEYS_FOR_IMPRESSION,
938
906
  file: FILE,
939
- user_id: user_id,
940
- campaign_key: campaign_key,
941
- api_name: ApiMethods::IS_FEATURE_ENABLED
907
+ campaign_id: impression[:experiment_id],
908
+ sdk_key: @sdk_key,
909
+ account_id: impression[:account_id],
910
+ variation_id: impression[:combination]
942
911
  )
943
912
  )
944
913
  end
914
+
915
+ else
916
+ @logger.log(
917
+ LogLevelEnum::INFO,
918
+ format(
919
+ LogMessageEnum::InfoMessages::USER_ALREADY_TRACKED,
920
+ file: FILE,
921
+ user_id: user_id,
922
+ campaign_key: campaign_key,
923
+ api_name: ApiMethods::IS_FEATURE_ENABLED
924
+ )
925
+ )
945
926
  end
946
- true
927
+ if campaign_type == CampaignTypes::FEATURE_ROLLOUT
928
+ result = true
929
+ else
930
+ result = variation['isFeatureEnabled']
931
+ end
932
+
933
+ if result
934
+ @logger.log(
935
+ LogLevelEnum::INFO,
936
+ format(
937
+ LogMessageEnum::InfoMessages::FEATURE_ENABLED_FOR_USER,
938
+ file: FILE,
939
+ user_id: user_id,
940
+ feature_key: campaign_key,
941
+ api_name: ApiMethods::IS_FEATURE_ENABLED
942
+ )
943
+ )
944
+ else
945
+ @logger.log(
946
+ LogLevelEnum::INFO,
947
+ format(
948
+ LogMessageEnum::InfoMessages::FEATURE_NOT_ENABLED_FOR_USER,
949
+ file: FILE,
950
+ user_id: user_id,
951
+ feature_key: campaign_key,
952
+ api_name: ApiMethods::IS_FEATURE_ENABLED
953
+ )
954
+ )
955
+ end
956
+
957
+ result
947
958
  rescue StandardError => e
948
959
  @logger.log(
949
960
  LogLevelEnum::ERROR,
@@ -989,9 +1000,10 @@ class VWO
989
1000
  return
990
1001
  end
991
1002
 
1003
+ options = convert_to_symbol_hash(options)
992
1004
  # Retrieve custom variables
993
- custom_variables = options['custom_variables'] || options[:custom_variables]
994
- variation_targeting_variables = options['variation_targeting_variables'] || options[:variation_targeting_variables]
1005
+ custom_variables = options[:custom_variables]
1006
+ variation_targeting_variables = options[:variation_targeting_variables]
995
1007
 
996
1008
  unless valid_string?(campaign_key) && valid_string?(variable_key) && valid_string?(user_id) &&
997
1009
  (custom_variables.nil? || valid_hash?(custom_variables)) && (variation_targeting_variables.nil? || valid_hash?(variation_targeting_variables))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vwo-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.15.0
4
+ version: 1.23.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - VWO
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-23 00:00:00.000000000 Z
11
+ date: 2021-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: codecov
@@ -111,6 +111,7 @@ files:
111
111
  - lib/vwo/utils/impression.rb
112
112
  - lib/vwo/utils/request.rb
113
113
  - lib/vwo/utils/segment.rb
114
+ - lib/vwo/utils/utility.rb
114
115
  - lib/vwo/utils/uuid.rb
115
116
  - lib/vwo/utils/validations.rb
116
117
  homepage: https://vwo.com/fullstack/server-side-testing/