kameleoon-client-ruby 2.2.0 → 3.0.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/client_readiness.rb +40 -0
  3. data/lib/kameleoon/configuration/data_file.rb +41 -0
  4. data/lib/kameleoon/configuration/feature_flag.rb +3 -2
  5. data/lib/kameleoon/configuration/rule.rb +18 -3
  6. data/lib/kameleoon/configuration/settings.rb +3 -1
  7. data/lib/kameleoon/configuration/variable.rb +0 -2
  8. data/lib/kameleoon/configuration/variation_exposition.rb +0 -2
  9. data/lib/kameleoon/data/browser.rb +1 -1
  10. data/lib/kameleoon/data/conversion.rb +1 -1
  11. data/lib/kameleoon/data/custom_data.rb +10 -14
  12. data/lib/kameleoon/data/data.rb +22 -3
  13. data/lib/kameleoon/data/device.rb +2 -1
  14. data/lib/kameleoon/data/manager/assigned_variation.rb +38 -0
  15. data/lib/kameleoon/data/manager/data_array_storage.rb +43 -0
  16. data/lib/kameleoon/data/manager/data_map_storage.rb +43 -0
  17. data/lib/kameleoon/data/manager/page_view_visit.rb +19 -0
  18. data/lib/kameleoon/data/manager/visitor.rb +142 -0
  19. data/lib/kameleoon/data/manager/visitor_manager.rb +71 -0
  20. data/lib/kameleoon/data/page_view.rb +2 -1
  21. data/lib/kameleoon/exceptions.rb +30 -35
  22. data/lib/kameleoon/hybrid/manager.rb +13 -31
  23. data/lib/kameleoon/{client.rb → kameleoon_client.rb} +165 -333
  24. data/lib/kameleoon/kameleoon_client_config.rb +91 -0
  25. data/lib/kameleoon/kameleoon_client_factory.rb +42 -0
  26. data/lib/kameleoon/network/activity_event.rb +6 -3
  27. data/lib/kameleoon/network/cookie/cookie_manager.rb +84 -0
  28. data/lib/kameleoon/network/net_provider.rb +5 -37
  29. data/lib/kameleoon/network/network_manager.rb +8 -7
  30. data/lib/kameleoon/network/request.rb +3 -2
  31. data/lib/kameleoon/network/response.rb +0 -8
  32. data/lib/kameleoon/network/url_provider.rb +5 -3
  33. data/lib/kameleoon/targeting/conditions/browser_condition.rb +2 -3
  34. data/lib/kameleoon/targeting/conditions/conversion_condition.rb +12 -4
  35. data/lib/kameleoon/targeting/conditions/custom_datum.rb +19 -13
  36. data/lib/kameleoon/targeting/conditions/device_condition.rb +3 -4
  37. data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +2 -1
  38. data/lib/kameleoon/targeting/conditions/page_title_condition.rb +11 -4
  39. data/lib/kameleoon/targeting/conditions/page_url_condition.rb +18 -4
  40. data/lib/kameleoon/targeting/conditions/string_value_condition.rb +2 -0
  41. data/lib/kameleoon/targeting/conditions/target_experiment.rb +11 -6
  42. data/lib/kameleoon/utils.rb +41 -4
  43. data/lib/kameleoon/version.rb +1 -1
  44. data/lib/kameleoon.rb +4 -2
  45. metadata +14 -9
  46. data/lib/kameleoon/configuration/experiment.rb +0 -42
  47. data/lib/kameleoon/cookie.rb +0 -88
  48. data/lib/kameleoon/factory.rb +0 -29
  49. data/lib/kameleoon/network/experiment_event.rb +0 -35
  50. data/lib/kameleoon/storage/variation_storage.rb +0 -42
  51. data/lib/kameleoon/storage/visitor_variation.rb +0 -20
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kameleoon
4
+ # KameleoonClient configuration which can be used instead of an external configuration file
5
+ class KameleoonClientConfig
6
+ DEFAULT_REFRESH_INTERVAL_MINUTES = 60
7
+ DEFAULT_SESSION_DURATION_MINUTES = 30
8
+ DEFAULT_TIMEOUT_MILLISECONDS = 10_000
9
+
10
+ attr_reader :client_id, :client_secret, :refresh_interval_second, :session_duration_second,
11
+ :default_timeout_millisecond, :environment, :top_level_domain, :verbose_mode
12
+
13
+ def initialize(
14
+ client_id,
15
+ client_secret,
16
+ refresh_interval_minute: DEFAULT_REFRESH_INTERVAL_MINUTES,
17
+ session_duration_minute: DEFAULT_SESSION_DURATION_MINUTES,
18
+ default_timeout_millisecond: DEFAULT_TIMEOUT_MILLISECONDS,
19
+ environment: nil,
20
+ top_level_domain: nil,
21
+ verbose_mode: false
22
+ )
23
+ raise Exception::ConfigCredentialsInvalid, 'Client ID is not specified' if client_id&.empty? != false
24
+ raise Exception::ConfigCredentialsInvalid, 'Client secret is not specified' if client_secret&.empty? != false
25
+
26
+ @verbose_mode = verbose_mode || false
27
+
28
+ @client_id = client_id
29
+ @client_secret = client_secret
30
+
31
+ if refresh_interval_minute.nil?
32
+ refresh_interval_minute = DEFAULT_REFRESH_INTERVAL_MINUTES
33
+ elsif refresh_interval_minute <= 0
34
+ log('Configuration refresh interval must have positive value. ' \
35
+ "Default refresh interval (#{DEFAULT_REFRESH_INTERVAL_MINUTES} minutes) is applied.")
36
+ refresh_interval_minute = DEFAULT_REFRESH_INTERVAL_MINUTES
37
+ end
38
+ @refresh_interval_second = refresh_interval_minute * 60
39
+
40
+ if session_duration_minute.nil?
41
+ session_duration_minute = DEFAULT_SESSION_DURATION_MINUTES
42
+ elsif session_duration_minute <= 0
43
+ log('Session duration must have positive value. ' \
44
+ "Default session duration (#{DEFAULT_SESSION_DURATION_MINUTES} minutes) is applied.")
45
+ session_duration_minute = DEFAULT_SESSION_DURATION_MINUTES
46
+ end
47
+ @session_duration_second = session_duration_minute * 60
48
+
49
+ if default_timeout_millisecond.nil?
50
+ @default_timeout_millisecond = DEFAULT_TIMEOUT_MILLISECONDS
51
+ elsif default_timeout_millisecond <= 0
52
+ log('Default timeout must have positive value. ' \
53
+ "Default timeout (#{DEFAULT_TIMEOUT_MILLISECONDS} ms) is applied.")
54
+ @default_timeout_millisecond = DEFAULT_TIMEOUT_MILLISECONDS
55
+ else
56
+ @default_timeout_millisecond = default_timeout_millisecond
57
+ end
58
+
59
+ @environment = environment
60
+
61
+ if top_level_domain.nil?
62
+ log('Setting top level domain is strictly recommended, otherwise you may have problems when using subdomains.')
63
+ end
64
+ @top_level_domain = top_level_domain
65
+ end
66
+
67
+ def self.read_from_yaml(path)
68
+ yaml = YAML.load_file(path) if File.exist?(path)
69
+ if yaml.nil?
70
+ warn "Kameleoon SDK: Configuration file with path #{path} does not exist"
71
+ yaml = {}
72
+ end
73
+ KameleoonClientConfig.new(
74
+ yaml['client_id'],
75
+ yaml['client_secret'],
76
+ refresh_interval_minute: yaml['refresh_interval_minute'],
77
+ session_duration_minute: yaml['session_duration_minute'],
78
+ default_timeout_millisecond: yaml['default_timeout_millisecond'],
79
+ environment: yaml['environment'],
80
+ top_level_domain: yaml['top_level_domain'],
81
+ verbose_mode: yaml['verbose_mode']
82
+ )
83
+ end
84
+
85
+ private
86
+
87
+ def log(text)
88
+ print "Kameleoon SDK Log: #{text}\n" if @verbose_mode
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent'
4
+ require 'kameleoon/kameleoon_client'
5
+ require 'kameleoon/kameleoon_client_config'
6
+
7
+ module Kameleoon
8
+ # A Factory class for creating kameleoon clients
9
+ module KameleoonClientFactory
10
+ CONFIG_PATH = '/etc/kameleoon/client-ruby.yaml'
11
+
12
+ @clients = Concurrent::Map.new
13
+
14
+ def self.create(site_code, config: nil, config_path: CONFIG_PATH)
15
+ unless config.is_a?(KameleoonClientConfig)
16
+ config_path = CONFIG_PATH unless config_path.is_a?(String)
17
+ config = KameleoonClientConfig.read_from_yaml(config_path)
18
+ end
19
+ key = get_client_key(site_code, config.environment)
20
+ @clients.compute_if_absent(key) do
21
+ client = KameleoonClient.new(site_code, config)
22
+ client.send(:log, "Client created with site code: #{site_code}")
23
+ client.send(:fetch_configuration_initially)
24
+ client
25
+ end
26
+ end
27
+
28
+ def self.forget(site_code, environment = nil)
29
+ key = get_client_key(site_code, environment)
30
+ @clients.compute_if_present(key) do |client|
31
+ client.send(:dispose)
32
+ nil
33
+ end
34
+ end
35
+
36
+ private_class_method
37
+
38
+ def self.get_client_key(site_code, environment)
39
+ environment.nil? ? site_code : "#{site_code}/#{environment}"
40
+ end
41
+ end
42
+ end
@@ -12,20 +12,23 @@ module Kameleoon
12
12
  class ActivityEvent
13
13
  EVENT_TYPE = 'activity'
14
14
 
15
- attr_accessor :sent
15
+ attr_reader :sent
16
16
 
17
17
  def initialize
18
18
  @sent = false
19
- @nonce = Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
20
19
  end
21
20
 
22
21
  def obtain_full_post_text_line
23
22
  params = {
24
23
  eventType: EVENT_TYPE,
25
- nonce: @nonce
24
+ nonce: Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
26
25
  }
27
26
  UriHelper.encode_query(params)
28
27
  end
28
+
29
+ def mark_as_sent
30
+ @sent = true
31
+ end
29
32
  end
30
33
  end
31
34
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kameleoon/utils'
4
+
5
+ module Kameleoon
6
+ module Network
7
+ module Cookie
8
+ COOKIE_KEY_JS = '_js_'
9
+ VISITOR_CODE_COOKIE = 'kameleoonVisitorCode'
10
+ COOKIE_TTL_SECONDS = 380 * 86_400 # 380 days in seconds
11
+
12
+ class CookieManager
13
+ attr_accessor :consent_required
14
+
15
+ def initialize(top_level_domain)
16
+ @consent_required = false
17
+ @top_level_domain = top_level_domain
18
+ end
19
+
20
+ def get_or_add(cookies, default_visitor_code = nil)
21
+ return if cookies.nil?
22
+
23
+ visitor_code = get_visitor_code_from_cookies(cookies)
24
+ unless visitor_code.nil?
25
+ Utils::VisitorCode.validate(visitor_code)
26
+ # Remove adding cookies when we will be sure that it doesn't break anything
27
+ add(visitor_code, cookies) unless @consent_required
28
+ return visitor_code
29
+ end
30
+
31
+ if default_visitor_code.nil?
32
+ visitor_code = Utils::VisitorCode.generate
33
+ add(visitor_code, cookies) unless @consent_required
34
+ return visitor_code
35
+ end
36
+
37
+ visitor_code = default_visitor_code
38
+ Utils::VisitorCode.validate(visitor_code)
39
+ add(visitor_code, cookies)
40
+ visitor_code
41
+ end
42
+
43
+ def update(visitor_code, consent, cookies)
44
+ return if cookies.nil?
45
+
46
+ if consent
47
+ add(visitor_code, cookies)
48
+ else
49
+ remove(cookies)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def add(visitor_code, cookies)
56
+ cookie = {
57
+ value: visitor_code,
58
+ expires: Time.now + COOKIE_TTL_SECONDS,
59
+ path: '/',
60
+ domain: @top_level_domain
61
+ }
62
+ cookies[VISITOR_CODE_COOKIE] = cookie
63
+ end
64
+
65
+ def remove(cookies)
66
+ cookies[VISITOR_CODE_COOKIE] = nil if @consent_required
67
+ end
68
+
69
+ def get_visitor_code_from_cookies(cookies)
70
+ cookie = cookies[VISITOR_CODE_COOKIE]
71
+ case cookie
72
+ when String
73
+ visitor_code = cookie
74
+ when Hash
75
+ visitor_code = cookie[:value]
76
+ end
77
+ visitor_code = visitor_code[COOKIE_KEY_JS.size..] if visitor_code&.start_with?(COOKIE_KEY_JS)
78
+ visitor_code = nil if visitor_code&.empty?
79
+ visitor_code
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'em-synchrony/em-http'
4
3
  require 'net/http'
5
4
  require 'kameleoon/version'
6
5
  require 'kameleoon/network/response'
@@ -16,7 +15,8 @@ module Kameleoon
16
15
  private
17
16
 
18
17
  def collect_headers(request)
19
- headers = { 'Content-Type': request.content_type }
18
+ headers = request.extra_headers || {}
19
+ headers['Content-Type'] = request.content_type
20
20
  headers['User-Agent'] = request.user_agent unless request.user_agent.nil?
21
21
  headers
22
22
  end
@@ -26,40 +26,6 @@ module Kameleoon
26
26
  end
27
27
  end
28
28
 
29
- class EMNetProvider < NetProvider
30
- def make_request(request)
31
- connetion_options = {
32
- tls: { verify_peer: false },
33
- connect_timeout: request.timeout,
34
- inactivity_timeout: request.timeout
35
- }
36
- headers = collect_headers(request)
37
- request_options = { head: headers, body: request.data }
38
- begin
39
- case request.method
40
- when Method::POST
41
- EventMachine::HttpRequest.new(request.url, connetion_options).apost(request_options)
42
- when Method::GET
43
- EventMachine::HttpRequest.new(request.url, connetion_options).aget(request_options)
44
- else
45
- dfr = DeferrableResponse.new
46
- dfr.response = unknown_method_response(request.method, request)
47
- dfr
48
- end
49
- rescue => e
50
- dfr = DeferrableResponse.new
51
- dfr.response = Response.new(e, nil, nil, request)
52
- dfr
53
- end
54
- end
55
-
56
- def self.em_resp_to_response(request, resp)
57
- return resp if resp.is_a?(Response)
58
-
59
- Response.new(nil, resp.response_header.status, resp.response, request)
60
- end
61
- end
62
-
63
29
  class SyncNetProvider < NetProvider
64
30
  def make_request(request)
65
31
  resp = nil
@@ -84,7 +50,9 @@ module Kameleoon
84
50
  rescue => e
85
51
  return Response.new(e, nil, nil, request)
86
52
  end
87
- Response.new(nil, resp.code.to_i, resp.body, request)
53
+ body = resp.body
54
+ body = nil if body&.empty?
55
+ Response.new(nil, resp.code.to_i, body, request)
88
56
  end
89
57
  end
90
58
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'em-synchrony'
4
3
  require 'kameleoon/network/content_type'
5
4
  require 'kameleoon/network/method'
6
5
  require 'kameleoon/network/request'
7
6
  require 'kameleoon/network/net_provider'
7
+ require 'kameleoon/version'
8
8
 
9
9
  module Kameleoon
10
10
  module Network
@@ -14,6 +14,8 @@ module Kameleoon
14
14
  FETCH_CONFIGURATION_ATTEMPT_NUMBER = 4
15
15
  TRACKING_CALL_ATTEMPT_NUMBER = 4
16
16
  TRACKING_CALL_RETRY_DELAY = 5.0 # in seconds
17
+ SDK_TYPE_HEADER = 'X-Kameleoon-SDK-Type'
18
+ SDK_VERSION_HEADER = 'X-Kameleoon-SDK-Version'
17
19
 
18
20
  attr_reader :environment, :default_timeout, :url_provider
19
21
 
@@ -21,7 +23,6 @@ module Kameleoon
21
23
  @environment = environment
22
24
  @default_timeout = default_timeout
23
25
  @url_provider = url_provider
24
- @em_net_provider = EMNetProvider.new
25
26
  @sync_net_provider = SyncNetProvider.new
26
27
  @log_func = log_func
27
28
  end
@@ -29,11 +30,11 @@ module Kameleoon
29
30
  def fetch_configuration(timestamp = nil, timeout = nil)
30
31
  url = @url_provider.make_configuration_url(@environment, timestamp)
31
32
  timeout = ensure_timeout(timeout)
32
- request = Request.new(Method::GET, url, ContentType::JSON, timeout)
33
+ sdk_headers = { SDK_TYPE_HEADER => SDK_NAME, SDK_VERSION_HEADER => SDK_VERSION }
34
+ request = Request.new(Method::GET, url, ContentType::JSON, timeout, extra_headers: sdk_headers)
33
35
  attempts_left = FETCH_CONFIGURATION_ATTEMPT_NUMBER
34
36
  while attempts_left.positive?
35
- em_resp = EM::Synchrony.sync(@em_net_provider.make_request(request))
36
- response = EMNetProvider.em_resp_to_response(request, em_resp)
37
+ response = @sync_net_provider.make_request(request)
37
38
  result = handle_response(response)
38
39
  return result if result
39
40
 
@@ -64,13 +65,13 @@ module Kameleoon
64
65
  url = @url_provider.make_tracking_url(visitor_code)
65
66
  timeout = ensure_timeout(timeout)
66
67
  data = (lines.map(&:obtain_full_post_text_line).join("\n") || '').encode('UTF-8')
67
- request = Request.new(Method::POST, url, ContentType::TEXT, timeout, user_agent, data)
68
+ request = Request.new(Method::POST, url, ContentType::TEXT, timeout, user_agent: user_agent, data: data)
68
69
  Thread.new do
69
70
  attempts_left = TRACKING_CALL_ATTEMPT_NUMBER
70
71
  loop do
71
72
  response = @sync_net_provider.make_request(request)
72
73
  if handle_response(response) != false
73
- lines.each { |line| line.sent = true }
74
+ lines.each(&:mark_as_sent)
74
75
  break
75
76
  end
76
77
  attempts_left -= 1
@@ -5,14 +5,15 @@ module Kameleoon
5
5
  ##
6
6
  # Request represents HTTP request.
7
7
  class Request
8
- attr_reader :method, :url, :content_type, :timeout, :user_agent, :data
8
+ attr_reader :method, :url, :content_type, :timeout, :user_agent, :extra_headers, :data
9
9
 
10
- def initialize(method, url, content_type, timeout, user_agent = nil, data = nil)
10
+ def initialize(method, url, content_type, timeout, user_agent: nil, extra_headers: nil, data: nil)
11
11
  @method = method
12
12
  @url = url
13
13
  @content_type = content_type
14
14
  @timeout = timeout
15
15
  @user_agent = user_agent
16
+ @extra_headers = extra_headers
16
17
  @data = !data.nil? && data.is_a?(String) ? data.encode('UTF-8') : data
17
18
  end
18
19
  end
@@ -18,13 +18,5 @@ module Kameleoon
18
18
  @error.nil? && (@code / 100 == 2)
19
19
  end
20
20
  end
21
-
22
- class DeferrableResponse < EventMachine::DefaultDeferrable
23
- attr_writer :response
24
-
25
- def callback(&blk)
26
- blk.call(@response)
27
- end
28
- end
29
21
  end
30
22
  end
@@ -12,7 +12,7 @@ module Kameleoon
12
12
  VISITOR_DATA_PATH = '/visit/visitor'
13
13
  GET_DATA_PATH = '/map/map'
14
14
  POST_DATA_PATH = '/map/maps'
15
- CONFIGURATION_API_URL = 'https://client-config.kameleoon.com/mobile'
15
+ CONFIGURATION_API_URL_FORMAT = 'https://sdk-config.kameleoon.eu/%s'
16
16
  RT_CONFIGURATION_URL = 'https://events.kameleoon.com:8110/sse'
17
17
 
18
18
  DEFAULT_DATA_API_URL = 'https://data.kameleoon.io'
@@ -56,10 +56,12 @@ module Kameleoon
56
56
  end
57
57
 
58
58
  def make_configuration_url(environment = nil, timestamp = nil)
59
- params = { siteCode: @site_code }
59
+ url = format(CONFIGURATION_API_URL_FORMAT, @site_code)
60
+ params = {}
60
61
  params[:environment] = environment unless environment.nil?
61
62
  params[:ts] = timestamp unless timestamp.nil?
62
- "#{CONFIGURATION_API_URL}?#{UriHelper.encode_query(params)}"
63
+ url = "#{url}?#{UriHelper.encode_query(params)}" unless params.empty?
64
+ url
63
65
  end
64
66
 
65
67
  def make_real_time_url
@@ -22,9 +22,8 @@ module Kameleoon
22
22
  @version_match_type = json_condition['versionMatchType']
23
23
  end
24
24
 
25
- def check(list_data)
26
- browser = get_last_targeting_data(list_data, Kameleoon::DataType::BROWSER)
27
- browser && check_targeting(browser)
25
+ def check(browser)
26
+ browser.is_a?(Kameleoon::Browser) && check_targeting(browser)
28
27
  end
29
28
 
30
29
  private
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'kameleoon/data/data'
3
+ require 'kameleoon/data/conversion'
4
+ require 'kameleoon/data/manager/data_array_storage'
4
5
 
5
6
  module Kameleoon
6
7
  # @api private
@@ -12,9 +13,16 @@ module Kameleoon
12
13
  @goal_id = json_condition['goalId']
13
14
  end
14
15
 
15
- def check(list_data)
16
- conversion = get_last_targeting_data(list_data, Kameleoon::DataType::CONVERSION)
17
- conversion && (@goal_id.nil? || @goal_id == conversion.goal_id)
16
+ def check(conversion_storage)
17
+ return false unless conversion_storage.is_a?(Kameleoon::DataManager::DataArrayStorage)
18
+ return true if @goal_id.nil?
19
+
20
+ is_targeted = false
21
+ conversion_storage.enumerate do |conversion|
22
+ is_targeted = conversion.is_a?(Kameleoon::Conversion) && (@goal_id == conversion.goal_id)
23
+ break if is_targeted
24
+ end
25
+ is_targeted
18
26
  end
19
27
  end
20
28
  end
@@ -12,6 +12,10 @@ module Kameleoon
12
12
  include Kameleoon::Exception
13
13
 
14
14
  class << self
15
+ def op_undefined(values, value)
16
+ false
17
+ end
18
+
15
19
  def op_match(values, value)
16
20
  re = Regexp.new(value.to_s)
17
21
  values.any? { |v| re.match(v) }
@@ -26,7 +30,8 @@ module Kameleoon
26
30
  end
27
31
 
28
32
  def op_equal(values, value)
29
- values.any? { |v| v.to_f == value.to_f }
33
+ epsilon = 1e-9
34
+ values.any? { |v| (v.to_f - value.to_f).abs < epsilon }
30
35
  end
31
36
 
32
37
  def op_greater(values, value)
@@ -52,6 +57,7 @@ module Kameleoon
52
57
  end
53
58
 
54
59
  @@op = {
60
+ Operator::UNDEFINED => method(:op_undefined),
55
61
  Operator::REGULAR_EXPRESSION => method(:op_match),
56
62
  Operator::CONTAINS => method(:op_contains),
57
63
  Operator::EXACT => method(:op_exact),
@@ -71,24 +77,24 @@ module Kameleoon
71
77
  end
72
78
 
73
79
  @type = ConditionType::CUSTOM_DATUM
74
- @index = json_condition['customDataIndex']
80
+ @index = json_condition['customDataIndex'].to_i
75
81
  @operator = json_condition['valueMatchType']
82
+ @operation = @@op[@operator]
76
83
  @value = json_condition['value']
77
84
  end
78
85
 
79
- def check(list_data)
80
- is_targeted = false
81
- custom_data = list_data.select { |data| data.instance == DataType::CUSTOM && data.id == @index }.last
82
- if custom_data.nil?
83
- is_targeted = (@operator == Operator::UNDEFINED.to_s)
84
- elsif @operator != Operator::UNDEFINED.to_s
85
- @operation = @@op[@operator]
86
- unless @operation
87
- raise KameleoonError.new("Undefined operator #{@operator}"), "Undefined operator #{@operator}"
86
+ def check(custom_data_storage)
87
+ is_targeted = nil
88
+ if custom_data_storage.is_a?(Kameleoon::DataManager::DataMapStorage)
89
+ custom_data = custom_data_storage.get(@index)
90
+ if custom_data.is_a?(Kameleoon::CustomData)
91
+ unless @operation
92
+ raise KameleoonError.new("Undefined operator #{@operator}"), "Undefined operator #{@operator}"
93
+ end
94
+ is_targeted = @operation.call(custom_data.values, @value)
88
95
  end
89
-
90
- is_targeted = @operation.call(custom_data.values, @value)
91
96
  end
97
+ is_targeted = (@operator == Operator::UNDEFINED.to_s) if is_targeted.nil?
92
98
  is_targeted
93
99
  end
94
100
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'kameleoon/data/data'
3
+ require 'kameleoon/data/device'
4
4
 
5
5
  module Kameleoon
6
6
  # @api private
@@ -12,9 +12,8 @@ module Kameleoon
12
12
  @device_type = json_condition['device']
13
13
  end
14
14
 
15
- def check(list_data)
16
- device = get_last_targeting_data(list_data, Kameleoon::DataType::DEVICE)
17
- device && @device_type == device.device_type
15
+ def check(device)
16
+ device.is_a?(Kameleoon::Device) && @device_type == device.device_type
18
17
  end
19
18
  end
20
19
  end
@@ -10,7 +10,8 @@ module Kameleoon
10
10
  def check(data)
11
11
  experiment_id = data.experiment_id
12
12
  storage = data.storage
13
- storage.nil? || storage.empty? || (storage.length == 1 && !storage[experiment_id].nil?)
13
+ storage.is_a?(Kameleoon::DataManager::DataMapStorage) &&
14
+ (storage.size.zero? || ((storage.size == 1) && !storage.get(experiment_id).nil?))
14
15
  end
15
16
  end
16
17
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'kameleoon/data/data'
3
+ require 'kameleoon/data/manager/data_map_storage'
4
+ require 'kameleoon/data/manager/page_view_visit'
4
5
  require_relative 'string_value_condition'
5
6
 
6
7
  module Kameleoon
@@ -12,9 +13,15 @@ module Kameleoon
12
13
  super(json_condition, json_condition['title'])
13
14
  end
14
15
 
15
- def check(list_data)
16
- page_view = get_last_targeting_data(list_data, Kameleoon::DataType::PAGE_VIEW)
17
- page_view && check_targeting(page_view.title)
16
+ def check(page_view_visit_storage)
17
+ return false unless page_view_visit_storage.is_a?(Kameleoon::DataManager::DataMapStorage)
18
+
19
+ is_targeted = false
20
+ page_view_visit_storage.enumerate do |visit|
21
+ is_targeted = visit.is_a?(Kameleoon::DataManager::PageViewVisit) && check_targeting(visit.page_view.title)
22
+ break if is_targeted
23
+ end
24
+ is_targeted
18
25
  end
19
26
  end
20
27
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'kameleoon/data/data'
3
+ require 'kameleoon/data/manager/data_map_storage'
4
+ require 'kameleoon/data/manager/page_view_visit'
4
5
  require_relative 'string_value_condition'
5
6
 
6
7
  module Kameleoon
@@ -12,9 +13,22 @@ module Kameleoon
12
13
  super(json_condition, json_condition['url'])
13
14
  end
14
15
 
15
- def check(list_data)
16
- page_view = get_last_targeting_data(list_data, Kameleoon::DataType::PAGE_VIEW)
17
- page_view && check_targeting(page_view.url)
16
+ def check(page_view_visit_storage)
17
+ return false unless page_view_visit_storage.is_a?(Kameleoon::DataManager::DataMapStorage)
18
+ return !page_view_visit_storage.get(condition_value).nil? if operator == Operator::EXACT
19
+
20
+ is_targeted = false
21
+ page_view_visit_storage.enumerate do |visit|
22
+ is_targeted = check_page_view_visit(visit)
23
+ break if is_targeted
24
+ end
25
+ is_targeted
26
+ end
27
+
28
+ private
29
+
30
+ def check_page_view_visit(visit)
31
+ visit.is_a?(Kameleoon::DataManager::PageViewVisit) && check_targeting(visit.page_view.url)
18
32
  end
19
33
  end
20
34
  end
@@ -19,6 +19,8 @@ module Kameleoon
19
19
 
20
20
  protected
21
21
 
22
+ attr_reader :operator, :condition_value
23
+
22
24
  def check_targeting(value)
23
25
  return false if value.nil?
24
26
 
@@ -24,16 +24,21 @@ module Kameleoon
24
24
  end
25
25
 
26
26
  def check(variation_storage)
27
- is_targeted = false
28
- variation_storage_exist = !variation_storage.nil? && !variation_storage.empty?
29
- saved_variation = variation_storage[@experiment] unless variation_storage.nil?
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
+
30
33
  case @operator
31
34
  when Operator::EXACT
32
- is_targeted = variation_storage_exist && saved_variation == @variation
35
+ variation = variation_storage.get(@experiment)
36
+ variation.variation_id == @variation
33
37
  when Operator::ANY
34
- is_targeted = variation_storage_exist
38
+ true
39
+ else
40
+ false
35
41
  end
36
- is_targeted
37
42
  end
38
43
  end
39
44
  end