kameleoon-client-ruby 3.2.0 → 3.4.0

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.
Files changed (75) 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 +40 -17
  4. data/lib/kameleoon/configuration/feature_flag.rb +10 -0
  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 +16 -0
  16. data/lib/kameleoon/data/manager/assigned_variation.rb +5 -0
  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 +198 -67
  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 +12 -1
  28. data/lib/kameleoon/hybrid/manager.rb +13 -4
  29. data/lib/kameleoon/kameleoon_client.rb +348 -146
  30. data/lib/kameleoon/kameleoon_client_config.rb +64 -17
  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 +33 -18
  37. data/lib/kameleoon/managers/remote_data/remote_visitor_data.rb +42 -16
  38. data/lib/kameleoon/managers/tracking/tracking_builder.rb +149 -0
  39. data/lib/kameleoon/managers/tracking/tracking_manager.rb +97 -0
  40. data/lib/kameleoon/managers/tracking/visitor_tracking_registry.rb +94 -0
  41. data/lib/kameleoon/managers/warehouse/warehouse_manager.rb +22 -5
  42. data/lib/kameleoon/network/access_token_source.rb +46 -14
  43. data/lib/kameleoon/network/cookie/cookie_manager.rb +45 -7
  44. data/lib/kameleoon/network/net_provider.rb +2 -3
  45. data/lib/kameleoon/network/network_manager.rb +16 -21
  46. data/lib/kameleoon/network/request.rb +14 -3
  47. data/lib/kameleoon/network/response.rb +4 -0
  48. data/lib/kameleoon/network/url_provider.rb +11 -10
  49. data/lib/kameleoon/real_time/real_time_configuration_service.rb +10 -11
  50. data/lib/kameleoon/sdk_version.rb +31 -0
  51. data/lib/kameleoon/targeting/condition.rb +6 -2
  52. data/lib/kameleoon/targeting/condition_factory.rb +3 -0
  53. data/lib/kameleoon/targeting/conditions/browser_condition.rb +3 -3
  54. data/lib/kameleoon/targeting/conditions/cookie_condition.rb +10 -10
  55. data/lib/kameleoon/targeting/conditions/geolocation_condition.rb +0 -1
  56. data/lib/kameleoon/targeting/conditions/kcs_heat_range_condition.rb +37 -0
  57. data/lib/kameleoon/targeting/conditions/number_condition.rb +4 -4
  58. data/lib/kameleoon/targeting/conditions/operating_system_condition.rb +1 -2
  59. data/lib/kameleoon/targeting/conditions/sdk_language_condition.rb +2 -1
  60. data/lib/kameleoon/targeting/conditions/segment_condition.rb +3 -3
  61. data/lib/kameleoon/targeting/conditions/string_value_condition.rb +2 -1
  62. data/lib/kameleoon/targeting/conditions/target_feature_flag_condition.rb +7 -11
  63. data/lib/kameleoon/targeting/conditions/time_elapsed_since_visit_condition.rb +1 -2
  64. data/lib/kameleoon/targeting/conditions/visit_number_today_condition.rb +4 -4
  65. data/lib/kameleoon/targeting/conditions/visit_number_total_condition.rb +5 -3
  66. data/lib/kameleoon/targeting/conditions/visitor_new_return_condition.rb +7 -6
  67. data/lib/kameleoon/targeting/models.rb +0 -14
  68. data/lib/kameleoon/targeting/targeting_manager.rb +37 -7
  69. data/lib/kameleoon/targeting/tree_builder.rb +10 -5
  70. data/lib/kameleoon/types/remote_visitor_data_filter.rb +21 -3
  71. data/lib/kameleoon/types/variable.rb +21 -0
  72. data/lib/kameleoon/types/variation.rb +22 -0
  73. data/lib/kameleoon/utils.rb +18 -0
  74. data/lib/kameleoon/version.rb +1 -27
  75. metadata +16 -2
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kameleoon/logging/kameleoon_logger'
3
4
  require 'kameleoon/network/content_type'
4
5
  require 'kameleoon/network/method'
5
6
  require 'kameleoon/network/request'
@@ -21,13 +22,12 @@ module Kameleoon
21
22
 
22
23
  attr_reader :environment, :default_timeout, :access_token_source, :url_provider
23
24
 
24
- def initialize(environment, default_timeout, access_token_source_factory, url_provider, log_func = nil)
25
+ def initialize(environment, default_timeout, access_token_source_factory, url_provider)
25
26
  @environment = environment
26
27
  @default_timeout = default_timeout
27
28
  @access_token_source = access_token_source_factory.create(self)
28
29
  @url_provider = url_provider
29
30
  @sync_net_provider = SyncNetProvider.new
30
- @log_func = log_func
31
31
  end
32
32
 
33
33
  def fetch_configuration(timestamp = nil, timeout = nil)
@@ -52,17 +52,13 @@ module Kameleoon
52
52
  make_call(request, true)
53
53
  end
54
54
 
55
- def send_tracking_data(visitor_code, lines, user_agent, is_unique_identifier, timeout = nil)
55
+ def send_tracking_data(lines, timeout = nil)
56
56
  return if lines.nil? || lines.empty?
57
57
 
58
- url = @url_provider.make_tracking_url(visitor_code, is_unique_identifier)
58
+ url = @url_provider.make_tracking_url
59
59
  timeout = ensure_timeout(timeout)
60
- data = (lines.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8')
61
- request = Request.new(Method::POST, url, ContentType::TEXT, timeout, user_agent: user_agent, data: data)
62
- Thread.new do
63
- result = make_call(request, true, TRACKING_CALL_ATTEMPT_NUMBER - 1, TRACKING_CALL_RETRY_DELAY)
64
- lines.each(&:mark_as_sent) if result != false
65
- end
60
+ request = Request.new(Method::POST, url, ContentType::TEXT, timeout, data: lines)
61
+ make_call(request, true, TRACKING_CALL_ATTEMPT_NUMBER - 1, TRACKING_CALL_RETRY_DELAY)
66
62
  end
67
63
 
68
64
  def fetch_access_jwtoken(client_id, client_secret, timeout = nil)
@@ -81,6 +77,8 @@ module Kameleoon
81
77
  private
82
78
 
83
79
  def make_call(request, try_access_token_auth, retry_limit = 0, retry_delay = 0)
80
+ Logging::KameleoonLogger.debug('Running request %s with access token %s, retry limit %s, retry delay %s ms',
81
+ request, try_access_token_auth, retry_limit, retry_delay)
84
82
  attempt = 0
85
83
  success = false
86
84
  while !success && (attempt <= retry_limit)
@@ -90,33 +88,30 @@ module Kameleoon
90
88
  if response.success?
91
89
  success = true
92
90
  elsif !response.error.nil?
93
- log_failure(request, "Error occurred during request: #{response.error}")
91
+ Logging::KameleoonLogger.warning("%s call '%s' failed: Error occurred during request: %s",
92
+ request.method, request.url, response.error)
94
93
  else
95
- log_failure(request, "Received unexpected status code '#{response.code}'")
94
+ Logging::KameleoonLogger.warning("%s call '%s' failed: Received unexpected status code '%s'",
95
+ request.method, request.url, response.code)
96
96
  if response.code == 401 && request.access_token
97
- @log_func&.call("Unexpected rejection of access token '#{request.access_token}'")
97
+ Logging::KameleoonLogger.warning("Unexpected rejection of access token '#{request.access_token}'")
98
98
  @access_token_source.discard_token(request.access_token)
99
99
  if attempt == retry_limit
100
100
  try_access_token_auth = false
101
101
  retry_delay = 0
102
102
  request.authorize(nil)
103
103
  attempt -= 1
104
+ Logging::KameleoonLogger.error("Wrong Kameleoon API access token slows down the SDK's requests")
104
105
  end
105
106
  end
106
107
  end
107
108
  attempt += 1
108
109
  end
110
+ Logging::KameleoonLogger.debug('Fetched response %s for request %s', response, request)
111
+ Logging::KameleoonLogger.error("Failed %s request '%s'", request.method, request.url) unless success
109
112
  success ? response.body : false
110
113
  end
111
114
 
112
- def log_failure(request, message)
113
- return if @log_func.nil?
114
-
115
- premsg = "#{request.method} call '#{request.url}' "
116
- premsg += request.data.nil? ? 'failed' : "(data '#{request.data}') failed"
117
- @log_func.call("#{premsg}: #{message}")
118
- end
119
-
120
115
  def delay(period)
121
116
  sleep(period)
122
117
  end
@@ -5,14 +5,25 @@ module Kameleoon
5
5
  ##
6
6
  # Request represents HTTP request.
7
7
  class Request
8
- attr_reader :method, :url, :content_type, :timeout, :user_agent, :extra_headers, :data, :access_token
8
+ attr_reader :method, :url, :content_type, :timeout, :extra_headers, :data, :access_token
9
9
 
10
- def initialize(method, url, content_type, timeout, user_agent: nil, extra_headers: nil, data: nil)
10
+ def to_s
11
+ body = 'null'
12
+ unless @data.nil?
13
+ if @data.is_a?(String)
14
+ body = @data.start_with?('grant_type=client_credentials') ? '****' : @data
15
+ else
16
+ body = @data
17
+ end
18
+ end
19
+ "HttpRequest{Method:'#{@method}',Url:'#{@url}',Headers:#{@extra_headers},Body:'#{body}'}"
20
+ end
21
+
22
+ def initialize(method, url, content_type, timeout, extra_headers: nil, data: nil)
11
23
  @method = method
12
24
  @url = url
13
25
  @content_type = content_type
14
26
  @timeout = timeout
15
- @user_agent = user_agent
16
27
  @extra_headers = extra_headers
17
28
  @data = !data.nil? && data.is_a?(String) ? data.encode('UTF-8') : data
18
29
  end
@@ -7,6 +7,10 @@ module Kameleoon
7
7
  class Response
8
8
  attr_reader :error, :code, :body, :request
9
9
 
10
+ def to_s
11
+ "HttpResponse{Code:'#{@code}',Reason:'#{@error}',Body:#{@body}}"
12
+ end
13
+
10
14
  def initialize(error, code, body, request)
11
15
  @error = error
12
16
  @code = code
@@ -19,7 +19,7 @@ module Kameleoon
19
19
  DEFAULT_DATA_API_DOMAIN = 'data.kameleoon.io'
20
20
  TEST_DATA_API_DOMAIN = 'data.kameleoon.net'
21
21
  DEFAULT_AUTOMATION_API_DOMAIN = 'api.kameleoon.com'
22
- TEST_AUTOMATION_API_DOMAIN = 'api.kameleoon.net'
22
+ TEST_AUTOMATION_API_DOMAIN = 'api.master.preview.kameleoon.net'
23
23
 
24
24
  attr_reader :site_code, :data_api_domain, :automation_api_domain
25
25
 
@@ -37,13 +37,13 @@ module Kameleoon
37
37
  @data_api_domain = domain if domain.is_a?(String)
38
38
  end
39
39
 
40
- def make_tracking_url(visitor_code, is_unique_identifier = false)
40
+ def make_tracking_url
41
41
  params = {
42
42
  sdkName: SDK_NAME,
43
43
  sdkVersion: SDK_VERSION,
44
- siteCode: @site_code
44
+ siteCode: @site_code,
45
+ bodyUa: true
45
46
  }
46
- params[is_unique_identifier ? :mappingValue : :visitorCode] = visitor_code
47
47
  "https://#{@data_api_domain}#{TRACKING_PATH}?#{UriHelper.encode_query(params)}"
48
48
  end
49
49
 
@@ -52,12 +52,13 @@ module Kameleoon
52
52
  params[is_unique_identifier ? :mappingValue : :visitorCode] = visitor_code
53
53
  params[:maxNumberPreviousVisits] = filter.previous_visit_amount
54
54
  params[:version] = 0
55
- params[:currentVisit] = filter.current_visit if filter.current_visit
56
- params[:customData] = filter.custom_data if filter.custom_data
57
- params[:conversion] = filter.conversions if filter.conversions
58
- params[:geolocation] = filter.geolocation if filter.geolocation
59
- params[:experiment] = filter.experiments if filter.experiments
60
- params[:page] = filter.page_views if filter.page_views
55
+ params[:kcs] = true if filter.kcs
56
+ params[:currentVisit] = true if filter.current_visit
57
+ params[:customData] = true if filter.custom_data
58
+ params[:conversion] = true if filter.conversions
59
+ params[:geolocation] = true if filter.geolocation
60
+ params[:experiment] = true if filter.experiments
61
+ params[:page] = true if filter.page_views
61
62
  params[:staticData] = true if filter.device || filter.browser || filter.operating_system
62
63
  "https://#{@data_api_domain}#{VISITOR_DATA_PATH}?#{UriHelper.encode_query(params)}"
63
64
  end
@@ -3,6 +3,7 @@
3
3
  # Kameleoon Real Time Configuration Service
4
4
 
5
5
  require 'json'
6
+ require 'kameleoon/logging/kameleoon_logger'
6
7
  require 'kameleoon/real_time/real_time_event'
7
8
  require 'kameleoon/real_time/sse_request'
8
9
  require 'kameleoon/real_time/sse_client'
@@ -21,8 +22,7 @@ module Kameleoon
21
22
  # @param url [String]
22
23
  # @param update_handler [Callable[Kameleoon::RealTime::RealTimeEvent] | NilClass] Handler which
23
24
  # is synchronously called for gotten RealTimeEvent objects.
24
- # @param log_func [Callable[String] | NilClass] Callable object which synchronously called to log.
25
- def initialize(url, update_handler, log_func, sse_request_source = nil)
25
+ def initialize(url, update_handler, sse_request_source = nil)
26
26
  @url = url
27
27
  @update_handler = update_handler
28
28
  @need_close = false
@@ -31,7 +31,6 @@ module Kameleoon
31
31
  'Cache-Control': 'no-cache',
32
32
  'Connection': 'Keep-Alive'
33
33
  }
34
- @log_func = log_func
35
34
  @sse_request_source = sse_request_source
36
35
  @sse_thread = nil
37
36
  @sse_client = nil
@@ -43,13 +42,13 @@ module Kameleoon
43
42
  def close
44
43
  return if @need_close
45
44
 
46
- @log_func&.call('Real-time configuration service is shutting down')
45
+ Logging::KameleoonLogger.info('Real-time configuration service is shutting down')
47
46
  @need_close = true
48
47
  return if @sse_thread.nil?
49
48
 
50
49
  @sse_thread.kill
51
50
  @sse_thread = nil
52
- @sse_client.call_close_handler
51
+ @sse_client&.call_close_handler
53
52
  end
54
53
 
55
54
  private
@@ -60,7 +59,7 @@ module Kameleoon
60
59
 
61
60
  def init_sse_client
62
61
  message_handler = proc do |message|
63
- @log_func&.call("Got SSE event: #{message.event}")
62
+ Logging::KameleoonLogger.debug("Got SSE event: #{message.event}")
64
63
  if message.event == CONFIGURATION_UPDATE_EVENT
65
64
  event_dict = JSON.parse(message.data)
66
65
  @update_handler&.call(RealTimeEvent.new(event_dict))
@@ -68,14 +67,14 @@ module Kameleoon
68
67
  end
69
68
  sse_request = make_sse_request
70
69
  @sse_client = SseClient.new(sse_request, message_handler)
71
- @log_func&.call('Created SSE client')
70
+ Logging::KameleoonLogger.info('Created SSE client')
72
71
  end
73
72
 
74
73
  def make_sse_request
75
- open_handler = proc { @log_func&.call('SSE connection open') }
76
- close_handler = proc { @log_func&.call('SSE connection closed') }
74
+ open_handler = proc { Logging::KameleoonLogger.info('SSE connection open') }
75
+ close_handler = proc { Logging::KameleoonLogger.info('SSE connection closed') }
77
76
  unexpected_status_code_handler =
78
- proc { |resp| @log_func&.call("Unexpected status code of SSE response: #{resp.code}") }
77
+ proc { |resp| Logging::KameleoonLogger.error("Unexpected status code of SSE response: #{resp.code}") }
79
78
  if @sse_request_source.nil?
80
79
  return SseRequest.new(@url, @headers, open_handler, close_handler, unexpected_status_code_handler)
81
80
  end
@@ -89,7 +88,7 @@ module Kameleoon
89
88
  begin
90
89
  @sse_client.start
91
90
  rescue StandardError => e
92
- @log_func&.call("Error occurred within SSE client: #{e}")
91
+ Logging::KameleoonLogger.error("Error occurred within SSE client: #{e}")
93
92
  end
94
93
  end
95
94
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/logging/kameleoon_logger'
4
+
5
+ module Kameleoon
6
+ # SdkManager is a helper method for fetching / obtaining version of SDK from string
7
+ class SdkVersion
8
+ def self.get_version_components(version_string)
9
+ versions = [0, 0, 0]
10
+
11
+ version_parts = version_string.split('.')
12
+ version_parts.each_with_index do |part, i|
13
+ versions[i] = Integer(part)
14
+ rescue ArgumentError
15
+ Logging::KameleoonLogger.error('Invalid version component, index: %s, value: %s', i, part)
16
+ return nil
17
+ end
18
+ versions
19
+ end
20
+
21
+ def self.get_float_version(version_string)
22
+ version_components = get_version_components(version_string)
23
+
24
+ return Float::NAN if version_components.nil?
25
+
26
+ major = version_components[0]
27
+ minor = version_components[1]
28
+ "#{major}.#{minor}".to_f
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'kameleoon/exceptions'
4
+ require 'kameleoon/logging/kameleoon_logger'
3
5
 
4
6
  module Kameleoon
5
7
  # @api private
@@ -26,6 +28,7 @@ module Kameleoon
26
28
  VISITS = 'VISITS'
27
29
  SAME_DAY_VISITS = 'SAME_DAY_VISITS'
28
30
  NEW_VISITORS = 'NEW_VISITORS'
31
+ HEAT_SLICE = 'HEAT_SLICE'
29
32
  end
30
33
 
31
34
  module Operator
@@ -45,12 +48,13 @@ module Kameleoon
45
48
 
46
49
  # Base class for all targeting conditions
47
50
  class Condition
48
- attr_reader :type, :include
51
+ attr_reader :type, :include, :id
49
52
 
50
53
  def initialize(json_condition)
51
54
  raise Exception::NotFound.new('targetingType'), 'targetingType missed' if json_condition['targetingType'].nil?
52
55
 
53
56
  @type = json_condition['targetingType']
57
+ @id = json_condition['id']
54
58
  @include = json_condition['isInclude'].nil? ? true : json_condition['isInclude']
55
59
  end
56
60
 
@@ -68,7 +72,7 @@ module Kameleoon
68
72
  begin
69
73
  return pattern.match? value
70
74
  rescue StandardError => e
71
- log "Failed to match with regex (targeting): #{e}"
75
+ Logging::KameleoonLogger.error("Failed to match with regex (targeting): #{e}")
72
76
  end
73
77
  false
74
78
  end
@@ -11,6 +11,7 @@ require_relative 'conditions/conversion_condition'
11
11
  require_relative 'conditions/browser_condition'
12
12
  require_relative 'conditions/sdk_language_condition'
13
13
  require_relative 'conditions/geolocation_condition'
14
+ require_relative 'conditions/kcs_heat_range_condition'
14
15
  require_relative 'conditions/operating_system_condition'
15
16
  require_relative 'conditions/cookie_condition'
16
17
  require_relative 'conditions/segment_condition'
@@ -67,6 +68,8 @@ module Kameleoon
67
68
  VisitorNewReturnCondition.new(condition_json)
68
69
  when ConditionType::FIRST_VISIT, ConditionType::LAST_VISIT
69
70
  TimeElapsedSinceVisitCondition.new(condition_json)
71
+ when ConditionType::HEAT_SLICE
72
+ KcsHeatRangeCondition.new(condition_json)
70
73
  else
71
74
  UnknownCondition.new(condition_json)
72
75
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'kameleoon/data/browser'
4
- require 'kameleoon/version'
4
+ require 'kameleoon/logging/kameleoon_logger'
5
+ require 'kameleoon/sdk_version'
5
6
 
6
7
  module Kameleoon
7
8
  # @api private
8
9
  module Targeting
9
-
10
10
  CHROME = 'CHROME'
11
11
  INTERNET_EXPLORER = 'IE'
12
12
  FIREFOX = 'FIREFOX'
@@ -44,7 +44,7 @@ module Kameleoon
44
44
  when Operator::LOWER
45
45
  browser.version < version_number
46
46
  else
47
- puts "Unexpected comparing operation for Browser condition: #{@version_match_type}"
47
+ Logging::KameleoonLogger.error("Unexpected comparing operation for 'Browser' condition: '#{@version_match_type}'")
48
48
  false
49
49
  end
50
50
  end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'kameleoon/data/cookie'
4
+ require 'kameleoon/logging/kameleoon_logger'
4
5
  require 'kameleoon/version'
5
6
 
6
7
  module Kameleoon
7
8
  # @api private
8
9
  module Targeting
9
-
10
10
  class CookieCondition < Condition
11
11
  def initialize(json_condition)
12
12
  super(json_condition)
@@ -26,13 +26,13 @@ module Kameleoon
26
26
  case @name_match_type
27
27
  when Kameleoon::Targeting::Operator::EXACT
28
28
  value = cookie.cookies[@condition_name]
29
- return value != nil ? [value] : []
29
+ return !value.nil? ? [value] : []
30
30
  when Kameleoon::Targeting::Operator::CONTAINS
31
- return cookie.cookies.select{|key| key.include? @condition_name}.values()
31
+ return cookie.cookies.select { |key| key.include? @condition_name }.values
32
32
  when Kameleoon::Targeting::Operator::REGULAR_EXPRESSION
33
- return cookie.cookies.select{|key| is_regex_match(@condition_name, key)}.values()
33
+ return cookie.cookies.select { |key| is_regex_match(@condition_name, key) }.values
34
34
  else
35
- log "Unexpected comparing operation for Cookie condition (name): #{@name_match_type}"
35
+ Logging::KameleoonLogger.error("Unexpected comparing operation for 'Cookie' condition (name): '#{@name_match_type}'")
36
36
  end
37
37
  []
38
38
  end
@@ -40,14 +40,14 @@ module Kameleoon
40
40
  def check_values(values)
41
41
  case @value_match_type
42
42
  when Kameleoon::Targeting::Operator::EXACT
43
- return values.any? {|value| value == @condition_value}
43
+ values.any? { |value| value == @condition_value }
44
44
  when Kameleoon::Targeting::Operator::CONTAINS
45
- return values.any? {|value| value.include? @condition_value}
45
+ values.any? { |value| value.include? @condition_value }
46
46
  when Kameleoon::Targeting::Operator::REGULAR_EXPRESSION
47
- return values.any? {|value| is_regex_match(@condition_value, value)}
47
+ values.any? { |value| is_regex_match(@condition_value, value) }
48
48
  else
49
- log "Unexpected comparing operation for Cookie condition (name): #{@name_match_type}"
50
- return false
49
+ Logging::KameleoonLogger.error("Unexpected comparing operation for 'Cookie' condition (name): '#{@name_match_type}'")
50
+ false
51
51
  end
52
52
  end
53
53
  end
@@ -6,7 +6,6 @@ require 'kameleoon/version'
6
6
  module Kameleoon
7
7
  # @api private
8
8
  module Targeting
9
-
10
9
  class GeolocationCondition < Condition
11
10
  def initialize(json_condition)
12
11
  super(json_condition)
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/data/device'
4
+
5
+ module Kameleoon
6
+ # @api private
7
+ module Targeting
8
+ # KcsHeatRangeCondition is a condition for checking KCS heat
9
+ class KcsHeatRangeCondition < Condition
10
+ def initialize(json_condition)
11
+ super(json_condition)
12
+ @goal_id = json_condition['goalId'] || -1
13
+ @key_moment_id = json_condition['keyMomentId'] || -1
14
+ @lower_bound = json_condition['lowerBound'] || Float::MAX
15
+ @upper_bound = json_condition['upperBound'] || Float::MIN
16
+ end
17
+
18
+ def check(kcs_heat)
19
+ kcs_heat.is_a?(Kameleoon::KcsHeat) && check_targeting(kcs_heat)
20
+ end
21
+
22
+ private
23
+
24
+ def check_targeting(kcs_heat)
25
+ return false unless kcs_heat.values.is_a?(Hash)
26
+
27
+ goal_scores = kcs_heat.values[@key_moment_id]
28
+ return false unless goal_scores.is_a?(Hash)
29
+
30
+ score = goal_scores[@goal_id]
31
+ return false unless score.is_a?(Float) || score.is_a?(Integer)
32
+
33
+ (score >= @lower_bound) && (score <= @upper_bound)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'kameleoon/data/cookie'
4
+ require 'kameleoon/logging/kameleoon_logger'
4
5
  require 'kameleoon/version'
5
6
 
6
7
  module Kameleoon
7
8
  # @api private
8
9
  module Targeting
9
-
10
10
  class NumberCondition < Condition
11
11
  def initialize(json_condition, value)
12
12
  super(json_condition)
@@ -25,11 +25,11 @@ module Kameleoon
25
25
  when Kameleoon::Targeting::Operator::EQUAL
26
26
  return value == @condition_value
27
27
  when Kameleoon::Targeting::Operator::GREATER
28
- return @condition_value != nil && value > @condition_value
28
+ return !@condition_value.nil? && value > @condition_value
29
29
  when Kameleoon::Targeting::Operator::LOWER
30
- return @condition_value != nil && value < @condition_value
30
+ return !@condition_value.nil? && value < @condition_value
31
31
  else
32
- log "Unexpected comparing operation for #{type} condition: #{@match_type}"
32
+ Logging::KameleoonLogger.error("Unexpected comparing operation for '#{@type}' condition: '#{@match_type}'")
33
33
  end
34
34
  false
35
35
  end
@@ -6,7 +6,6 @@ require 'kameleoon/version'
6
6
  module Kameleoon
7
7
  # @api private
8
8
  module Targeting
9
-
10
9
  class OperatingSystemCondition < Condition
11
10
  def initialize(json_condition)
12
11
  super(json_condition)
@@ -20,7 +19,7 @@ module Kameleoon
20
19
  private
21
20
 
22
21
  def check_targeting(operating_system)
23
- @os_type != nil && operating_system.os_type == @os_type
22
+ !@os_type.nil? && operating_system.os_type == @os_type
24
23
  end
25
24
  end
26
25
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'kameleoon/data/data'
4
+ require 'kameleoon/logging/kameleoon_logger'
4
5
  require 'kameleoon/version'
5
6
 
6
7
  module Kameleoon
@@ -56,7 +57,7 @@ module Kameleoon
56
57
  (major_sdk == major_condition && minor_sdk < minor_condition) ||
57
58
  (major_sdk == major_condition && minor_sdk == minor_condition && patch_sdk < patch_condition)
58
59
  else
59
- puts "Unexpected comparing operation for SdkLanguage condition: #{@operator}"
60
+ Logging::KameleoonLogger.error("Unexpected comparing operation for 'SdkLanguage' condition: '#{@operator}'")
60
61
  false
61
62
  end
62
63
  end
@@ -6,11 +6,10 @@ require 'kameleoon/version'
6
6
  module Kameleoon
7
7
  # @api private
8
8
  module Targeting
9
-
10
9
  class SegmentCondition < Condition
11
10
  def initialize(json_condition)
12
11
  super(json_condition)
13
- @segment_id = json_condition["segmentId"]
12
+ @segment_id = json_condition['segmentId']
14
13
  end
15
14
 
16
15
  def check(data)
@@ -22,7 +21,8 @@ module Kameleoon
22
21
  def check_targeting(segment_info)
23
22
  rule = segment_info.data_file.rule_by_segment_id[@segment_id]
24
23
  return false unless rule.is_a?(Kameleoon::Configuration::Rule)
25
- rule.targeting_segment.check_tree(->(type) {segment_info.condition_data(type)})
24
+
25
+ rule.targeting_segment.check_tree(->(type) { segment_info.condition_data(type) })
26
26
  end
27
27
  end
28
28
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kameleoon/logging/kameleoon_logger'
3
4
  require 'kameleoon/targeting/condition'
4
5
 
5
6
  module Kameleoon
@@ -33,7 +34,7 @@ module Kameleoon
33
34
  pattern = Regexp.new(@condition_value)
34
35
  pattern.match?(value)
35
36
  else
36
- puts "Unexpected comparing operation for #{@type} condition: #{@operator}"
37
+ Logging::KameleoonLogger.error("Unexpected comparing operation for '#{@type}' condition: '#{@operator}'")
37
38
  false
38
39
  end
39
40
  end
@@ -20,20 +20,19 @@ module Kameleoon
20
20
 
21
21
  def check(data)
22
22
  return false unless data.is_a?(Kameleoon::Targeting::TargetFeatureFlagInfo) && data.variations_storage.size != 0
23
- get_rules(data).any? {|rule| check_rule(data, rule)}
23
+
24
+ get_rules(data).any? { |rule| check_rule(data, rule) }
24
25
  end
25
26
 
26
27
  private def check_rule(data, rule)
27
- return false if !rule.is_a?(Kameleoon::Configuration::Rule) || rule.experiment_id == nil
28
+ return false if !rule.is_a?(Kameleoon::Configuration::Rule) || rule.experiment_id.nil?
28
29
 
29
- if @condition_rule_id != nil
30
- return false if @condition_rule_id != rule.id
31
- end
30
+ return false if !@condition_rule_id.nil? && (@condition_rule_id != rule.id)
32
31
 
33
32
  variation = data.variations_storage.get(rule.experiment_id)
34
- return false if variation == nil
33
+ return false if variation.nil?
35
34
 
36
- return true if @condition_variation_key == nil
35
+ return true if @condition_variation_key.nil?
37
36
 
38
37
  variation = data.data_file.variation_by_id[variation.variation_id]
39
38
 
@@ -44,10 +43,7 @@ module Kameleoon
44
43
 
45
44
  def get_rules(data)
46
45
  feature_flag = data.data_file.feature_flag_by_id[@feature_flag_id]
47
- if feature_flag != nil
48
- return feature_flag.rules
49
- end
50
- []
46
+ feature_flag&.rules || []
51
47
  end
52
48
  end
53
49
 
@@ -6,7 +6,6 @@ require 'kameleoon/data/visitor_visits'
6
6
  module Kameleoon
7
7
  # @api private
8
8
  module Targeting
9
-
10
9
  class TimeElapsedSinceVisitCondition < NumberCondition
11
10
  def initialize(json_condition)
12
11
  count_in_millis = json_condition['countInMillis']
@@ -15,7 +14,7 @@ module Kameleoon
15
14
  end
16
15
 
17
16
  def check(data)
18
- return false unless data.is_a?(Kameleoon::VisitorVisits) && @condition_value != nil
17
+ return false unless data.is_a?(Kameleoon::VisitorVisits) && !@condition_value.nil?
19
18
 
20
19
  previous_visits_count = data.previous_visit_timestamps.count
21
20
  if previous_visits_count >= 1
@@ -6,7 +6,6 @@ require 'time'
6
6
  module Kameleoon
7
7
  # @api private
8
8
  module Targeting
9
-
10
9
  class VisitNumberTodayCondition < NumberCondition
11
10
  def initialize(json_condition)
12
11
  visit_count = json_condition['visitCount']
@@ -14,10 +13,11 @@ module Kameleoon
14
13
  end
15
14
 
16
15
  def check(data)
17
- return false unless data.is_a?(Kameleoon::VisitorVisits) && @condition_value != nil
16
+ return false unless VisitorVisits.visitor_visits?(data) && !@condition_value.nil?
17
+
18
18
  number_of_visits_today = 0
19
- start_of_day = (Time.new.to_date.to_time.to_f * 1000).to_i # ... * 1000 for convert seconds to milliseconds
20
- for timestamp in data.previous_visit_timestamps
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
21
  break if timestamp < start_of_day
22
22
  number_of_visits_today += 1
23
23
  end