kameleoon-client-ruby 1.1.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,23 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kameleoon
2
- #@api private
4
+ # @api private
3
5
  module Targeting
4
6
  class Condition
5
7
  attr_accessor :type, :include
6
8
 
7
- def initialize(json_conditions)
8
- raise "Abstract class cannot be instantiate"
9
+ def initialize(json_condition)
10
+ if json_condition['targetingType'].nil?
11
+ raise Exception::NotFoundError.new('targetingType'), 'targetingType missed'
12
+ end
13
+
14
+ @type = json_condition['targetingType']
15
+
16
+ if json_condition['include'].nil? && json_condition['isInclude'].nil?
17
+ raise Exception::NotFoundError.new('include / isInclude missed'), 'include / isInclude missed'
18
+ end
19
+
20
+ @include = json_condition['include'] || json_condition['isInclude']
9
21
  end
10
22
 
11
23
  def check(conditions)
@@ -1,4 +1,6 @@
1
1
  require 'kameleoon/targeting/conditions/custom_datum'
2
+ require 'kameleoon/targeting/conditions/target_experiment'
3
+ require 'kameleoon/targeting/conditions/exclusive_experiment'
2
4
 
3
5
  module Kameleoon
4
6
  #@api private
@@ -6,11 +8,16 @@ module Kameleoon
6
8
  module ConditionFactory
7
9
  def get_condition(condition_json)
8
10
  condition = nil
9
- if condition_json['targetingType'] == ConditionType::CUSTOM_DATUM.to_s
11
+ case condition_json['targetingType']
12
+ when ConditionType::CUSTOM_DATUM.to_s
10
13
  condition = CustomDatum.new(condition_json)
14
+ when ConditionType::TARGET_EXPERIMENT.to_s
15
+ condition = TargetExperiment.new(condition_json)
16
+ when ConditionType::EXCLUSIVE_EXPERIMENT.to_s
17
+ condition = ExclusiveExperiment.new(condition_json)
11
18
  end
12
19
  condition
13
20
  end
14
21
  end
15
22
  end
16
- end
23
+ end
@@ -1,34 +1,32 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'kameleoon/targeting/condition'
2
4
  require 'kameleoon/exceptions'
3
5
 
4
6
  module Kameleoon
5
- #@api private
6
7
  module Targeting
8
+ # CustomDatum represents an instance of Custom Data condition from back office
7
9
  class CustomDatum < Condition
8
10
  include Kameleoon::Exception
9
11
 
10
- attr_accessor :index, :operator, :value
11
12
  def initialize(json_condition)
12
- if json_condition['customDataIndex'].nil?
13
- raise Exception::NotFoundError.new('customDataIndex')
14
- end
13
+ super(json_condition)
15
14
  @index = json_condition['customDataIndex']
16
15
 
17
16
  if json_condition['valueMatchType'].nil?
18
- raise Exception::NotFoundError.new('valueMatchType')
17
+ raise Exception::NotFoundError.new('valueMatchType'), 'valueMatchType missed'
19
18
  end
19
+
20
20
  @operator = json_condition['valueMatchType']
21
21
 
22
- # if json_condition['value'].nil?
23
- # raise Exception::NotFoundError.new('value')
24
- # end
25
22
  @value = json_condition['value']
26
23
 
27
24
  @type = ConditionType::CUSTOM_DATUM
28
25
 
29
26
  if json_condition['include'].nil? && json_condition['isInclude'].nil?
30
- raise Exception::NotFoundError.new('include / isInclude missed')
27
+ raise Exception::NotFoundError.new('include / isInclude missed'), 'include / isInclude missed'
31
28
  end
29
+
32
30
  @include = json_condition['include'] || json_condition['isInclude']
33
31
  end
34
32
 
@@ -40,43 +38,29 @@ module Kameleoon
40
38
  else
41
39
  case @operator
42
40
  when Operator::MATCH.to_s
43
- if Regexp.new(@value.to_s).match(custom_data.value.to_s)
44
- is_targeted = true
45
- end
41
+ is_targeted = !Regexp.new(@value.to_s).match(custom_data.value.to_s).nil?
46
42
  when Operator::CONTAINS.to_s
47
- if custom_data.value.to_s.include? @value
48
- is_targeted = true
49
- end
43
+ is_targeted = custom_data.value.to_s.include? @value
50
44
  when Operator::EXACT.to_s
51
- if custom_data.value.to_s == @value.to_s
52
- is_targeted = true
53
- end
45
+ is_targeted = custom_data.value.to_s == @value.to_s
54
46
  when Operator::EQUAL.to_s
55
- if custom_data.value.to_f == @value.to_f
56
- is_targeted = true
57
- end
47
+ is_targeted = custom_data.value.to_f == @value.to_f
58
48
  when Operator::GREATER.to_s
59
- if custom_data.value.to_f > @value.to_f
60
- is_targeted = true
61
- end
49
+ is_targeted = custom_data.value.to_f > @value.to_f
62
50
  when Operator::LOWER.to_s
63
- if custom_data.value.to_f < @value.to_f
64
- is_targeted = true
65
- end
51
+ is_targeted = custom_data.value.to_f < @value.to_f
66
52
  when Operator::IS_TRUE.to_s
67
- if custom_data.value == 'true'
68
- is_targeted = true
69
- end
53
+ is_targeted = custom_data.value == 'true'
70
54
  when Operator::IS_FALSE.to_s
71
- if custom_data.value == 'false'
72
- is_targeted = true
73
- end
55
+ is_targeted = custom_data.value == 'false'
56
+ when Operator::AMONG_VALUES.to_s
57
+ is_targeted = @value.scan(/"([^"]*)"/).flatten.include?(custom_data.value)
74
58
  else
75
- raise KameleoonError.new("Undefined operator " + @operator.to_s)
59
+ raise KameleoonError.new("Undefined operator #{@operator}"), "Undefined operator #{@operator}"
76
60
  end
77
61
  end
78
62
  is_targeted
79
63
  end
80
64
  end
81
65
  end
82
- end
66
+ end
@@ -0,0 +1,29 @@
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
+ # ExclusiveExperiment represents an instance of Exclusive Experiment condition in user account
10
+ class ExclusiveExperiment < Condition
11
+ include Kameleoon::Exception
12
+
13
+ def initialize(json_condition)
14
+ if json_condition['targetingType'].nil?
15
+ raise Exception::NotFoundError.new('targetingType'), 'targetingType missed'
16
+ end
17
+
18
+ @type = json_condition['targetingType']
19
+ @include = true
20
+ end
21
+
22
+ def check(data)
23
+ experiment_id = data.experiment_id
24
+ storage = data.storage
25
+ storage.nil? || storage.empty? || (storage.length == 1 && !storage[experiment_id].nil?)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,44 @@
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
+ if json_condition['experiment'].nil?
17
+ raise Exception::NotFoundError.new('experiment'), 'experiment missed'
18
+ end
19
+
20
+ @experiment = json_condition['experiment']
21
+
22
+ if json_condition['variationMatchType'].nil?
23
+ raise Exception::NotFoundError.new('variationMatchType'), 'variationMatchType missed'
24
+ end
25
+
26
+ @operator = json_condition['variationMatchType']
27
+ @variation = json_condition['variation']
28
+ end
29
+
30
+ def check(variation_storage)
31
+ is_targeted = false
32
+ variation_storage_exist = !variation_storage.nil? && !variation_storage.empty?
33
+ saved_variation = variation_storage[@experiment] unless variation_storage.nil?
34
+ case @operator
35
+ when Operator::EXACT.to_s
36
+ is_targeted = variation_storage_exist && saved_variation == @variation
37
+ when Operator::ANY.to_s
38
+ is_targeted = variation_storage_exist
39
+ end
40
+ is_targeted
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,15 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'kameleoon/targeting/tree_builder'
2
4
  require 'kameleoon/exceptions'
3
5
 
4
6
  module Kameleoon
5
- #@api private
7
+ # @api private
6
8
  module Targeting
7
9
  class Segment
8
10
  include TreeBuilder
9
11
  attr_accessor :id, :tree
10
12
  def to_s
11
- print("\nSegment id: " + @id.to_s)
12
- print("\n")
13
+ print("\nSegment id: #{@id}\n")
13
14
  @tree.to_s
14
15
  end
15
16
 
@@ -18,16 +19,16 @@ module Kameleoon
18
19
  if args.length == 1
19
20
  hash = args.first
20
21
  if hash.nil?
21
- raise Kameleoon::Exception::NotFound.new("arguments for segment")
22
+ raise Kameleoon::Exception::NotFound.new('arguments for segment'), 'arguments for segment'
22
23
  end
23
- if hash["id"].nil?
24
- raise Kameleoon::Exception::NotFound.new("id")
24
+ if hash['id'].nil?
25
+ raise Kameleoon::Exception::NotFound.new('id'), 'id'
25
26
  end
26
- @id = hash["id"].to_i
27
- if hash["conditionsData"].nil?
28
- raise Kameleoon::Exception::NotFound.new(hash["conditionsData"])
27
+ @id = hash['id'].to_i
28
+ if hash['conditionsData'].nil?
29
+ raise Kameleoon::Exception::NotFound.new(hash['conditionsData']), 'hash[\'conditionsData\']'
29
30
  end
30
- @tree = create_tree(hash["conditionsData"])
31
+ @tree = create_tree(hash['conditionsData'])
31
32
  elsif args.length == 2
32
33
  @id = args[0]
33
34
  @tree = args[1]
@@ -49,17 +50,14 @@ module Kameleoon
49
50
  attr_accessor :or_operator, :left_child, :right_child, :condition
50
51
 
51
52
  def to_s
52
- print("or_operator: " + @or_operator.to_s)
53
- print("\n")
54
- print("condition: " + @condition.to_s)
53
+ print("or_operator: #{@or_operator}\n")
54
+ print("condition: #{@condition}")
55
55
  unless @left_child.nil?
56
- print("\n")
57
- print("Left child:\n ")
56
+ print('\nLeft child:\n ')
58
57
  @left_child.to_s
59
58
  end
60
59
  unless @right_child.nil?
61
- print("\n")
62
- print("right child:\n ")
60
+ print('\nright child:\n ')
63
61
  @right_child.to_s
64
62
  end
65
63
  end
@@ -125,37 +123,39 @@ module Kameleoon
125
123
  if condition.nil?
126
124
  is_targeted = true
127
125
  else
128
- is_targeted = condition.check(datas)
126
+ is_targeted = condition.check(datas.call(condition.type))
129
127
  unless condition.include
130
- if is_targeted.nil?
131
- is_targeted = true
132
- else
133
- is_targeted = !is_targeted
134
- end
128
+ return true if is_targeted.nil?
129
+
130
+ is_targeted = !is_targeted
135
131
  end
136
132
  end
137
- Marshal.load(Marshal.dump(is_targeted)) #Deep copy
133
+ Marshal.load(Marshal.dump(is_targeted)) # Deep copy
138
134
  end
139
135
  end
140
136
 
141
137
  module DataType
142
- CUSTOM = "CUSTOM"
138
+ CUSTOM = 'CUSTOM'
143
139
  end
144
140
 
145
141
  module ConditionType
146
- CUSTOM_DATUM = "CUSTOM_DATUM"
142
+ CUSTOM_DATUM = 'CUSTOM_DATUM'
143
+ TARGET_EXPERIMENT = 'TARGET_EXPERIMENT'
144
+ EXCLUSIVE_EXPERIMENT = 'EXCLUSIVE_EXPERIMENT'
147
145
  end
148
146
 
149
147
  module Operator
150
- UNDEFINED = "UNDEFINED"
151
- CONTAINS = "CONTAINS"
152
- EXACT = "EXACT"
153
- MATCH = "REGULAR_EXPRESSION"
154
- LOWER = "LOWER"
155
- EQUAL = "EQUAL"
156
- GREATER = "GREATER"
157
- IS_TRUE = "TRUE"
158
- IS_FALSE = "FALSE"
148
+ UNDEFINED = 'UNDEFINED'
149
+ CONTAINS = 'CONTAINS'
150
+ EXACT = 'EXACT'
151
+ MATCH = 'REGULAR_EXPRESSION'
152
+ LOWER = 'LOWER'
153
+ EQUAL = 'EQUAL'
154
+ GREATER = 'GREATER'
155
+ IS_TRUE = 'TRUE'
156
+ IS_FALSE = 'FALSE'
157
+ AMONG_VALUES = 'AMONG_VALUES'
158
+ ANY = 'ANY'
159
159
  end
160
160
  end
161
- end
161
+ end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kameleoon
4
+ # Utils is a helper module for project
2
5
  module Utils
3
6
  ALPHA_NUMERIC_CHARS = 'abcdef0123456789'
4
7
 
@@ -10,4 +13,4 @@ module Kameleoon
10
13
  (1..length).map { ALPHA_NUMERIC_CHARS[rand(ALPHA_NUMERIC_CHARS.length)] }.join
11
14
  end
12
15
  end
13
- end
16
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kameleoon
2
- VERSION = '1.1.2'
3
- end
4
+ VERSION = '2.0.0'
5
+ end
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: 1.1.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kameleoon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-08 00:00:00.000000000 Z
11
+ date: 2023-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: em-http-request
@@ -62,15 +62,25 @@ files:
62
62
  - README.md
63
63
  - lib/kameleoon.rb
64
64
  - lib/kameleoon/client.rb
65
+ - lib/kameleoon/configuration/experiment.rb
66
+ - lib/kameleoon/configuration/feature_flag.rb
67
+ - lib/kameleoon/configuration/feature_flag_v2.rb
68
+ - lib/kameleoon/configuration/rule.rb
69
+ - lib/kameleoon/configuration/variable.rb
70
+ - lib/kameleoon/configuration/variation.rb
71
+ - lib/kameleoon/configuration/variation_exposition.rb
65
72
  - lib/kameleoon/cookie.rb
66
73
  - lib/kameleoon/data.rb
67
74
  - lib/kameleoon/exceptions.rb
68
75
  - lib/kameleoon/factory.rb
69
- - lib/kameleoon/query_graphql.rb
70
76
  - lib/kameleoon/request.rb
77
+ - lib/kameleoon/storage/variation_storage.rb
78
+ - lib/kameleoon/storage/visitor_variation.rb
71
79
  - lib/kameleoon/targeting/condition.rb
72
80
  - lib/kameleoon/targeting/condition_factory.rb
73
81
  - lib/kameleoon/targeting/conditions/custom_datum.rb
82
+ - lib/kameleoon/targeting/conditions/exclusive_experiment.rb
83
+ - lib/kameleoon/targeting/conditions/target_experiment.rb
74
84
  - lib/kameleoon/targeting/models.rb
75
85
  - lib/kameleoon/targeting/tree_builder.rb
76
86
  - lib/kameleoon/utils.rb
@@ -1,76 +0,0 @@
1
- module Kameleoon
2
- module Query
3
-
4
- def self.query_experiments(site_code)
5
- '{
6
- "operationName": "getExperiments",
7
- "query": "query getExperiments($first: Int, $after: String, $filter: FilteringExpression, $sort: [SortingParameter!]) { experiments(first: $first, after: $after, filter: $filter, sort: $sort) { edges { node { id name type site { id code isKameleoonEnabled } status variations { id customJson } deviations { variationId value } respoolTime {variationId value } segment { id name conditionsData { firstLevelOrOperators firstLevel { orOperators conditions { targetingType isInclude ... on CustomDataTargetingCondition { customDataIndex value valueMatchType } } } } } __typename } __typename } pageInfo { endCursor hasNextPage __typename } totalCount __typename } }",
8
- "variables": {
9
- "filter": {
10
- "and": [{
11
- "condition": {
12
- "field": "status",
13
- "operator": "IN",
14
- "parameters": ["ACTIVE", "DEVIATED", "USED_AS_PERSONALIZATION"]
15
- }
16
- },
17
- {
18
- "condition": {
19
- "field": "type",
20
- "operator": "IN",
21
- "parameters": ["SERVER_SIDE", "HYBRID"]
22
- }
23
- },
24
- {
25
- "condition": {
26
- "field": "siteCode",
27
- "operator": "IN",
28
- "parameters": ["' + site_code + '"]
29
- }
30
- }]
31
- },
32
- "sort": [{
33
- "field": "id",
34
- "direction": "ASC"
35
- }]
36
- }
37
- }'
38
- end
39
-
40
- def self.query_feature_flags(site_code, environment)
41
- '{
42
- "operationName": "getFeatureFlags",
43
- "query": "query getFeatureFlags($first: Int, $after: String, $filter: FilteringExpression, $sort: [SortingParameter!]) { featureFlags(first: $first, after: $after, filter: $filter, sort: $sort) { edges { node { id name site { id code isKameleoonEnabled } bypassDeviation status variations { id customJson } respoolTime { variationId value } expositionRate identificationKey featureFlagSdkLanguageType featureStatus schedules { dateStart dateEnd } segment { id name conditionsData { firstLevelOrOperators firstLevel { orOperators conditions { targetingType isInclude ... on CustomDataTargetingCondition { customDataIndex value valueMatchType } } } } } __typename } __typename } pageInfo { endCursor hasNextPage __typename } totalCount __typename } }",
44
- "variables": {
45
- "filter": {
46
- "and": [{
47
- "condition": {
48
- "field": "featureStatus",
49
- "operator": "IN",
50
- "parameters": ["ACTIVATED", "SCHEDULED", "DEACTIVATED"]
51
- }
52
- },
53
- {
54
- "condition": {
55
- "field": "siteCode",
56
- "operator": "IN",
57
- "parameters": ["' + site_code + '"]
58
- }
59
- },
60
- {
61
- "condition": {
62
- "field": "environment.key",
63
- "operator": "IN",
64
- "parameters": ["' + environment + '"]
65
- }
66
- }]
67
- },
68
- "sort": [{
69
- "field": "id",
70
- "direction": "ASC"
71
- }]
72
- }
73
- }'
74
- end
75
- end
76
- end