hackle-ruby-sdk 0.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hackle/client.rb +191 -79
  3. data/lib/hackle/config.rb +59 -17
  4. data/lib/hackle/decision.rb +113 -0
  5. data/lib/hackle/event.rb +89 -0
  6. data/lib/hackle/internal/clock/clock.rb +47 -0
  7. data/lib/hackle/internal/concurrent/executors.rb +20 -0
  8. data/lib/hackle/internal/concurrent/schedule/scheduler.rb +12 -0
  9. data/lib/hackle/internal/concurrent/schedule/timer_scheduler.rb +30 -0
  10. data/lib/hackle/internal/config/parameter_config.rb +50 -0
  11. data/lib/hackle/internal/core/hackle_core.rb +182 -0
  12. data/lib/hackle/internal/evaluation/bucketer/bucketer.rb +46 -0
  13. data/lib/hackle/internal/evaluation/evaluator/contextual/contextual_evaluator.rb +29 -0
  14. data/lib/hackle/internal/evaluation/evaluator/delegating/delegating_evaluator.rb +26 -0
  15. data/lib/hackle/internal/evaluation/evaluator/evaluator.rb +117 -0
  16. data/lib/hackle/internal/evaluation/evaluator/experiment/experiment_evaluation_flow_factory.rb +67 -0
  17. data/lib/hackle/internal/evaluation/evaluator/experiment/experiment_evaluator.rb +172 -0
  18. data/lib/hackle/internal/evaluation/evaluator/experiment/experiment_flow_evaluator.rb +241 -0
  19. data/lib/hackle/internal/evaluation/evaluator/experiment/experiment_resolver.rb +166 -0
  20. data/lib/hackle/internal/evaluation/evaluator/remoteconfig/remote_config_determiner.rb +48 -0
  21. data/lib/hackle/internal/evaluation/evaluator/remoteconfig/remote_config_evaluator.rb +174 -0
  22. data/lib/hackle/internal/evaluation/flow/evaluation_flow.rb +49 -0
  23. data/lib/hackle/internal/evaluation/flow/flow_evaluator.rb +11 -0
  24. data/lib/hackle/internal/evaluation/match/condition/condition_matcher.rb +11 -0
  25. data/lib/hackle/internal/evaluation/match/condition/condition_matcher_factory.rb +53 -0
  26. data/lib/hackle/internal/evaluation/match/condition/experiment/experiment_condition_matcher.rb +29 -0
  27. data/lib/hackle/internal/evaluation/match/condition/experiment/experiment_evaluator_matcher.rb +135 -0
  28. data/lib/hackle/internal/evaluation/match/condition/segment/segment_condition_matcher.rb +67 -0
  29. data/lib/hackle/internal/evaluation/match/condition/user/user_condition_matcher.rb +44 -0
  30. data/lib/hackle/internal/evaluation/match/operator/operator_matcher.rb +185 -0
  31. data/lib/hackle/internal/evaluation/match/operator/operator_matcher_factory.rb +31 -0
  32. data/lib/hackle/internal/evaluation/match/target/target_matcher.rb +31 -0
  33. data/lib/hackle/internal/evaluation/match/value/value_matcher.rb +96 -0
  34. data/lib/hackle/internal/evaluation/match/value/value_matcher_factory.rb +28 -0
  35. data/lib/hackle/internal/evaluation/match/value/value_operator_matcher.rb +59 -0
  36. data/lib/hackle/internal/event/user_event.rb +187 -0
  37. data/lib/hackle/internal/event/user_event_dispatcher.rb +156 -0
  38. data/lib/hackle/internal/event/user_event_factory.rb +58 -0
  39. data/lib/hackle/internal/event/user_event_processor.rb +181 -0
  40. data/lib/hackle/internal/http/http.rb +28 -0
  41. data/lib/hackle/internal/http/http_client.rb +48 -0
  42. data/lib/hackle/internal/identifiers/identifier_builder.rb +67 -0
  43. data/lib/hackle/internal/logger/logger.rb +31 -0
  44. data/lib/hackle/internal/model/action.rb +57 -0
  45. data/lib/hackle/internal/model/bucket.rb +58 -0
  46. data/lib/hackle/internal/model/container.rb +47 -0
  47. data/lib/hackle/internal/model/decision_reason.rb +31 -0
  48. data/lib/hackle/internal/model/event_type.rb +19 -0
  49. data/lib/hackle/internal/model/experiment.rb +194 -0
  50. data/lib/hackle/internal/model/parameter_configuration.rb +19 -0
  51. data/lib/hackle/internal/model/remote_config_parameter.rb +76 -0
  52. data/lib/hackle/internal/model/sdk.rb +23 -0
  53. data/lib/hackle/internal/model/segment.rb +61 -0
  54. data/lib/hackle/internal/model/target.rb +203 -0
  55. data/lib/hackle/internal/model/target_rule.rb +19 -0
  56. data/lib/hackle/internal/model/targeting.rb +45 -0
  57. data/lib/hackle/internal/model/value_type.rb +75 -0
  58. data/lib/hackle/internal/model/variation.rb +27 -0
  59. data/lib/hackle/internal/model/version.rb +153 -0
  60. data/lib/hackle/internal/properties/properties_builder.rb +101 -0
  61. data/lib/hackle/internal/user/hackle_user.rb +74 -0
  62. data/lib/hackle/internal/user/hackle_user_resolver.rb +27 -0
  63. data/lib/hackle/internal/workspace/http_workspace_fetcher.rb +50 -0
  64. data/lib/hackle/internal/workspace/polling_workspace_fetcher.rb +62 -0
  65. data/lib/hackle/internal/workspace/workspace.rb +353 -0
  66. data/lib/hackle/internal/workspace/workspace_fetcher.rb +18 -0
  67. data/lib/hackle/remote_config.rb +55 -0
  68. data/lib/hackle/user.rb +124 -0
  69. data/lib/hackle/version.rb +1 -11
  70. data/lib/hackle.rb +4 -32
  71. metadata +123 -51
  72. data/.gitignore +0 -11
  73. data/.rspec +0 -2
  74. data/.travis.yml +0 -7
  75. data/Gemfile +0 -6
  76. data/README.md +0 -33
  77. data/Rakefile +0 -6
  78. data/hackle-ruby-sdk.gemspec +0 -29
  79. data/lib/hackle/decision/bucketer.rb +0 -30
  80. data/lib/hackle/decision/decider.rb +0 -54
  81. data/lib/hackle/events/event.rb +0 -33
  82. data/lib/hackle/events/event_dispatcher.rb +0 -89
  83. data/lib/hackle/events/event_processor.rb +0 -115
  84. data/lib/hackle/http/http.rb +0 -37
  85. data/lib/hackle/models/bucket.rb +0 -15
  86. data/lib/hackle/models/event_type.rb +0 -14
  87. data/lib/hackle/models/experiment.rb +0 -36
  88. data/lib/hackle/models/slot.rb +0 -15
  89. data/lib/hackle/models/variation.rb +0 -11
  90. data/lib/hackle/workspaces/http_workspace_fetcher.rb +0 -24
  91. data/lib/hackle/workspaces/polling_workspace_fetcher.rb +0 -44
  92. data/lib/hackle/workspaces/workspace.rb +0 -87
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+
5
+ class Container
6
+ # @!attribute [r] id
7
+ # @return [Integer]
8
+ # @!attribute [r] bucket_id
9
+ # @return [Integer]
10
+ # @!attribute [r] groups
11
+ # @return [Array<ContainerGroup>]
12
+ attr_reader :id, :bucket_id, :groups
13
+
14
+ # @param id [Integer]
15
+ # @param bucket_id [Integer]
16
+ # @param groups [Array<ContainerGroup>]
17
+ def initialize(id:, bucket_id:, groups:)
18
+ @id = id
19
+ @bucket_id = bucket_id
20
+ @groups = groups
21
+ end
22
+
23
+ # @param group_id [Integer]
24
+ # @return [ContainerGroup, nil]
25
+ def get_group_or_nil(group_id)
26
+ groups.each do |group|
27
+ return group if group.id == group_id
28
+ end
29
+ nil
30
+ end
31
+ end
32
+
33
+ class ContainerGroup
34
+ # @!attribute [r] id
35
+ # @return [Integer]
36
+ # @!attribute [r] experiments
37
+ # @return [Array<Integer>]
38
+ attr_reader :id, :experiments
39
+
40
+ # @param id [Integer]
41
+ # @param experiments [Array<Integer>]
42
+ def initialize(id:, experiments:)
43
+ @id = id
44
+ @experiments = experiments
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+ class DecisionReason
5
+ SDK_NOT_READY = 'SDK_NOT_READY'
6
+ EXCEPTION = 'EXCEPTION'
7
+ INVALID_INPUT = 'INVALID_INPUT'
8
+
9
+ EXPERIMENT_NOT_FOUND = 'EXPERIMENT_NOT_FOUND'
10
+ EXPERIMENT_DRAFT = 'EXPERIMENT_DRAFT'
11
+ EXPERIMENT_PAUSED = 'EXPERIMENT_PAUSED'
12
+ EXPERIMENT_COMPLETED = 'EXPERIMENT_COMPLETED'
13
+ OVERRIDDEN = 'OVERRIDDEN'
14
+ TRAFFIC_NOT_ALLOCATED = 'TRAFFIC_NOT_ALLOCATED'
15
+ TRAFFIC_ALLOCATED = 'TRAFFIC_ALLOCATED'
16
+ TRAFFIC_ALLOCATED_BY_TARGETING = 'TRAFFIC_ALLOCATED_BY_TARGETING'
17
+ VARIATION_DROPPED = 'VARIATION_DROPPED'
18
+ NOT_IN_EXPERIMENT_TARGET = 'NOT_IN_EXPERIMENT_TARGET'
19
+ NOT_IN_MUTUAL_EXCLUSION_EXPERIMENT = 'NOT_IN_MUTUAL_EXCLUSION_EXPERIMENT'
20
+ IDENTIFIER_NOT_FOUND = 'IDENTIFIER_NOT_FOUND'
21
+
22
+ FEATURE_FLAG_NOT_FOUND = 'FEATURE_FLAG_NOT_FOUND'
23
+ FEATURE_FLAG_INACTIVE = 'FEATURE_FLAG_INACTIVE'
24
+ INDIVIDUAL_TARGET_MATCH = 'INDIVIDUAL_TARGET_MATCH'
25
+ TARGET_RULE_MATCH = 'TARGET_RULE_MATCH'
26
+ DEFAULT_RULE = 'DEFAULT_RULE'
27
+
28
+ REMOTE_CONFIG_PARAMETER_NOT_FOUND = 'REMOTE_CONFIG_PARAMETER_NOT_FOUND'
29
+ TYPE_MISMATCH = 'TYPE_MISMATCH'
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+ class EventType
5
+
6
+ # @!attribute [r] id
7
+ # @return [Integer]
8
+ # @!attribute [r] key
9
+ # @return [String]
10
+ attr_accessor :id, :key
11
+
12
+ # @param id [Integer]
13
+ # @param key [String]
14
+ def initialize(id:, key:)
15
+ @id = id
16
+ @key = key
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+ class Experiment
5
+ # @return [Integer]
6
+ attr_reader :id
7
+
8
+ # @return [Integer]
9
+ attr_reader :key
10
+
11
+ # @return [String, nil]
12
+ attr_reader :name
13
+
14
+ # @return [ExperimentType]
15
+ attr_reader :type
16
+
17
+ # @return [String]
18
+ attr_reader :identifier_type
19
+
20
+ # @return [ExperimentStatus]
21
+ attr_reader :status
22
+
23
+ # @return [Integer]
24
+ attr_reader :version
25
+
26
+ # @return [Integer]
27
+ attr_reader :execution_version
28
+
29
+ # @return [Array<Variation>]
30
+ attr_reader :variations
31
+
32
+ # @return [Hash{String => Integer}]
33
+ attr_reader :user_overrides
34
+
35
+ # @return [Array<TargetRule>]
36
+ attr_reader :segment_overrides
37
+
38
+ # @return [Array<Target>]
39
+ attr_reader :target_audiences
40
+
41
+ # @return [Array<TargetRule>]
42
+ attr_reader :target_rules
43
+
44
+ # @return [Action]
45
+ attr_reader :default_rule
46
+
47
+ # @return [Integer, nil]
48
+ attr_reader :container_id
49
+
50
+ # @return [Integer, nil]
51
+ attr_reader :winner_variation_id
52
+
53
+ # @param [Integer] id
54
+ # @param [Integer] key
55
+ # @param [String, nil] name
56
+ # @param [ExperimentType] type
57
+ # @param [String] identifier_type
58
+ # @param [ExperimentStatus] status
59
+ # @param [Integer] version
60
+ # @param [Integer] execution_version
61
+ # @param [Array<Variation>] variations
62
+ # @param [Hash{String => Integer}] user_overrides
63
+ # @param [Array<TargetRule>] segment_overrides
64
+ # @param [Array<Target>] target_audiences
65
+ # @param [Array<TargetRule>] target_rules
66
+ # @param [Action] default_rule
67
+ # @param [Integer, nil] container_id
68
+ # @param [Integer, nil] winner_variation_id
69
+ def initialize(
70
+ id:,
71
+ key:,
72
+ name:,
73
+ type:,
74
+ identifier_type:,
75
+ status:,
76
+ version:,
77
+ execution_version:,
78
+ variations:,
79
+ user_overrides:,
80
+ segment_overrides:,
81
+ target_audiences:,
82
+ target_rules:,
83
+ default_rule:,
84
+ container_id:,
85
+ winner_variation_id:
86
+ )
87
+ @id = id
88
+ @key = key
89
+ @name = name
90
+ @type = type
91
+ @identifier_type = identifier_type
92
+ @status = status
93
+ @version = version
94
+ @execution_version = execution_version
95
+ @variations = variations
96
+ @user_overrides = user_overrides
97
+ @segment_overrides = segment_overrides
98
+ @target_audiences = target_audiences
99
+ @target_rules = target_rules
100
+ @default_rule = default_rule
101
+ @container_id = container_id
102
+ @winner_variation_id = winner_variation_id
103
+ end
104
+
105
+ # @param id [Integer]
106
+ # @return [Hackle::Variation, nil]
107
+ def get_variation_or_nil_by_id(id)
108
+ variations.find { |v| v.id == id }
109
+ end
110
+
111
+ # @param key [String]
112
+ # @return [Hackle::Variation, nil]
113
+ def get_variation_or_nil_by_key(key)
114
+ variations.find { |v| v.key == key }
115
+ end
116
+
117
+ # @return [Hackle::Variation, nil]
118
+ def winner_variation_or_nil
119
+ get_variation_or_nil_by_id(winner_variation_id) unless winner_variation_id.nil?
120
+ end
121
+ end
122
+
123
+ class ExperimentType
124
+ # @!attribute [r] name
125
+ # @return [String]
126
+ attr_reader :name
127
+
128
+ # @param name [String]
129
+ def initialize(name)
130
+ @name = name
131
+ end
132
+
133
+ def to_s
134
+ name
135
+ end
136
+
137
+ AB_TEST = new('AB_TEST')
138
+ FEATURE_FLAG = new('FEATURE_FLAG')
139
+
140
+ @types = {
141
+ 'AB_TEST' => AB_TEST,
142
+ 'FEATURE_FLAG' => FEATURE_FLAG
143
+ }.freeze
144
+
145
+ # @param name [String]
146
+ # @return [ExperimentType, nil]
147
+ def self.from_or_nil(name)
148
+ @types[name.upcase]
149
+ end
150
+
151
+ # @return [Array<ExperimentType>]
152
+ def self.values
153
+ @types.values
154
+ end
155
+ end
156
+
157
+ class ExperimentStatus
158
+ # @!attribute [r] name
159
+ # @return [String]
160
+ attr_reader :name
161
+
162
+ # @param name [String]
163
+ def initialize(name)
164
+ @name = name
165
+ end
166
+
167
+ def to_s
168
+ name
169
+ end
170
+
171
+ DRAFT = new('DRAFT')
172
+ RUNNING = new('RUNNING')
173
+ PAUSED = new('PAUSED')
174
+ COMPLETED = new('COMPLETED')
175
+
176
+ @types = {
177
+ 'READY' => DRAFT,
178
+ 'RUNNING' => RUNNING,
179
+ 'PAUSED' => PAUSED,
180
+ 'STOPPED' => COMPLETED
181
+ }.freeze
182
+
183
+ # @param name [String]
184
+ # @return [ExperimentStatus, nil]
185
+ def self.from_or_nil(name)
186
+ @types[name.upcase]
187
+ end
188
+
189
+ # @return [Array<ExperimentStatus>]
190
+ def self.values
191
+ @types.values
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+ class ParameterConfiguration
5
+
6
+ # @!attribute [r] id
7
+ # @return [Integer]
8
+ # @!attribute [r] parameters
9
+ # @return [Hash{String => Object}]
10
+ attr_accessor :id, :parameters
11
+
12
+ # @param id [Integer]
13
+ # @param parameters [Hash{String => Object}]
14
+ def initialize(id:, parameters:)
15
+ @id = id
16
+ @parameters = parameters
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+
5
+ class RemoteConfigParameter
6
+ # @!attribute [r] id
7
+ # @return [Integer]
8
+ # @!attribute [r] key
9
+ # @return [String]
10
+ # @!attribute [r] type
11
+ # @return [ValueType]
12
+ # @!attribute [r] identifier_type
13
+ # @return [String]
14
+ # @!attribute [r] target_rules
15
+ # @return [Array<RemoteConfigTargetRule>]
16
+ # @!attribute [r] default_value
17
+ # @return [RemoteConfigValue]
18
+ attr_accessor :id, :key, :type, :identifier_type, :target_rules, :default_value
19
+
20
+ # @param id [Integer]
21
+ # @param key [String]
22
+ # @param type [ValueType]
23
+ # @param identifier_type [String]
24
+ # @param target_rules [Array<RemoteConfigTargetRule>]
25
+ # @param default_value [RemoteConfigValue]
26
+ def initialize(id:, key:, type:, identifier_type:, target_rules:, default_value:)
27
+ @id = id
28
+ @key = key
29
+ @type = type
30
+ @identifier_type = identifier_type
31
+ @target_rules = target_rules
32
+ @default_value = default_value
33
+ end
34
+ end
35
+
36
+ class RemoteConfigTargetRule
37
+ # @!attribute [r] key
38
+ # @return [String]
39
+ # @!attribute [r] name
40
+ # @return [String]
41
+ # @!attribute [r] target
42
+ # @return [Target]
43
+ # @!attribute [r] bucket_id
44
+ # @return [Integer]
45
+ # @!attribute [r] value
46
+ # @return [RemoteConfigValue]
47
+ attr_reader :key, :name, :target, :bucket_id, :value
48
+
49
+ # @param key [String]
50
+ # @param name [String]
51
+ # @param target [Target]
52
+ # @param bucket_id [Integer]
53
+ # @param value [RemoteConfigValue]
54
+ def initialize(key:, name:, target:, bucket_id:, value:)
55
+ @key = key
56
+ @name = name
57
+ @target = target
58
+ @bucket_id = bucket_id
59
+ @value = value
60
+
61
+ end
62
+ end
63
+
64
+ class RemoteConfigValue
65
+ # @!attribute [r] id
66
+ # @return [Integer]
67
+ # @!attribute [r] raw_value
68
+ # @return [Object]
69
+ attr_accessor :id, :raw_value
70
+
71
+ def initialize(id:, raw_value:)
72
+ @id = id
73
+ @raw_value = raw_value
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+ class Sdk
5
+
6
+ # @!attribute [r] name
7
+ # @return [String]
8
+ # @!attribute [r] version
9
+ # @return [String]
10
+ # @!attribute [r] key
11
+ # @return [String]
12
+ attr_reader :name, :version, :key
13
+
14
+ # @param name [String]
15
+ # @param version [String]
16
+ # @param key [String]
17
+ def initialize(name:, version:, key:)
18
+ @name = name
19
+ @version = version
20
+ @key = key
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+ class Segment
5
+
6
+ # @!attribute [r] id
7
+ # @return [Integer]
8
+ # @!attribute [r] key
9
+ # @return [String]
10
+ # @!attribute [r] type
11
+ # @return [SegmentType]
12
+ # @!attribute [r] targets
13
+ # @return [Array<Target>]
14
+ attr_accessor :id, :key, :type, :targets
15
+
16
+ # @param id [Integer]
17
+ # @param key [String]
18
+ # @param type [SegmentType]
19
+ # @param targets [Array<Target>]
20
+ def initialize(id:, key:, type:, targets:)
21
+ @id = id
22
+ @key = key
23
+ @type = type
24
+ @targets = targets
25
+ end
26
+ end
27
+
28
+ class SegmentType
29
+ # @!attribute [r] name
30
+ # @return [String]
31
+ attr_reader :name
32
+
33
+ # @param name [String]
34
+ def initialize(name)
35
+ @name = name
36
+ end
37
+
38
+ def to_s
39
+ name
40
+ end
41
+
42
+ USER_ID = new('USER_ID')
43
+ USER_PROPERTY = new('USER_PROPERTY')
44
+
45
+ @types = {
46
+ 'USER_ID' => USER_ID,
47
+ 'USER_PROPERTY' => USER_PROPERTY
48
+ }.freeze
49
+
50
+ # @param name [String]
51
+ # @return [SegmentType, nil]
52
+ def self.from_or_nil(name)
53
+ @types[name.upcase]
54
+ end
55
+
56
+ # @return [Array<SegmentType>]
57
+ def self.values
58
+ @types.values
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+ class Target
5
+ # @!attribute [r] conditions
6
+ # @return [Array<TargetCondition>]
7
+ attr_reader :conditions
8
+
9
+ # @param conditions [Array<TargetCondition>]
10
+ def initialize(conditions:)
11
+ @conditions = conditions
12
+ end
13
+ end
14
+
15
+ class TargetCondition
16
+ # @!attribute [r] key
17
+ # @return [TargetKey]
18
+ # @!attribute [r] match
19
+ # @return [TargetMatch]
20
+ attr_reader :key, :match
21
+
22
+ def initialize(key:, match:)
23
+ @key = key
24
+ @match = match
25
+ end
26
+ end
27
+
28
+ class TargetKey
29
+ # @!attribute [r] type
30
+ # @return [TargetKeyType]
31
+ # @!attribute [r] name
32
+ # @return [String]
33
+ attr_reader :type, :name
34
+
35
+ # @param type [TargetKeyType]
36
+ # @param name [String]
37
+ def initialize(type:, name:)
38
+ @type = type
39
+ @name = name
40
+ end
41
+ end
42
+
43
+ class TargetMatch
44
+
45
+ # @!attribute [r] type
46
+ # @return [TargetMatchType]
47
+ # @!attribute [r] operator
48
+ # @return [TargetOperator]
49
+ # @!attribute [r] value_type
50
+ # @return [ValueType]
51
+ # @!attribute [r] values
52
+ # @return [Array<Object>]
53
+ attr_reader :type, :operator, :value_type, :values
54
+
55
+ # @param type [TargetMatchType]
56
+ # @param operator [TargetOperator]
57
+ # @param value_type [ValueType]
58
+ # @param values [Array<Object>]
59
+ def initialize(type:, operator:, value_type:, values:)
60
+ @type = type
61
+ @operator = operator
62
+ @value_type = value_type
63
+ @values = values
64
+ end
65
+
66
+ end
67
+
68
+ class TargetKeyType
69
+ # @!attribute [r] name
70
+ # @return [String]
71
+ attr_reader :name
72
+
73
+ # @param name [String]
74
+ def initialize(name)
75
+ @name = name
76
+ end
77
+
78
+ def to_s
79
+ name
80
+ end
81
+
82
+ USER_ID = new('USER_ID')
83
+ USER_PROPERTY = new('USER_PROPERTY')
84
+ HACKLE_PROPERTY = new('HACKLE_PROPERTY')
85
+ SEGMENT = new('SEGMENT')
86
+ AB_TEST = new('AB_TEST')
87
+ FEATURE_FLAG = new('FEATURE_FLAG')
88
+
89
+ @types = {
90
+ 'USER_ID' => USER_ID,
91
+ 'USER_PROPERTY' => USER_PROPERTY,
92
+ 'HACKLE_PROPERTY' => HACKLE_PROPERTY,
93
+ 'SEGMENT' => SEGMENT,
94
+ 'AB_TEST' => AB_TEST,
95
+ 'FEATURE_FLAG' => FEATURE_FLAG
96
+ }.freeze
97
+
98
+ # @param name [String]
99
+ # @return [TargetKeyType, nil]
100
+ def self.from_or_nil(name)
101
+ @types[name.upcase]
102
+ end
103
+
104
+ # @return [Array<TargetKeyType>]
105
+ def self.values
106
+ @types.values
107
+ end
108
+ end
109
+
110
+ class TargetMatchType
111
+ # @!attribute [r] name
112
+ # @return [String]
113
+ attr_reader :name
114
+
115
+ # @param name [String]
116
+ def initialize(name)
117
+ @name = name
118
+ end
119
+
120
+ def to_s
121
+ name
122
+ end
123
+
124
+ MATCH = new('MATCH')
125
+ NOT_MATCH = new('NOT MATCH')
126
+
127
+ @types = {
128
+ 'MATCH' => MATCH,
129
+ 'NOT_MATCH' => NOT_MATCH
130
+ }
131
+
132
+ # @param name [String]
133
+ # @return [TargetMatchType, nil]
134
+ def self.from_or_nil(name)
135
+ @types[name.upcase]
136
+ end
137
+
138
+ # @return [Array<TargetMatchType>]
139
+ def self.values
140
+ @types.values
141
+ end
142
+
143
+ # @param type [TargetMatchType]
144
+ # @param matches [boolean]
145
+ # @return [boolean]
146
+ def self.matches(type, matches)
147
+ case type
148
+ when MATCH
149
+ matches
150
+ when NOT_MATCH
151
+ !matches
152
+ else
153
+ raise ArgumentError, "Unsupported type: #{type}"
154
+ end
155
+ end
156
+ end
157
+
158
+ class TargetOperator
159
+ # @!attribute [r] name
160
+ # @return [String]
161
+ attr_reader :name
162
+
163
+ # @param name [String]
164
+ def initialize(name)
165
+ @name = name
166
+ end
167
+
168
+ def to_s
169
+ name
170
+ end
171
+
172
+ IN = new('IN')
173
+ CONTAINS = new('CONTAINS')
174
+ STARTS_WITH = new('STARTS_WITH')
175
+ ENDS_WITH = new('ENDS_WITH')
176
+ GT = new('GT')
177
+ GTE = new('GTE')
178
+ LT = new('LT')
179
+ LTE = new('LTE')
180
+
181
+ @types = {
182
+ 'IN' => IN,
183
+ 'CONTAINS' => CONTAINS,
184
+ 'STARTS_WITH' => STARTS_WITH,
185
+ 'ENDS_WITH' => ENDS_WITH,
186
+ 'GT' => GT,
187
+ 'GTE' => GTE,
188
+ 'LT' => LT,
189
+ 'LTE' => LTE
190
+ }.freeze
191
+
192
+ # @param name [String]
193
+ # @return [TargetOperator, nil]
194
+ def self.from_or_nil(name)
195
+ @types[name.upcase]
196
+ end
197
+
198
+ # @return [Array<TargetOperator>]
199
+ def self.values
200
+ @types.values
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hackle
4
+ class TargetRule
5
+
6
+ # @!attribute [r] target
7
+ # @return [Target]
8
+ # @!attribute [r] action
9
+ # @return [Action]
10
+ attr_accessor :target, :action
11
+
12
+ # @param target [Target]
13
+ # @param action [Action]
14
+ def initialize(target:, action:)
15
+ @target = target
16
+ @action = action
17
+ end
18
+ end
19
+ end