kameleoon-client-ruby 3.3.0 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kameleoon/configuration/custom_data_info.rb +16 -8
  3. data/lib/kameleoon/configuration/data_file.rb +52 -16
  4. data/lib/kameleoon/configuration/feature_flag.rb +11 -1
  5. data/lib/kameleoon/configuration/rule.rb +4 -0
  6. data/lib/kameleoon/configuration/settings.rb +13 -8
  7. data/lib/kameleoon/configuration/variation_exposition.rb +4 -0
  8. data/lib/kameleoon/data/browser.rb +4 -0
  9. data/lib/kameleoon/data/conversion.rb +4 -0
  10. data/lib/kameleoon/data/cookie.rb +4 -0
  11. data/lib/kameleoon/data/custom_data.rb +11 -3
  12. data/lib/kameleoon/data/data.rb +30 -4
  13. data/lib/kameleoon/data/device.rb +4 -0
  14. data/lib/kameleoon/data/geolocation.rb +5 -0
  15. data/lib/kameleoon/data/kcs_heat.rb +4 -0
  16. data/lib/kameleoon/data/manager/assigned_variation.rb +8 -1
  17. data/lib/kameleoon/data/manager/data_array_storage.rb +7 -0
  18. data/lib/kameleoon/data/manager/data_map_storage.rb +7 -0
  19. data/lib/kameleoon/data/manager/page_view_visit.rb +4 -0
  20. data/lib/kameleoon/data/manager/visitor.rb +197 -73
  21. data/lib/kameleoon/data/manager/visitor_manager.rb +54 -17
  22. data/lib/kameleoon/data/mapping_identifier.rb +33 -0
  23. data/lib/kameleoon/data/operating_system.rb +4 -0
  24. data/lib/kameleoon/data/page_view.rb +6 -1
  25. data/lib/kameleoon/data/unique_identifier.rb +11 -0
  26. data/lib/kameleoon/data/user_agent.rb +4 -0
  27. data/lib/kameleoon/data/visitor_visits.rb +4 -0
  28. data/lib/kameleoon/hybrid/manager.rb +19 -7
  29. data/lib/kameleoon/kameleoon_client.rb +477 -178
  30. data/lib/kameleoon/kameleoon_client_config.rb +65 -18
  31. data/lib/kameleoon/kameleoon_client_factory.rb +15 -2
  32. data/lib/kameleoon/logging/default_logger.rb +20 -0
  33. data/lib/kameleoon/logging/kameleoon_logger.rb +77 -0
  34. data/lib/kameleoon/logging/logger.rb +12 -0
  35. data/lib/kameleoon/managers/data/data_manager.rb +36 -0
  36. data/lib/kameleoon/managers/remote_data/remote_data_manager.rb +32 -15
  37. data/lib/kameleoon/managers/tracking/tracking_builder.rb +149 -0
  38. data/lib/kameleoon/managers/tracking/tracking_manager.rb +98 -0
  39. data/lib/kameleoon/managers/tracking/visitor_tracking_registry.rb +94 -0
  40. data/lib/kameleoon/managers/warehouse/warehouse_manager.rb +22 -5
  41. data/lib/kameleoon/network/access_token_source.rb +46 -14
  42. data/lib/kameleoon/network/cookie/cookie_manager.rb +46 -7
  43. data/lib/kameleoon/network/net_provider.rb +2 -3
  44. data/lib/kameleoon/network/network_manager.rb +17 -21
  45. data/lib/kameleoon/network/request.rb +14 -3
  46. data/lib/kameleoon/network/response.rb +4 -0
  47. data/lib/kameleoon/network/url_provider.rb +3 -3
  48. data/lib/kameleoon/real_time/real_time_configuration_service.rb +10 -11
  49. data/lib/kameleoon/sdk_version.rb +31 -0
  50. data/lib/kameleoon/targeting/condition.rb +4 -2
  51. data/lib/kameleoon/targeting/conditions/browser_condition.rb +3 -3
  52. data/lib/kameleoon/targeting/conditions/cookie_condition.rb +10 -10
  53. data/lib/kameleoon/targeting/conditions/geolocation_condition.rb +0 -1
  54. data/lib/kameleoon/targeting/conditions/number_condition.rb +4 -4
  55. data/lib/kameleoon/targeting/conditions/operating_system_condition.rb +1 -2
  56. data/lib/kameleoon/targeting/conditions/sdk_language_condition.rb +2 -1
  57. data/lib/kameleoon/targeting/conditions/segment_condition.rb +3 -3
  58. data/lib/kameleoon/targeting/conditions/string_value_condition.rb +2 -1
  59. data/lib/kameleoon/targeting/models.rb +0 -14
  60. data/lib/kameleoon/targeting/targeting_manager.rb +35 -7
  61. data/lib/kameleoon/targeting/tree_builder.rb +10 -5
  62. data/lib/kameleoon/types/remote_visitor_data_filter.rb +13 -0
  63. data/lib/kameleoon/types/variable.rb +4 -0
  64. data/lib/kameleoon/types/variation.rb +8 -0
  65. data/lib/kameleoon/utils.rb +49 -0
  66. data/lib/kameleoon/version.rb +1 -27
  67. metadata +12 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '019ae7a1fe145f50f68beea1eb05bcae993d4061a2b1bdb2fe4324fc4215aa39'
4
- data.tar.gz: fe9637047ba81b006c1b19a4c85e82fa5641a4d3f666fe14cb28ee243076b6ac
3
+ metadata.gz: 283250365ae9bf4087ebffeb7a4de0e31cca91f06a865cdd4ad2cae1f88c692c
4
+ data.tar.gz: 31ab8ddbd1ef7524b41019a0afe442a47ee5b5e9e1d50649ed04aab625d7c3a3
5
5
  SHA512:
6
- metadata.gz: 5455718dd4a68c584c280e4004ff1c96e28b35d7bfcd9bd8299c68b9d0f3930bd064e16057ce71bbfc386911f106839f54a6398165e6966cad5ce5a4388ccbe9
7
- data.tar.gz: 7a2e231a4625c642a56354615999543c26d7e882d8fc7a2c743f7f4f045d01bc88d5dafd227757fd88f308053610f22f21bfa6cbadd79eafe2b7f2bc3a5e03b7
6
+ metadata.gz: 23f61dd193ad1bb7477ee44e0e2eb5c16bec625748b9ebdde37a9a6b9e71a4610a98c218a4e76addb66a5a55ecf2bcae1764f2aac8d9f9f8ebb6bbc3be86e318
7
+ data.tar.gz: d27d91e39fb5bc968ba414016642de07baef8ef7888f1d93969ae5fb67f07b903ba60b981de9387fa5c6eb20e99bd647d965fea0123841348f67a8aa66840f99
@@ -1,25 +1,28 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kameleoon/logging/kameleoon_logger'
4
+
3
5
  module Kameleoon
4
6
  # Module which contains all internal data of SDK
5
7
  module Configuration
6
-
7
8
  class CustomDataInfo
8
9
  attr_reader :local_only, :visitor_scope, :mapping_identifier_index
10
+
9
11
  SCOPE_VISITOR = 'VISITOR'
10
12
 
11
- def initialize(hashes, log_func = nil)
13
+ def initialize(hashes)
12
14
  @local_only = Set[]
13
15
  @visitor_scope = Set[]
14
- @log_func = log_func
15
16
  unless hashes.nil?
16
17
  for hash in hashes
17
18
  index = hash['index']
18
19
  @local_only.add(index) if hash['localOnly']
19
20
  @visitor_scope.add(index) if hash['scope'] == SCOPE_VISITOR
20
21
  if hash['isMappingIdentifier']
21
- if @mapping_identifier_index != nil
22
- @log_func&.call('More than one mapping identifier is set. Undefined behavior may occur on cross-device reconciliation.')
22
+ unless @mapping_identifier_index.nil?
23
+ Logging::KameleoonLogger.warning('More than one mapping identifier is set. Undefined behavior ' \
24
+ 'may occur on cross-device reconciliation.')
25
+
23
26
  end
24
27
  @mapping_identifier_index = index
25
28
  end
@@ -27,17 +30,22 @@ module Kameleoon
27
30
  end
28
31
  end
29
32
 
30
- def local_only? (index)
33
+ def local_only?(index)
31
34
  @local_only.include?(index)
32
35
  end
33
36
 
34
- def mapping_identifier? (index)
37
+ def mapping_identifier?(index)
35
38
  index == @mapping_identifier_index
36
39
  end
37
40
 
38
- def visitor_scope? (index)
41
+ def visitor_scope?(index)
39
42
  @visitor_scope.include?(index)
40
43
  end
44
+
45
+ def self.mapping_identifier?(custom_data_info, custom_data)
46
+ !custom_data_info.nil? && (custom_data.id == custom_data_info.mapping_identifier_index) && \
47
+ !(custom_data.values.empty? || custom_data.values[0].empty?)
48
+ end
41
49
  end
42
50
  end
43
51
  end
@@ -3,32 +3,32 @@
3
3
  require 'kameleoon/configuration/settings'
4
4
  require 'kameleoon/configuration/feature_flag'
5
5
  require 'kameleoon/configuration/custom_data_info'
6
+ require 'kameleoon/logging/kameleoon_logger'
6
7
 
7
8
  module Kameleoon
8
9
  module Configuration
9
10
  class DataFile
10
11
  attr_reader :settings, :feature_flags, :has_any_targeted_delivery_rule, :feature_flag_by_id, :rule_by_segment_id,
11
- :variation_by_id, :custom_data_info
12
+ :variation_by_id, :custom_data_info, :experiment_ids_with_js_css_variable
12
13
 
13
- def initialize(environment, log_func = nil)
14
- @settings = Settings.new
15
- @feature_flags = {}
16
- @environment = environment
17
- @log_func = log_func
18
- collect_indices
19
- @custom_data_info = Kameleoon::Configuration::CustomDataInfo.new(nil, @log_func)
14
+ def to_s
15
+ 'DataFile{' \
16
+ "environment:#{@environment}," \
17
+ "feature_flags:#{@feature_flags.size}," \
18
+ "settings:#{@settings}" \
19
+ '}'
20
20
  end
21
21
 
22
- def init(configuration)
23
- @settings.update(configuration['configuration'])
24
- configuration['featureFlags'].each do |raw|
25
- ff = FeatureFlag.new(raw)
26
- @feature_flags[ff.feature_key] = ff
22
+ def initialize(environment, configuration = nil)
23
+ Logging::KameleoonLogger.debug('CALL: DataFile.new(environment: %s)', environment)
24
+ @environment = environment
25
+ if configuration.nil?
26
+ init_default
27
+ else
28
+ init(configuration)
27
29
  end
28
- @has_any_targeted_delivery_rule = any_targeted_delivery_rule?
29
30
  collect_indices
30
- @custom_data_info = CustomDataInfo.new(configuration['customData'], @log_func)
31
- self
31
+ Logging::KameleoonLogger.debug('RETURN: DataFile.new(environment: %s)', environment)
32
32
  end
33
33
 
34
34
  def get_feature_flag(feature_key)
@@ -39,8 +39,34 @@ module Kameleoon
39
39
  ff
40
40
  end
41
41
 
42
+ def experiment_js_css_variable?(experiment_id)
43
+ @experiment_ids_with_js_css_variable.include?(experiment_id)
44
+ end
45
+
42
46
  private
43
47
 
48
+ def init_default
49
+ Logging::KameleoonLogger.debug('CALL: DataFile.init_default')
50
+ @settings = Settings.new
51
+ @feature_flags = {}
52
+ @has_any_targeted_delivery_rule = false
53
+ @custom_data_info = Kameleoon::Configuration::CustomDataInfo.new(nil)
54
+ Logging::KameleoonLogger.debug('RETURN: DataFile.init_default')
55
+ end
56
+
57
+ def init(configuration)
58
+ Logging::KameleoonLogger.debug('CALL: DataFile.init(configuration: %s)', configuration)
59
+ @settings = Settings.new(configuration['configuration'])
60
+ @feature_flags = {}
61
+ configuration['featureFlags'].each do |raw|
62
+ ff = FeatureFlag.new(raw)
63
+ @feature_flags[ff.feature_key] = ff
64
+ end
65
+ @has_any_targeted_delivery_rule = any_targeted_delivery_rule?
66
+ @custom_data_info = CustomDataInfo.new(configuration['customData'])
67
+ Logging::KameleoonLogger.debug('RETURN: DataFile.init(configuration: %s)', configuration)
68
+ end
69
+
44
70
  def any_targeted_delivery_rule?
45
71
  @feature_flags.any? { |_, ff| ff.environment_enabled && ff.rules.any?(&:targeted_delivery_type?) }
46
72
  end
@@ -49,21 +75,31 @@ module Kameleoon
49
75
  @feature_flag_by_id = {}
50
76
  @rule_by_segment_id = {}
51
77
  @variation_by_id = {}
78
+ @experiment_ids_with_js_css_variable = Set.new
52
79
 
53
80
  @feature_flags.each_value do |feature_flag|
54
81
  @feature_flag_by_id[feature_flag.id] = feature_flag
55
82
  next if feature_flag.rules.nil?
56
83
 
84
+ has_feature_flag_variable_js_css = feature_flag_variable_js_css?(feature_flag)
57
85
  feature_flag.rules.each do |rule|
58
86
  @rule_by_segment_id[rule.segment_id] = rule
59
87
  rule.variation_by_exposition.each do |variation|
60
88
  @variation_by_id[variation.variation_id] = variation
61
89
  end
90
+ @experiment_ids_with_js_css_variable.add(rule.experiment_id) if has_feature_flag_variable_js_css
62
91
  end
63
92
  end
64
93
  @feature_flag_by_id.freeze
65
94
  @rule_by_segment_id.freeze
66
95
  @variation_by_id.freeze
96
+ @experiment_ids_with_js_css_variable.freeze
97
+ end
98
+
99
+ def feature_flag_variable_js_css?(feature_flag)
100
+ feature_flag.variations.first&.variables&.any? do |variable|
101
+ %w[JS CSS].include?(variable.type)
102
+ end
67
103
  end
68
104
  end
69
105
  end
@@ -14,6 +14,16 @@ module Kameleoon
14
14
  array&.map { |it| FeatureFlag.new(it) }
15
15
  end
16
16
 
17
+ def to_s
18
+ 'FeatureFlag{' \
19
+ "id:#{@id}, " \
20
+ "feature_key:#{@feature_key}, " \
21
+ "environment_enabled:#{@environment_enabled}, " \
22
+ "default_variation_key:#{@default_variation_key}, " \
23
+ "rules:#{@rules.size}" \
24
+ '}'
25
+ end
26
+
17
27
  def initialize(hash)
18
28
  @id = hash['id']
19
29
  @feature_key = hash['featureKey']
@@ -23,7 +33,7 @@ module Kameleoon
23
33
  @rules = Rule.create_from_array(hash['rules'])
24
34
  end
25
35
 
26
- def get_variation_key(key)
36
+ def get_variation_by_key(key)
27
37
  variations.select { |v| v.key == key }.first
28
38
  end
29
39
  end
@@ -36,6 +36,10 @@ module Kameleoon
36
36
  array&.map { |it| Rule.new(it) }
37
37
  end
38
38
 
39
+ def to_s
40
+ "Rule{id:#{@id}}"
41
+ end
42
+
39
43
  def initialize(hash)
40
44
  @id = hash['id']
41
45
  @order = hash['order']
@@ -9,16 +9,21 @@ module Kameleoon
9
9
  attr_accessor :real_time_update
10
10
  attr_reader :is_consent_required, :data_api_domain
11
11
 
12
- def initialize
13
- @real_time_update = false
14
- @is_consent_required = false
15
- @data_api_domain = nil
12
+ def to_s
13
+ "Settings{real_time_update:#{@real_time_update},is_consent_required:#{@is_consent_required}," \
14
+ "data_api_domain:#{@data_api_domain}}"
16
15
  end
17
16
 
18
- def update(configuration)
19
- @real_time_update = configuration['realTimeUpdate'] || false
20
- @is_consent_required = configuration['consentType'] == 'REQUIRED'
21
- @data_api_domain = configuration['dataApiDomain']
17
+ def initialize(configuration = nil)
18
+ if configuration.nil?
19
+ @real_time_update = false
20
+ @is_consent_required = false
21
+ @data_api_domain = nil
22
+ else
23
+ @real_time_update = configuration['realTimeUpdate'] || false
24
+ @is_consent_required = configuration['consentType'] == 'REQUIRED'
25
+ @data_api_domain = configuration['dataApiDomain']
26
+ end
22
27
  end
23
28
  end
24
29
  end
@@ -11,6 +11,10 @@ module Kameleoon
11
11
  array&.map { |it| VariationByExposition.new(it) }
12
12
  end
13
13
 
14
+ def to_s
15
+ "VariationByExposition{exposition:#{@exposition},variation_key:#{@variation_key},variation_id:#{@variation_id}}"
16
+ end
17
+
14
18
  def initialize(hash)
15
19
  @variation_key = hash['variationKey']
16
20
  @variation_id = hash['variationId']
@@ -37,6 +37,10 @@ module Kameleoon
37
37
  class Browser < DuplicationUnsafeData
38
38
  attr_reader :type, :version
39
39
 
40
+ def to_s
41
+ "Browser{type:#{@type},version:#{@version}}"
42
+ end
43
+
40
44
  # @param [BrowserType] browser_type Browser type, can be: CHROME, INTERNET_EXPLORER, FIREFOX, SAFARI, OPERA, OTHER
41
45
  # @param [float] version Version of browser
42
46
  def initialize(browser_type, version = Float::NAN)
@@ -9,6 +9,10 @@ module Kameleoon
9
9
  class Conversion < DuplicationSafeData
10
10
  attr_reader :goal_id, :revenue, :negative
11
11
 
12
+ def to_s
13
+ "Conversion{goal_id:#{@goal_id},revenue:#{@revenue},negative:#{@negative}}"
14
+ end
15
+
12
16
  # @param [Integer] goal_id Id of the goal associated to the conversion
13
17
  # @param [Float] revenue Optional field - Revenue associated to the conversion.
14
18
  # @param [Boolean] negative Optional field - If the revenue is negative. By default it's positive.
@@ -9,6 +9,10 @@ module Kameleoon
9
9
  def initialize(cookies)
10
10
  @cookies = cookies
11
11
  end
12
+
13
+ def to_s
14
+ "Cookie{cookies:#{@cookies}}"
15
+ end
12
16
  end
13
17
  end
14
18
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
+ require 'kameleoon/logging/kameleoon_logger'
4
5
  require 'kameleoon/network/uri_helper'
5
6
  require_relative 'data'
6
7
 
@@ -8,7 +9,10 @@ module Kameleoon
8
9
  # Represents any custom data for targeting conditions
9
10
  class CustomData < DuplicationUnsafeData
10
11
  attr_reader :id, :values
11
- attr_accessor :is_mapping_identifier
12
+
13
+ def to_s
14
+ "CustomData{id:#{@id},values:#{@values}}"
15
+ end
12
16
 
13
17
  # @param [Integer] id Id of the custom data
14
18
  # @param [String] value Value of the custom data
@@ -33,9 +37,14 @@ module Kameleoon
33
37
  @id = arg0
34
38
  @values = args
35
39
  end
40
+
41
+ if @values.empty?
42
+ Logging::KameleoonLogger.error('Created a custom data %s with no values. It will not be tracked.', @id)
43
+ end
44
+
36
45
  return if @id.is_a?(Integer)
37
46
 
38
- warn "CustomData field 'id' must be of 'Integer' type"
47
+ Logging::KameleoonLogger.warning("CustomData field 'id' must be of 'Integer' type")
39
48
  @id = @id.is_a?(String) ? @id.to_i : -1
40
49
  end
41
50
  # rubocop:enable Metrics/MethodLength
@@ -51,7 +60,6 @@ module Kameleoon
51
60
  overwrite: 'true',
52
61
  nonce: nonce
53
62
  }
54
- params[:mappingIdentifier] = is_mapping_identifier if is_mapping_identifier
55
63
  Kameleoon::Network::UriHelper.encode_query(params)
56
64
  end
57
65
  end
@@ -18,21 +18,47 @@ module Kameleoon
18
18
  GEOLOCATION = 'GEOLOCATION'
19
19
  end
20
20
 
21
+ module DataState
22
+ UNSENT = 0
23
+ TRANSMITTING = 1
24
+ SENT = 2
25
+ end
26
+
21
27
  # Represents base class for any Kameleoon data
22
28
  class Data
23
- attr_reader :instance, :sent
29
+ attr_reader :instance
24
30
 
25
31
  def initialize(data_type)
26
32
  @instance = data_type
27
- @sent = false
33
+ @state = DataState::UNSENT
28
34
  end
29
35
 
30
36
  def obtain_full_post_text_line
31
37
  raise KameleoonError.new('ToDo: implement this method.'), 'ToDo: implement this method.'
32
38
  end
33
39
 
40
+ def unsent
41
+ @state == DataState::UNSENT
42
+ end
43
+
44
+ def transmitting
45
+ @state == DataState::TRANSMITTING
46
+ end
47
+
48
+ def sent
49
+ @state == DataState::SENT
50
+ end
51
+
52
+ def mark_as_unsent
53
+ @state = DataState::UNSENT if transmitting
54
+ end
55
+
56
+ def mark_as_transmitting
57
+ @state = DataState::TRANSMITTING if unsent
58
+ end
59
+
34
60
  def mark_as_sent
35
- @sent = true
61
+ @state = DataState::SENT
36
62
  @nonce = nil
37
63
  end
38
64
  end
@@ -52,7 +78,7 @@ module Kameleoon
52
78
  private
53
79
 
54
80
  def nonce
55
- @nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH) if !@sent && @nonce.nil?
81
+ @nonce = Kameleoon::Utils.generate_random_string(NONCE_LENGTH) if !sent && @nonce.nil?
56
82
  @nonce
57
83
  end
58
84
  end
@@ -15,6 +15,10 @@ module Kameleoon
15
15
  class Device < DuplicationUnsafeData
16
16
  attr_reader :device_type
17
17
 
18
+ def to_s
19
+ "Device{device_type:#{@device_type}}"
20
+ end
21
+
18
22
  def initialize(device_type)
19
23
  super(DataType::DEVICE)
20
24
  @device_type = device_type
@@ -5,6 +5,11 @@ module Kameleoon
5
5
  class Geolocation < DuplicationUnsafeData
6
6
  attr_reader :country, :region, :city, :postal_code, :latitude, :longitude
7
7
 
8
+ def to_s
9
+ "Geolocation{country:'#{@country}',region:'#{@region}',city:'#{@city}',postal_code:'#{@postal_code}'," \
10
+ "latitude:#{@latitude},longitude:#{@longitude}}"
11
+ end
12
+
8
13
  # @param [String] country Country of visitor's geolocation. Required
9
14
  # @param [String] region Region of visitor's geolocation. Optional
10
15
  # @param [String] city City of visitor's geolocation. Optional
@@ -9,4 +9,8 @@ module Kameleoon
9
9
  @values.freeze
10
10
  end
11
11
  end
12
+
13
+ def to_s
14
+ "KcsHeat{values:#{@values}}"
15
+ end
12
16
  end
@@ -13,7 +13,14 @@ module Kameleoon
13
13
 
14
14
  attr_reader :experiment_id, :variation_id, :rule_type, :assignment_time
15
15
 
16
- def initialize(experiment_id, variation_id, rule_type = Kameleoon::Configuration::RuleType::UNKNOWN, assignment_time: nil)
16
+ def to_s
17
+ "AssignedVariation{experiment_id:#{@experiment_id},variation_id:#{@variation_id}," \
18
+ "assignment_time:#{@assignment_time},rule_type:#{@rule_type}}"
19
+ end
20
+
21
+ def initialize(
22
+ experiment_id, variation_id, rule_type = Kameleoon::Configuration::RuleType::UNKNOWN, assignment_time: nil
23
+ )
17
24
  super(DataType::ASSIGNED_VARIATION)
18
25
  @experiment_id = experiment_id
19
26
  @variation_id = variation_id
@@ -6,6 +6,13 @@ module Kameleoon
6
6
  # DataArrayStorage is a readonly accessor to a sequntial storage of specific visitor data.
7
7
  # It is thread-safe
8
8
  class DataArrayStorage
9
+
10
+ def to_s
11
+ values = []
12
+ enumerate { |v| values << v }
13
+ "DataArrayStorage{values:#{values.join(',')}}"
14
+ end
15
+
9
16
  def initialize(mutex, array)
10
17
  @mutex = mutex
11
18
  @array = array
@@ -6,6 +6,13 @@ module Kameleoon
6
6
  # DataMapStorage is a readonly accessor to a key-value based storage of specific visitor data.
7
7
  # It is thread-safe
8
8
  class DataMapStorage
9
+
10
+ def to_s
11
+ values = []
12
+ enumerate { |v| values << v }
13
+ "DataMapStorage{values:#{values.join(',')}}"
14
+ end
15
+
9
16
  def initialize(mutex, map)
10
17
  @mutex = mutex
11
18
  @map = map
@@ -5,6 +5,10 @@ module Kameleoon
5
5
  class PageViewVisit
6
6
  attr_reader :page_view, :count, :last_timestamp
7
7
 
8
+ def to_s
9
+ "PageViewVisit{last_timestamp:#{@last_timestamp},count:#{@count},page_view:#{@page_view}}"
10
+ end
11
+
8
12
  def initialize(page_view, count = 1, timestamp = nil)
9
13
  @page_view = page_view
10
14
  @count = count