kameleoon-client-ruby 3.1.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kameleoon/configuration/custom_data_info.rb +43 -0
  3. data/lib/kameleoon/configuration/data_file.rb +31 -2
  4. data/lib/kameleoon/configuration/rule.rb +4 -1
  5. data/lib/kameleoon/configuration/variation_exposition.rb +1 -1
  6. data/lib/kameleoon/data/browser.rb +19 -0
  7. data/lib/kameleoon/data/cookie.rb +14 -0
  8. data/lib/kameleoon/data/custom_data.rb +2 -0
  9. data/lib/kameleoon/data/data.rb +2 -0
  10. data/lib/kameleoon/data/geolocation.rb +45 -0
  11. data/lib/kameleoon/data/kcs_heat.rb +12 -0
  12. data/lib/kameleoon/data/manager/assigned_variation.rb +2 -1
  13. data/lib/kameleoon/data/manager/page_view_visit.rb +16 -2
  14. data/lib/kameleoon/data/manager/visitor.rb +71 -14
  15. data/lib/kameleoon/data/manager/visitor_manager.rb +23 -1
  16. data/lib/kameleoon/data/operating_system.rb +72 -0
  17. data/lib/kameleoon/data/page_view.rb +2 -2
  18. data/lib/kameleoon/data/visitor_visits.rb +20 -0
  19. data/lib/kameleoon/kameleoon_client.rb +122 -94
  20. data/lib/kameleoon/managers/remote_data/remote_data_manager.rb +55 -0
  21. data/lib/kameleoon/managers/remote_data/remote_visitor_data.rb +188 -0
  22. data/lib/kameleoon/managers/warehouse/warehouse_manager.rb +3 -1
  23. data/lib/kameleoon/network/access_token_source.rb +22 -5
  24. data/lib/kameleoon/network/network_manager.rb +10 -10
  25. data/lib/kameleoon/network/response.rb +1 -1
  26. data/lib/kameleoon/network/url_provider.rb +16 -12
  27. data/lib/kameleoon/targeting/condition.rb +24 -2
  28. data/lib/kameleoon/targeting/condition_factory.rb +39 -6
  29. data/lib/kameleoon/targeting/conditions/cookie_condition.rb +55 -0
  30. data/lib/kameleoon/targeting/conditions/exclusive_feature_flag_condition.rb +27 -0
  31. data/lib/kameleoon/targeting/conditions/geolocation_condition.rb +33 -0
  32. data/lib/kameleoon/targeting/conditions/kcs_heat_range_condition.rb +37 -0
  33. data/lib/kameleoon/targeting/conditions/number_condition.rb +38 -0
  34. data/lib/kameleoon/targeting/conditions/operating_system_condition.rb +27 -0
  35. data/lib/kameleoon/targeting/conditions/page_view_number_condition.rb +28 -0
  36. data/lib/kameleoon/targeting/conditions/previous_page_condition.rb +35 -0
  37. data/lib/kameleoon/targeting/conditions/segment_condition.rb +42 -0
  38. data/lib/kameleoon/targeting/conditions/target_feature_flag_condition.rb +59 -0
  39. data/lib/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.rb +29 -0
  40. data/lib/kameleoon/targeting/conditions/visit_number_today_condition.rb +28 -0
  41. data/lib/kameleoon/targeting/conditions/visit_number_total_condition.rb +23 -0
  42. data/lib/kameleoon/targeting/conditions/visitor_new_return_condition.rb +34 -0
  43. data/lib/kameleoon/targeting/targeting_manager.rb +68 -0
  44. data/lib/kameleoon/types/remote_visitor_data_filter.rb +29 -0
  45. data/lib/kameleoon/types/variable.rb +17 -0
  46. data/lib/kameleoon/types/variation.rb +18 -0
  47. data/lib/kameleoon/utils.rb +1 -0
  48. data/lib/kameleoon/version.rb +1 -1
  49. metadata +28 -4
  50. data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +0 -18
  51. data/lib/kameleoon/targeting/conditions/target_experiment.rb +0 -45
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/targeting/conditions/number_condition'
4
+ require 'kameleoon/data/visitor_visits'
5
+
6
+ module Kameleoon
7
+ # @api private
8
+ module Targeting
9
+ class TimeElapsedSinceVisitCondition < NumberCondition
10
+ def initialize(json_condition)
11
+ count_in_millis = json_condition['countInMillis']
12
+ super(json_condition, count_in_millis)
13
+ @is_first_visit = @type == Kameleoon::Targeting::ConditionType::FIRST_VISIT
14
+ end
15
+
16
+ def check(data)
17
+ return false unless data.is_a?(Kameleoon::VisitorVisits) && !@condition_value.nil?
18
+
19
+ previous_visits_count = data.previous_visit_timestamps.count
20
+ if previous_visits_count >= 1
21
+ now = (Time.now.to_f * 1000).to_i # ... * 1000 for convert seconds to milliseconds
22
+ visit_time = data.previous_visit_timestamps[@is_first_visit ? previous_visits_count - 1 : 0]
23
+ return check_targeting(now - visit_time)
24
+ end
25
+ false
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/data/visitor_visits'
4
+ require 'time'
5
+
6
+ module Kameleoon
7
+ # @api private
8
+ module Targeting
9
+ class VisitNumberTodayCondition < NumberCondition
10
+ def initialize(json_condition)
11
+ visit_count = json_condition['visitCount']
12
+ super(json_condition, visit_count)
13
+ end
14
+
15
+ def check(data)
16
+ return false unless VisitorVisits.visitor_visits?(data) && !@condition_value.nil?
17
+
18
+ number_of_visits_today = 0
19
+ start_of_day = (Time.new.to_date.to_time.to_f * 1000).to_i # ... * 1000 to convert seconds to milliseconds
20
+ for timestamp in VisitorVisits.get_previous_visit_timestamps(data)
21
+ break if timestamp < start_of_day
22
+ number_of_visits_today += 1
23
+ end
24
+ check_targeting(number_of_visits_today + 1) # +1 for current visit
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/data/visitor_visits'
4
+ require 'kameleoon/targeting/conditions/number_condition'
5
+
6
+ module Kameleoon
7
+ # @api private
8
+ module Targeting
9
+ class VisitNumberTotalCondition < NumberCondition
10
+ def initialize(json_condition)
11
+ visit_count = json_condition['visitCount']
12
+ super(json_condition, visit_count)
13
+ end
14
+
15
+ def check(data)
16
+ return false unless VisitorVisits.visitor_visits?(data) && !@condition_value.nil?
17
+
18
+ previous_visit_timestamps = VisitorVisits.get_previous_visit_timestamps(data)
19
+ check_targeting(previous_visit_timestamps.size + 1) # +1 for current visit
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/data/visitor_visits'
4
+
5
+ module Kameleoon
6
+ # @api private
7
+ module Targeting
8
+ module VisitorType
9
+ NEW = 'NEW'
10
+ RETURNING = 'RETURNING'
11
+ end
12
+
13
+ class VisitorNewReturnCondition < Condition
14
+ def initialize(json_condition)
15
+ super(json_condition)
16
+ @visitor_type = json_condition['visitorType']
17
+ end
18
+
19
+ def check(data)
20
+ return false unless VisitorVisits.visitor_visits?(data)
21
+
22
+ previous_visit_timestamps = VisitorVisits.get_previous_visit_timestamps(data)
23
+ case @visitor_type
24
+ when VisitorType::NEW
25
+ previous_visit_timestamps.empty?
26
+ when VisitorType::RETURNING
27
+ !previous_visit_timestamps.empty?
28
+ else
29
+ false
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/targeting/conditions/segment_condition'
4
+
5
+ module Kameleoon
6
+ # @api private
7
+ module Targeting
8
+ class TargetingManager
9
+ def initialize(visitor_manager, data_file)
10
+ @visitor_manager = visitor_manager
11
+ @data_file = data_file
12
+ end
13
+
14
+ def check_targeting(visitor_code, campaign_id, exp_ff_rule)
15
+ segment = exp_ff_rule.targeting_segment
16
+ return true if segment.nil?
17
+
18
+ visitor = @visitor_manager.get_visitor(visitor_code)
19
+ segment.check_tree(->(type) { get_condition_data(type, visitor, visitor_code, campaign_id) })
20
+ end
21
+
22
+ def get_condition_data(type, visitor, visitor_code, campaign_id)
23
+ condition_data = nil
24
+ case type
25
+ when Kameleoon::Targeting::ConditionType::CUSTOM_DATUM
26
+ condition_data = visitor.custom_data unless visitor.nil?
27
+ when Kameleoon::Targeting::ConditionType::PAGE_VIEWS,
28
+ Kameleoon::Targeting::ConditionType::PREVIOUS_PAGE,
29
+ Kameleoon::Targeting::ConditionType::PAGE_TITLE,
30
+ Kameleoon::Targeting::ConditionType::PAGE_URL
31
+ condition_data = visitor.page_view_visits unless visitor.nil?
32
+ when Kameleoon::Targeting::ConditionType::DEVICE_TYPE
33
+ condition_data = visitor.device unless visitor.nil?
34
+ when Kameleoon::Targeting::ConditionType::BROWSER
35
+ condition_data = visitor.browser unless visitor.nil?
36
+ when Kameleoon::Targeting::ConditionType::COOKIE
37
+ condition_data = visitor.cookie unless visitor.nil?
38
+ when Kameleoon::Targeting::ConditionType::GEOLOCATION
39
+ condition_data = visitor.geolocation unless visitor.nil?
40
+ when Kameleoon::Targeting::ConditionType::OPERATING_SYSTEM
41
+ condition_data = visitor.operating_system unless visitor.nil?
42
+ when Kameleoon::Targeting::ConditionType::SEGMENT
43
+ condition_data = SegmentInfo.new(
44
+ @data_file,
45
+ lambda { |type|
46
+ get_condition_data(type, visitor, visitor_code, campaign_id)
47
+ }
48
+ )
49
+ when Kameleoon::Targeting::ConditionType::CONVERSIONS
50
+ condition_data = visitor.conversions unless visitor.nil?
51
+ when Kameleoon::Targeting::ConditionType::SDK_LANGUAGE
52
+ condition_data = Kameleoon::Targeting::SdkInfo.new(Kameleoon::SDK_NAME, Kameleoon::SDK_VERSION)
53
+ when Kameleoon::Targeting::ConditionType::VISITOR_CODE
54
+ condition_data = visitor_code
55
+ when Kameleoon::Targeting::ConditionType::TARGET_FEATURE_FLAG
56
+ condition_data = TargetFeatureFlagInfo.new(@data_file, visitor.variations) unless visitor.nil?
57
+ when Kameleoon::Targeting::ConditionType::EXCLUSIVE_FEATURE_FLAG
58
+ condition_data = ExclusiveFeatureFlagInfo.new(campaign_id, visitor&.variations)
59
+ when ConditionType::FIRST_VISIT, ConditionType::LAST_VISIT, ConditionType::VISITS, ConditionType::SAME_DAY_VISITS, ConditionType::NEW_VISITORS
60
+ condition_data = visitor.visitor_visits unless visitor.nil?
61
+ when Kameleoon::Targeting::ConditionType::HEAT_SLICE
62
+ condition_data = visitor&.kcs_heat
63
+ end
64
+ condition_data
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ # Module which contains all internal data of SDK
5
+ module Types
6
+ class RemoteVisitorDataFilter
7
+ attr_reader :previous_visit_amount, :current_visit, :custom_data, :page_views, :geolocation, :device, :browser,
8
+ :operating_system, :conversions, :experiments, :kcs
9
+
10
+ def initialize(
11
+ previous_visit_amount: 1, current_visit: true, custom_data: true, page_views: false,
12
+ geolocation: false, device: false, browser: false, operating_system: false, conversions: false,
13
+ experiments: false, kcs: false
14
+ )
15
+ @previous_visit_amount = previous_visit_amount
16
+ @current_visit = current_visit
17
+ @custom_data = custom_data
18
+ @page_views = page_views
19
+ @geolocation = geolocation
20
+ @device = device
21
+ @browser = browser
22
+ @operating_system = operating_system
23
+ @conversions = conversions
24
+ @experiments = experiments
25
+ @kcs = kcs
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ # Module which contains all internal data of SDK
5
+ module Types
6
+ # Variable
7
+ class Variable
8
+ attr_reader :key, :type, :value
9
+
10
+ def initialize(key, type, value)
11
+ @key = key
12
+ @type = type
13
+ @value = value
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ # Module which contains all internal data of SDK
5
+ module Types
6
+ # Variation
7
+ class Variation
8
+ attr_reader :key, :id, :experiment_id, :variables
9
+
10
+ def initialize(key, id, experiment_id, variables)
11
+ @key = key
12
+ @id = id
13
+ @experiment_id = experiment_id
14
+ @variables = variables
15
+ end
16
+ end
17
+ end
18
+ end
@@ -19,6 +19,7 @@ module Kameleoon
19
19
  VISITOR_CODE_LENGTH = 16
20
20
 
21
21
  def self.validate(visitor_code)
22
+ raise Kameleoon::Exception::VisitorCodeInvalid, 'Visitor Code is nil or invalidate type' unless visitor_code.is_a?(String)
22
23
  raise Kameleoon::Exception::VisitorCodeInvalid, 'Empty visitor Code' if visitor_code&.empty?
23
24
  if visitor_code.size > VISITOR_CODE_MAX_LENGTH
24
25
  raise Kameleoon::Exception::VisitorCodeInvalid, "Visitor Code is longer than #{VISITOR_CODE_MAX_LENGTH} chars"
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Kameleoon
4
4
  SDK_NAME = 'RUBY'
5
- SDK_VERSION = '3.1.1'
5
+ SDK_VERSION = '3.3.0'
6
6
 
7
7
  # SdkManager is a helper method for fetching / obtaining version of SDK from string
8
8
  class SdkVersion
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kameleoon-client-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.1
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kameleoon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-27 00:00:00.000000000 Z
11
+ date: 2024-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-http-request
@@ -76,6 +76,7 @@ files:
76
76
  - README.md
77
77
  - lib/kameleoon.rb
78
78
  - lib/kameleoon/client_readiness.rb
79
+ - lib/kameleoon/configuration/custom_data_info.rb
79
80
  - lib/kameleoon/configuration/data_file.rb
80
81
  - lib/kameleoon/configuration/feature_flag.rb
81
82
  - lib/kameleoon/configuration/rule.rb
@@ -85,22 +86,29 @@ files:
85
86
  - lib/kameleoon/configuration/variation_exposition.rb
86
87
  - lib/kameleoon/data/browser.rb
87
88
  - lib/kameleoon/data/conversion.rb
89
+ - lib/kameleoon/data/cookie.rb
88
90
  - lib/kameleoon/data/custom_data.rb
89
91
  - lib/kameleoon/data/data.rb
90
92
  - lib/kameleoon/data/device.rb
93
+ - lib/kameleoon/data/geolocation.rb
94
+ - lib/kameleoon/data/kcs_heat.rb
91
95
  - lib/kameleoon/data/manager/assigned_variation.rb
92
96
  - lib/kameleoon/data/manager/data_array_storage.rb
93
97
  - lib/kameleoon/data/manager/data_map_storage.rb
94
98
  - lib/kameleoon/data/manager/page_view_visit.rb
95
99
  - lib/kameleoon/data/manager/visitor.rb
96
100
  - lib/kameleoon/data/manager/visitor_manager.rb
101
+ - lib/kameleoon/data/operating_system.rb
97
102
  - lib/kameleoon/data/page_view.rb
98
103
  - lib/kameleoon/data/user_agent.rb
104
+ - lib/kameleoon/data/visitor_visits.rb
99
105
  - lib/kameleoon/exceptions.rb
100
106
  - lib/kameleoon/hybrid/manager.rb
101
107
  - lib/kameleoon/kameleoon_client.rb
102
108
  - lib/kameleoon/kameleoon_client_config.rb
103
109
  - lib/kameleoon/kameleoon_client_factory.rb
110
+ - lib/kameleoon/managers/remote_data/remote_data_manager.rb
111
+ - lib/kameleoon/managers/remote_data/remote_visitor_data.rb
104
112
  - lib/kameleoon/managers/warehouse/warehouse_manager.rb
105
113
  - lib/kameleoon/network/access_token_source.rb
106
114
  - lib/kameleoon/network/activity_event.rb
@@ -124,18 +132,34 @@ files:
124
132
  - lib/kameleoon/targeting/condition_factory.rb
125
133
  - lib/kameleoon/targeting/conditions/browser_condition.rb
126
134
  - lib/kameleoon/targeting/conditions/conversion_condition.rb
135
+ - lib/kameleoon/targeting/conditions/cookie_condition.rb
127
136
  - lib/kameleoon/targeting/conditions/custom_datum.rb
128
137
  - lib/kameleoon/targeting/conditions/device_condition.rb
129
- - lib/kameleoon/targeting/conditions/exclusive_experiment.rb
138
+ - lib/kameleoon/targeting/conditions/exclusive_feature_flag_condition.rb
139
+ - lib/kameleoon/targeting/conditions/geolocation_condition.rb
140
+ - lib/kameleoon/targeting/conditions/kcs_heat_range_condition.rb
141
+ - lib/kameleoon/targeting/conditions/number_condition.rb
142
+ - lib/kameleoon/targeting/conditions/operating_system_condition.rb
130
143
  - lib/kameleoon/targeting/conditions/page_title_condition.rb
131
144
  - lib/kameleoon/targeting/conditions/page_url_condition.rb
145
+ - lib/kameleoon/targeting/conditions/page_view_number_condition.rb
146
+ - lib/kameleoon/targeting/conditions/previous_page_condition.rb
132
147
  - lib/kameleoon/targeting/conditions/sdk_language_condition.rb
148
+ - lib/kameleoon/targeting/conditions/segment_condition.rb
133
149
  - lib/kameleoon/targeting/conditions/string_value_condition.rb
134
- - lib/kameleoon/targeting/conditions/target_experiment.rb
150
+ - lib/kameleoon/targeting/conditions/target_feature_flag_condition.rb
151
+ - lib/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.rb
135
152
  - lib/kameleoon/targeting/conditions/unknown_condition.rb
153
+ - lib/kameleoon/targeting/conditions/visit_number_today_condition.rb
154
+ - lib/kameleoon/targeting/conditions/visit_number_total_condition.rb
136
155
  - lib/kameleoon/targeting/conditions/visitor_code_condition.rb
156
+ - lib/kameleoon/targeting/conditions/visitor_new_return_condition.rb
137
157
  - lib/kameleoon/targeting/models.rb
158
+ - lib/kameleoon/targeting/targeting_manager.rb
138
159
  - lib/kameleoon/targeting/tree_builder.rb
160
+ - lib/kameleoon/types/remote_visitor_data_filter.rb
161
+ - lib/kameleoon/types/variable.rb
162
+ - lib/kameleoon/types/variation.rb
139
163
  - lib/kameleoon/utils.rb
140
164
  - lib/kameleoon/version.rb
141
165
  homepage: https://developers.kameleoon.com/ruby-sdk.html
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'kameleoon/targeting/condition'
4
-
5
- module Kameleoon
6
- # @api private
7
- module Targeting
8
- # ExclusiveExperiment represents an instance of Exclusive Experiment condition in user account
9
- class ExclusiveExperiment < Condition
10
- def check(data)
11
- experiment_id = data.experiment_id
12
- storage = data.storage
13
- storage.is_a?(Kameleoon::DataManager::DataMapStorage) &&
14
- (storage.size.zero? || ((storage.size == 1) && !storage.get(experiment_id).nil?))
15
- end
16
- end
17
- end
18
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'kameleoon/targeting/condition'
4
- require 'kameleoon/exceptions'
5
-
6
- module Kameleoon
7
- # @api private
8
- module Targeting
9
- # TargetExperiment represents an instance of Experiment condition in user account
10
- class TargetExperiment < Condition
11
- include Kameleoon::Exception
12
-
13
- def initialize(json_condition)
14
- super(json_condition)
15
-
16
- raise Exception::NotFound.new('experiment'), 'experiment missed' if json_condition['experiment'].nil?
17
- if json_condition['variationMatchType'].nil?
18
- raise Exception::NotFound.new('variationMatchType'), 'variationMatchType missed'
19
- end
20
-
21
- @experiment = json_condition['experiment']
22
- @operator = json_condition['variationMatchType']
23
- @variation = json_condition['variation']
24
- end
25
-
26
- def check(variation_storage)
27
- return false unless variation_storage.is_a?(Kameleoon::DataManager::DataMapStorage) &&
28
- variation_storage.size.positive?
29
-
30
- variation = variation_storage.get(@experiment)
31
- return false unless variation.is_a?(Kameleoon::DataManager::AssignedVariation)
32
-
33
- case @operator
34
- when Operator::EXACT
35
- variation = variation_storage.get(@experiment)
36
- variation.variation_id == @variation
37
- when Operator::ANY
38
- true
39
- else
40
- false
41
- end
42
- end
43
- end
44
- end
45
- end