kameleoon-client-ruby 1.1.2 → 2.0.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.
@@ -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