kameleoon-client-ruby 2.1.0 → 2.2.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.
- checksums.yaml +4 -4
- data/lib/kameleoon/client.rb +105 -151
- data/lib/kameleoon/configuration/rule.rb +1 -1
- data/lib/kameleoon/data/browser.rb +39 -0
- data/lib/kameleoon/data/conversion.rb +33 -0
- data/lib/kameleoon/data/custom_data.rb +60 -0
- data/lib/kameleoon/data/data.rb +38 -0
- data/lib/kameleoon/data/device.rb +31 -0
- data/lib/kameleoon/data/page_view.rb +34 -0
- data/lib/kameleoon/data/user_agent.rb +14 -0
- data/lib/kameleoon/network/activity_event.rb +31 -0
- data/lib/kameleoon/network/content_type.rb +11 -0
- data/lib/kameleoon/network/experiment_event.rb +35 -0
- data/lib/kameleoon/network/method.rb +10 -0
- data/lib/kameleoon/network/net_provider.rb +91 -0
- data/lib/kameleoon/network/network_manager.rb +114 -0
- data/lib/kameleoon/network/request.rb +20 -0
- data/lib/kameleoon/network/response.rb +30 -0
- data/lib/kameleoon/network/uri_helper.rb +37 -0
- data/lib/kameleoon/network/url_provider.rb +71 -0
- data/lib/kameleoon/targeting/condition.rb +40 -11
- data/lib/kameleoon/targeting/condition_factory.rb +35 -12
- data/lib/kameleoon/targeting/conditions/browser_condition.rb +71 -0
- data/lib/kameleoon/targeting/conditions/conversion_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/custom_datum.rb +60 -65
- data/lib/kameleoon/targeting/conditions/device_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/exclusive_experiment.rb +0 -12
- data/lib/kameleoon/targeting/conditions/page_title_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/page_url_condition.rb +21 -0
- data/lib/kameleoon/targeting/conditions/sdk_language_condition.rb +65 -0
- data/lib/kameleoon/targeting/conditions/string_value_condition.rb +40 -0
- data/lib/kameleoon/targeting/conditions/target_experiment.rb +4 -8
- data/lib/kameleoon/targeting/conditions/unknown_condition.rb +15 -0
- data/lib/kameleoon/targeting/conditions/visitor_code_condition.rb +16 -0
- data/lib/kameleoon/targeting/models.rb +0 -24
- data/lib/kameleoon/utils.rb +1 -1
- data/lib/kameleoon/version.rb +28 -1
- metadata +28 -4
- data/lib/kameleoon/data.rb +0 -175
- data/lib/kameleoon/request.rb +0 -90
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'kameleoon/network/uri_helper'
|
5
|
+
require_relative 'data'
|
6
|
+
|
7
|
+
module Kameleoon
|
8
|
+
# Represents page view data for tracking calls
|
9
|
+
class PageView < Data
|
10
|
+
attr_reader :url, :title, :referrer
|
11
|
+
|
12
|
+
# @param [String] url Url of the page
|
13
|
+
# @param [String] title Title of the page
|
14
|
+
# @param [Array] referrers Optional field - Referrer ids
|
15
|
+
def initialize(url, title, referrers = nil)
|
16
|
+
super(DataType::PAGE_VIEW)
|
17
|
+
@url = url || ''
|
18
|
+
@title = title || ''
|
19
|
+
@referrers = referrers.instance_of?(Integer) ? [referrers] : referrers
|
20
|
+
end
|
21
|
+
|
22
|
+
def obtain_full_post_text_line
|
23
|
+
params = {
|
24
|
+
eventType: 'page',
|
25
|
+
href: @url,
|
26
|
+
title: @title,
|
27
|
+
nonce: nonce
|
28
|
+
}
|
29
|
+
params[:referrersIndices] = "[#{@referrers.each(&:to_s).join(',')}]" if
|
30
|
+
!@referrers.nil? && !@referrers.empty?
|
31
|
+
Kameleoon::Network::UriHelper.encode_query(params)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'kameleoon/data/data'
|
5
|
+
require 'kameleoon/utils'
|
6
|
+
require 'kameleoon/network/uri_helper'
|
7
|
+
|
8
|
+
module Kameleoon
|
9
|
+
module Network
|
10
|
+
##
|
11
|
+
# ActivityEvent represents an activity tracking event.
|
12
|
+
class ActivityEvent
|
13
|
+
EVENT_TYPE = 'activity'
|
14
|
+
|
15
|
+
attr_accessor :sent
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@sent = false
|
19
|
+
@nonce = Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
|
20
|
+
end
|
21
|
+
|
22
|
+
def obtain_full_post_text_line
|
23
|
+
params = {
|
24
|
+
eventType: EVENT_TYPE,
|
25
|
+
nonce: @nonce
|
26
|
+
}
|
27
|
+
UriHelper.encode_query(params)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'kameleoon/data/data'
|
5
|
+
require 'kameleoon/utils'
|
6
|
+
require 'kameleoon/network/uri_helper'
|
7
|
+
|
8
|
+
module Kameleoon
|
9
|
+
module Network
|
10
|
+
##
|
11
|
+
# ExperimentEvent represents an experiment tracking event.
|
12
|
+
class ExperimentEvent
|
13
|
+
EVENT_TYPE = 'experiment'
|
14
|
+
|
15
|
+
attr_accessor :sent
|
16
|
+
|
17
|
+
def initialize(experiment_id, variation_id)
|
18
|
+
@sent = false
|
19
|
+
@experiment_id = experiment_id
|
20
|
+
@variation_id = variation_id
|
21
|
+
@nonce = Kameleoon::Utils.generate_random_string(Kameleoon::NONCE_LENGTH)
|
22
|
+
end
|
23
|
+
|
24
|
+
def obtain_full_post_text_line
|
25
|
+
params = {
|
26
|
+
eventType: EVENT_TYPE,
|
27
|
+
id: @experiment_id,
|
28
|
+
variationId: @variation_id,
|
29
|
+
nonce: @nonce
|
30
|
+
}
|
31
|
+
UriHelper.encode_query(params)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'em-synchrony/em-http'
|
4
|
+
require 'net/http'
|
5
|
+
require 'kameleoon/version'
|
6
|
+
require 'kameleoon/network/response'
|
7
|
+
require 'kameleoon/exceptions'
|
8
|
+
|
9
|
+
module Kameleoon
|
10
|
+
module Network
|
11
|
+
class NetProvider
|
12
|
+
def make_request(_request)
|
13
|
+
raise KameleoonError, 'Call of not implemented method!'
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def collect_headers(request)
|
19
|
+
headers = { 'Content-Type': request.content_type }
|
20
|
+
headers['User-Agent'] = request.user_agent unless request.user_agent.nil?
|
21
|
+
headers
|
22
|
+
end
|
23
|
+
|
24
|
+
def unknown_method_response(method, request)
|
25
|
+
Response.new("Unknown request method '#{method}'", nil, nil, request)
|
26
|
+
end
|
27
|
+
end
|
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
|
+
class SyncNetProvider < NetProvider
|
64
|
+
def make_request(request)
|
65
|
+
resp = nil
|
66
|
+
begin
|
67
|
+
case request.method
|
68
|
+
when Method::GET
|
69
|
+
req = Net::HTTP::Get.new(request.url)
|
70
|
+
when Method::POST
|
71
|
+
req = Net::HTTP::Post.new(request.url)
|
72
|
+
req.body = request.data
|
73
|
+
else
|
74
|
+
return unknown_method_response(request.method, request)
|
75
|
+
end
|
76
|
+
timeout = request.timeout.to_f / 1000.0
|
77
|
+
headers = collect_headers(request)
|
78
|
+
headers.each { |k, v| req[k] = v }
|
79
|
+
uri = URI(request.url)
|
80
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: true, open_timeout: timeout,
|
81
|
+
read_timeout: timeout, ssl_timeout: timeout) do |http|
|
82
|
+
resp = http.request(req)
|
83
|
+
end
|
84
|
+
rescue => e
|
85
|
+
return Response.new(e, nil, nil, request)
|
86
|
+
end
|
87
|
+
Response.new(nil, resp.code.to_i, resp.body, request)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'em-synchrony'
|
4
|
+
require 'kameleoon/network/content_type'
|
5
|
+
require 'kameleoon/network/method'
|
6
|
+
require 'kameleoon/network/request'
|
7
|
+
require 'kameleoon/network/net_provider'
|
8
|
+
|
9
|
+
module Kameleoon
|
10
|
+
module Network
|
11
|
+
##
|
12
|
+
# NetworkManager is used to make API calls.
|
13
|
+
class NetworkManager
|
14
|
+
FETCH_CONFIGURATION_ATTEMPT_NUMBER = 4
|
15
|
+
TRACKING_CALL_ATTEMPT_NUMBER = 4
|
16
|
+
TRACKING_CALL_RETRY_DELAY = 5.0 # in seconds
|
17
|
+
|
18
|
+
attr_reader :environment, :default_timeout, :url_provider
|
19
|
+
|
20
|
+
def initialize(environment, default_timeout, url_provider, log_func = nil)
|
21
|
+
@environment = environment
|
22
|
+
@default_timeout = default_timeout
|
23
|
+
@url_provider = url_provider
|
24
|
+
@em_net_provider = EMNetProvider.new
|
25
|
+
@sync_net_provider = SyncNetProvider.new
|
26
|
+
@log_func = log_func
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_configuration(timestamp = nil, timeout = nil)
|
30
|
+
url = @url_provider.make_configuration_url(@environment, timestamp)
|
31
|
+
timeout = ensure_timeout(timeout)
|
32
|
+
request = Request.new(Method::GET, url, ContentType::JSON, timeout)
|
33
|
+
attempts_left = FETCH_CONFIGURATION_ATTEMPT_NUMBER
|
34
|
+
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
|
+
result = handle_response(response)
|
38
|
+
return result if result
|
39
|
+
|
40
|
+
attempts_left -= 1
|
41
|
+
end
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_remote_data(key, timeout = nil)
|
46
|
+
url = @url_provider.make_api_data_get_request_url(key)
|
47
|
+
timeout = ensure_timeout(timeout)
|
48
|
+
request = Request.new(Method::GET, url, ContentType::JSON, timeout)
|
49
|
+
response = @sync_net_provider.make_request(request)
|
50
|
+
handle_response(response)
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_remote_visitor_data(visitor_code, timeout = nil)
|
54
|
+
url = @url_provider.make_visitor_data_get_url(visitor_code)
|
55
|
+
timeout = ensure_timeout(timeout)
|
56
|
+
request = Request.new(Method::GET, url, ContentType::JSON, timeout)
|
57
|
+
response = @sync_net_provider.make_request(request)
|
58
|
+
handle_response(response)
|
59
|
+
end
|
60
|
+
|
61
|
+
def send_tracking_data(visitor_code, lines, user_agent, timeout = nil)
|
62
|
+
return if lines.nil? || lines.empty?
|
63
|
+
|
64
|
+
url = @url_provider.make_tracking_url(visitor_code)
|
65
|
+
timeout = ensure_timeout(timeout)
|
66
|
+
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
|
+
Thread.new do
|
69
|
+
attempts_left = TRACKING_CALL_ATTEMPT_NUMBER
|
70
|
+
loop do
|
71
|
+
response = @sync_net_provider.make_request(request)
|
72
|
+
if handle_response(response) != false
|
73
|
+
lines.each { |line| line.sent = true }
|
74
|
+
break
|
75
|
+
end
|
76
|
+
attempts_left -= 1
|
77
|
+
break unless attempts_left.positive?
|
78
|
+
|
79
|
+
delay(TRACKING_CALL_RETRY_DELAY)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def log_failure(request, message)
|
87
|
+
return if @log_func.nil?
|
88
|
+
|
89
|
+
premsg = "#{request.method} call '#{request.url}' "
|
90
|
+
premsg += request.data.nil? ? 'failed' : "(data '#{request.data}') failed"
|
91
|
+
@log_func.call("#{premsg}: #{message}")
|
92
|
+
end
|
93
|
+
|
94
|
+
def delay(period)
|
95
|
+
sleep(period)
|
96
|
+
end
|
97
|
+
|
98
|
+
def ensure_timeout(timeout)
|
99
|
+
timeout.nil? ? @default_timeout : timeout
|
100
|
+
end
|
101
|
+
|
102
|
+
def handle_response(response)
|
103
|
+
if !response.error.nil?
|
104
|
+
log_failure(response.request, "Error occurred during request: #{response.error}")
|
105
|
+
elsif response.code / 100 != 2
|
106
|
+
log_failure(response.request, "Received unexpected status code '#{response.code}'")
|
107
|
+
else
|
108
|
+
return response.body
|
109
|
+
end
|
110
|
+
false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
module Network
|
5
|
+
##
|
6
|
+
# Request represents HTTP request.
|
7
|
+
class Request
|
8
|
+
attr_reader :method, :url, :content_type, :timeout, :user_agent, :data
|
9
|
+
|
10
|
+
def initialize(method, url, content_type, timeout, user_agent = nil, data = nil)
|
11
|
+
@method = method
|
12
|
+
@url = url
|
13
|
+
@content_type = content_type
|
14
|
+
@timeout = timeout
|
15
|
+
@user_agent = user_agent
|
16
|
+
@data = !data.nil? && data.is_a?(String) ? data.encode('UTF-8') : data
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kameleoon
|
4
|
+
module Network
|
5
|
+
##
|
6
|
+
# Response represents HTTP response.
|
7
|
+
class Response
|
8
|
+
attr_reader :error, :code, :body, :request
|
9
|
+
|
10
|
+
def initialize(error, code, body, request)
|
11
|
+
@error = error
|
12
|
+
@code = code
|
13
|
+
@body = body
|
14
|
+
@request = request
|
15
|
+
end
|
16
|
+
|
17
|
+
def success?
|
18
|
+
@error.nil? && (@code / 100 == 2)
|
19
|
+
end
|
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
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
module Network
|
8
|
+
##
|
9
|
+
# UriHelper contains functions which helps working with URIs.
|
10
|
+
module UriHelper
|
11
|
+
def self.encode_uri(uri)
|
12
|
+
encoded = CGI.escape(uri)
|
13
|
+
encoded.gsub!(/%21|%27|%28|%29|%2A|\+/,
|
14
|
+
'%21' => '!',
|
15
|
+
'%27' => "'",
|
16
|
+
'%28' => '(',
|
17
|
+
'%29' => ')',
|
18
|
+
'%2A' => '*',
|
19
|
+
'+' => '%20')
|
20
|
+
encoded
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.encode_query(params)
|
24
|
+
params.delete_if { |_k, v| v.nil? || (v == '') }
|
25
|
+
encoded = URI.encode_www_form(params)
|
26
|
+
encoded.gsub!(/%21|%27|%28|%29|%7E|\+/,
|
27
|
+
'%21' => '!',
|
28
|
+
'%27' => "'",
|
29
|
+
'%28' => '(',
|
30
|
+
'%29' => ')',
|
31
|
+
'%7E' => '~',
|
32
|
+
'+' => '%20')
|
33
|
+
encoded
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kameleoon/version'
|
4
|
+
require 'kameleoon/network/uri_helper'
|
5
|
+
|
6
|
+
module Kameleoon
|
7
|
+
module Network
|
8
|
+
##
|
9
|
+
# UrlProvider is used as a source of URLs for network calls.
|
10
|
+
class UrlProvider
|
11
|
+
TRACKING_PATH = '/visit/events'
|
12
|
+
VISITOR_DATA_PATH = '/visit/visitor'
|
13
|
+
GET_DATA_PATH = '/map/map'
|
14
|
+
POST_DATA_PATH = '/map/maps'
|
15
|
+
CONFIGURATION_API_URL = 'https://client-config.kameleoon.com/mobile'
|
16
|
+
RT_CONFIGURATION_URL = 'https://events.kameleoon.com:8110/sse'
|
17
|
+
|
18
|
+
DEFAULT_DATA_API_URL = 'https://data.kameleoon.io'
|
19
|
+
TEST_DATA_API_URL = 'https://data.kameleoon.net'
|
20
|
+
|
21
|
+
attr_reader :site_code, :data_api_url
|
22
|
+
|
23
|
+
def initialize(site_code, data_api_url)
|
24
|
+
@site_code = site_code
|
25
|
+
@data_api_url = data_api_url
|
26
|
+
end
|
27
|
+
|
28
|
+
def make_tracking_url(visitor_code)
|
29
|
+
params = {
|
30
|
+
sdkName: SDK_NAME,
|
31
|
+
sdkVersion: SDK_VERSION,
|
32
|
+
siteCode: @site_code,
|
33
|
+
visitorCode: visitor_code
|
34
|
+
}
|
35
|
+
"#{@data_api_url}#{TRACKING_PATH}?#{UriHelper.encode_query(params)}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def make_visitor_data_get_url(visitor_code)
|
39
|
+
params = {
|
40
|
+
siteCode: @site_code,
|
41
|
+
visitorCode: visitor_code,
|
42
|
+
currentVisit: true,
|
43
|
+
maxNumberPreviousVisits: 1,
|
44
|
+
customData: true,
|
45
|
+
version: 0
|
46
|
+
}
|
47
|
+
"#{@data_api_url}#{VISITOR_DATA_PATH}?#{UriHelper.encode_query(params)}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def make_api_data_get_request_url(key)
|
51
|
+
params = {
|
52
|
+
siteCode: @site_code,
|
53
|
+
key: key
|
54
|
+
}
|
55
|
+
"#{@data_api_url}#{GET_DATA_PATH}?#{UriHelper.encode_query(params)}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def make_configuration_url(environment = nil, timestamp = nil)
|
59
|
+
params = { siteCode: @site_code }
|
60
|
+
params[:environment] = environment unless environment.nil?
|
61
|
+
params[:ts] = timestamp unless timestamp.nil?
|
62
|
+
"#{CONFIGURATION_API_URL}?#{UriHelper.encode_query(params)}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def make_real_time_url
|
66
|
+
params = { siteCode: @site_code }
|
67
|
+
"#{RT_CONFIGURATION_URL}?#{UriHelper.encode_query(params)}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -1,28 +1,57 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'kameleoon/exceptions'
|
2
3
|
|
3
4
|
module Kameleoon
|
4
5
|
# @api private
|
5
6
|
module Targeting
|
7
|
+
module ConditionType
|
8
|
+
CUSTOM_DATUM = 'CUSTOM_DATUM'
|
9
|
+
TARGET_EXPERIMENT = 'TARGET_EXPERIMENT'
|
10
|
+
EXCLUSIVE_EXPERIMENT = 'EXCLUSIVE_EXPERIMENT'
|
11
|
+
PAGE_URL = 'PAGE_URL'
|
12
|
+
PAGE_TITLE = 'PAGE_TITLE'
|
13
|
+
VISITOR_CODE = 'VISITOR_CODE'
|
14
|
+
DEVICE_TYPE = 'DEVICE_TYPE'
|
15
|
+
BROWSER = 'BROWSER'
|
16
|
+
SDK_LANGUAGE = 'SDK_LANGUAGE'
|
17
|
+
CONVERSIONS = 'CONVERSIONS'
|
18
|
+
end
|
19
|
+
|
20
|
+
module Operator
|
21
|
+
UNDEFINED = 'UNDEFINED'
|
22
|
+
CONTAINS = 'CONTAINS'
|
23
|
+
EXACT = 'EXACT'
|
24
|
+
REGULAR_EXPRESSION = 'REGULAR_EXPRESSION'
|
25
|
+
LOWER = 'LOWER'
|
26
|
+
EQUAL = 'EQUAL'
|
27
|
+
GREATER = 'GREATER'
|
28
|
+
IS_TRUE = 'TRUE'
|
29
|
+
IS_FALSE = 'FALSE'
|
30
|
+
AMONG_VALUES = 'AMONG_VALUES'
|
31
|
+
ANY = 'ANY'
|
32
|
+
UNKNOWN = 'UNKNOWN'
|
33
|
+
end
|
34
|
+
|
35
|
+
# Base class for all targeting conditions
|
6
36
|
class Condition
|
7
|
-
|
37
|
+
attr_reader :type, :include
|
8
38
|
|
9
39
|
def initialize(json_condition)
|
10
|
-
if json_condition['targetingType'].nil?
|
11
|
-
raise Exception::NotFound.new('targetingType'), 'targetingType missed'
|
12
|
-
end
|
40
|
+
raise Exception::NotFound.new('targetingType'), 'targetingType missed' if json_condition['targetingType'].nil?
|
13
41
|
|
14
42
|
@type = json_condition['targetingType']
|
15
|
-
|
16
|
-
if json_condition['include'].nil? && json_condition['isInclude'].nil?
|
17
|
-
raise Exception::NotFound.new('include / isInclude missed'), 'include / isInclude missed'
|
18
|
-
end
|
19
|
-
|
20
|
-
@include = json_condition['include'] || json_condition['isInclude']
|
43
|
+
@include = json_condition['isInclude'].nil? ? true : json_condition['isInclude']
|
21
44
|
end
|
22
45
|
|
23
|
-
def check(
|
46
|
+
def check(_data)
|
24
47
|
raise 'Abstract method `check` call'
|
25
48
|
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def get_last_targeting_data(list_data, data_type)
|
53
|
+
list_data.select { |data| data.instance == data_type }.last
|
54
|
+
end
|
26
55
|
end
|
27
56
|
end
|
28
57
|
end
|
@@ -1,22 +1,45 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'conditions/custom_datum'
|
2
|
+
require_relative 'conditions/target_experiment'
|
3
|
+
require_relative 'conditions/exclusive_experiment'
|
4
|
+
require_relative 'conditions/page_title_condition'
|
5
|
+
require_relative 'conditions/page_url_condition'
|
6
|
+
require_relative 'conditions/visitor_code_condition'
|
7
|
+
require_relative 'conditions/device_condition'
|
8
|
+
require_relative 'conditions/conversion_condition'
|
9
|
+
require_relative 'conditions/browser_condition'
|
10
|
+
require_relative 'conditions/sdk_language_condition'
|
11
|
+
require_relative 'conditions/unknown_condition'
|
4
12
|
|
5
13
|
module Kameleoon
|
6
|
-
|
14
|
+
# @api private
|
7
15
|
module Targeting
|
16
|
+
# Module for create different targeting conditions
|
8
17
|
module ConditionFactory
|
9
18
|
def get_condition(condition_json)
|
10
|
-
condition = nil
|
11
19
|
case condition_json['targetingType']
|
12
|
-
when ConditionType::CUSTOM_DATUM
|
13
|
-
|
14
|
-
when ConditionType::TARGET_EXPERIMENT
|
15
|
-
|
16
|
-
when ConditionType::EXCLUSIVE_EXPERIMENT
|
17
|
-
|
20
|
+
when ConditionType::CUSTOM_DATUM
|
21
|
+
CustomDatum.new(condition_json)
|
22
|
+
when ConditionType::TARGET_EXPERIMENT
|
23
|
+
TargetExperiment.new(condition_json)
|
24
|
+
when ConditionType::EXCLUSIVE_EXPERIMENT
|
25
|
+
ExclusiveExperiment.new(condition_json)
|
26
|
+
when ConditionType::PAGE_URL
|
27
|
+
PageUrlCondition.new(condition_json)
|
28
|
+
when ConditionType::PAGE_TITLE
|
29
|
+
PageTitleCondition.new(condition_json)
|
30
|
+
when ConditionType::VISITOR_CODE
|
31
|
+
VisitorCodeCondition.new(condition_json)
|
32
|
+
when ConditionType::DEVICE_TYPE
|
33
|
+
DeviceCondition.new(condition_json)
|
34
|
+
when ConditionType::CONVERSIONS
|
35
|
+
ConversionCondition.new(condition_json)
|
36
|
+
when ConditionType::BROWSER
|
37
|
+
BrowserCondition.new(condition_json)
|
38
|
+
when ConditionType::SDK_LANGUAGE
|
39
|
+
SdkLanguageCondition.new(condition_json)
|
40
|
+
else
|
41
|
+
UnknownCondition.new(condition_json)
|
18
42
|
end
|
19
|
-
condition
|
20
43
|
end
|
21
44
|
end
|
22
45
|
end
|