featurevisor 0.3.0 → 1.1.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.
@@ -3,8 +3,6 @@
3
3
  module Featurevisor
4
4
  # Child instance class for managing child contexts and sticky features
5
5
  class ChildInstance
6
- attr_reader :parent, :context, :sticky, :emitter
7
-
8
6
  # Initialize a new child instance
9
7
  # @param options [Hash] Child instance options
10
8
  # @option options [Instance] :parent Parent instance
@@ -94,8 +92,8 @@ module Featurevisor
94
92
  **context
95
93
  },
96
94
  {
97
- sticky: @sticky,
98
- **options
95
+ **options,
96
+ __featurevisor_child_sticky: @sticky
99
97
  }
100
98
  )
101
99
  end
@@ -113,8 +111,8 @@ module Featurevisor
113
111
  **context
114
112
  },
115
113
  {
116
- sticky: @sticky,
117
- **options
114
+ **options,
115
+ __featurevisor_child_sticky: @sticky
118
116
  }
119
117
  )
120
118
  end
@@ -134,8 +132,8 @@ module Featurevisor
134
132
  **context
135
133
  },
136
134
  {
137
- sticky: @sticky,
138
- **options
135
+ **options,
136
+ __featurevisor_child_sticky: @sticky
139
137
  }
140
138
  )
141
139
  end
@@ -155,8 +153,8 @@ module Featurevisor
155
153
  **context
156
154
  },
157
155
  {
158
- sticky: @sticky,
159
- **options
156
+ **options,
157
+ __featurevisor_child_sticky: @sticky
160
158
  }
161
159
  )
162
160
  end
@@ -176,8 +174,8 @@ module Featurevisor
176
174
  **context
177
175
  },
178
176
  {
179
- sticky: @sticky,
180
- **options
177
+ **options,
178
+ __featurevisor_child_sticky: @sticky
181
179
  }
182
180
  )
183
181
  end
@@ -197,8 +195,8 @@ module Featurevisor
197
195
  **context
198
196
  },
199
197
  {
200
- sticky: @sticky,
201
- **options
198
+ **options,
199
+ __featurevisor_child_sticky: @sticky
202
200
  }
203
201
  )
204
202
  end
@@ -218,8 +216,8 @@ module Featurevisor
218
216
  **context
219
217
  },
220
218
  {
221
- sticky: @sticky,
222
- **options
219
+ **options,
220
+ __featurevisor_child_sticky: @sticky
223
221
  }
224
222
  )
225
223
  end
@@ -239,8 +237,8 @@ module Featurevisor
239
237
  **context
240
238
  },
241
239
  {
242
- sticky: @sticky,
243
- **options
240
+ **options,
241
+ __featurevisor_child_sticky: @sticky
244
242
  }
245
243
  )
246
244
  end
@@ -260,8 +258,8 @@ module Featurevisor
260
258
  **context
261
259
  },
262
260
  {
263
- sticky: @sticky,
264
- **options
261
+ **options,
262
+ __featurevisor_child_sticky: @sticky
265
263
  }
266
264
  )
267
265
  end
@@ -281,8 +279,8 @@ module Featurevisor
281
279
  **context
282
280
  },
283
281
  {
284
- sticky: @sticky,
285
- **options
282
+ **options,
283
+ __featurevisor_child_sticky: @sticky
286
284
  }
287
285
  )
288
286
  end
@@ -300,8 +298,8 @@ module Featurevisor
300
298
  },
301
299
  feature_keys,
302
300
  {
303
- sticky: @sticky,
304
- **options
301
+ **options,
302
+ __featurevisor_child_sticky: @sticky
305
303
  }
306
304
  )
307
305
  end
@@ -5,7 +5,7 @@ require "json"
5
5
  module Featurevisor
6
6
  # DatafileReader class for reading and processing Featurevisor datafiles
7
7
  class DatafileReader
8
- attr_reader :schema_version, :revision, :segments, :features, :logger, :regex_cache
8
+ attr_reader :schema_version, :revision, :featurevisor_version, :segments, :features, :logger, :regex_cache
9
9
 
10
10
  # Initialize a new DatafileReader
11
11
  # @param options [Hash] Options hash containing datafile and logger
@@ -17,6 +17,7 @@ module Featurevisor
17
17
 
18
18
  @schema_version = datafile[:schemaVersion]
19
19
  @revision = datafile[:revision]
20
+ @featurevisor_version = datafile[:featurevisorVersion]
20
21
  @segments = (datafile[:segments] || {}).transform_keys(&:to_sym)
21
22
  @features = (datafile[:features] || {}).transform_keys(&:to_sym)
22
23
 
@@ -65,6 +66,16 @@ module Featurevisor
65
66
  @schema_version
66
67
  end
67
68
 
69
+ def get_datafile
70
+ {
71
+ schemaVersion: @schema_version,
72
+ revision: @revision,
73
+ featurevisorVersion: @featurevisor_version,
74
+ segments: @segments,
75
+ features: @features
76
+ }.compact
77
+ end
78
+
68
79
  # Get a segment by key
69
80
  # @param segment_key [String] Segment key to retrieve
70
81
  # @return [Hash, nil] Segment data or nil if not found
@@ -172,15 +183,11 @@ module Featurevisor
172
183
  end
173
184
 
174
185
  if conditions.is_a?(Hash) && conditions[:not] && conditions[:not].is_a?(Array)
175
- return conditions[:not].all? do
176
- all_conditions_are_matched({ and: conditions[:not] }, context) == false
177
- end
186
+ return !all_conditions_are_matched({ and: conditions[:not] }, context)
178
187
  end
179
188
 
180
189
  if conditions.is_a?(Hash) && conditions["not"] && conditions["not"].is_a?(Array)
181
- return conditions["not"].all? do
182
- all_conditions_are_matched({ "and" => conditions["not"] }, context) == false
183
- end
190
+ return !all_conditions_are_matched({ "and" => conditions["not"] }, context)
184
191
  end
185
192
 
186
193
 
@@ -237,15 +244,11 @@ module Featurevisor
237
244
  end
238
245
 
239
246
  if group_segments[:not] && group_segments[:not].is_a?(Array)
240
- return group_segments[:not].all? do
241
- all_segments_are_matched({ and: group_segments[:not] }, context) == false
242
- end
247
+ return !all_segments_are_matched({ and: group_segments[:not] }, context)
243
248
  end
244
249
 
245
250
  if group_segments["not"] && group_segments["not"].is_a?(Array)
246
- return group_segments["not"].all? do
247
- all_segments_are_matched({ "and" => group_segments["not"] }, context) == false
248
- end
251
+ return !all_segments_are_matched({ "and" => group_segments["not"] }, context)
249
252
  end
250
253
 
251
254
 
@@ -351,4 +354,6 @@ module Featurevisor
351
354
  segments
352
355
  end
353
356
  end
357
+
358
+ private_constant :DatafileReader
354
359
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Featurevisor
4
4
  # Event names for the emitter
5
- EVENT_NAMES = %w[datafile_set context_set sticky_set].freeze
5
+ EVENT_NAMES = %w[datafile_set context_set sticky_set error].freeze
6
6
 
7
7
  # Event emitter class for handling event subscriptions and triggers
8
8
  class Emitter
@@ -42,7 +42,7 @@ module Featurevisor
42
42
 
43
43
  return unless listeners
44
44
 
45
- listeners.each do |listener|
45
+ listeners.dup.each do |listener|
46
46
  begin
47
47
  listener.call(details)
48
48
  rescue => err
@@ -36,20 +36,17 @@ module Featurevisor
36
36
  # Evaluation module for feature flag evaluation
37
37
  module Evaluate
38
38
 
39
- # Evaluate with hooks
39
+ # Evaluate with modules
40
40
  # @param options [Hash] Evaluation options
41
41
  # @return [Hash] Evaluation result
42
- def self.evaluate_with_hooks(options)
42
+ def self.evaluate_with_modules(options)
43
43
  begin
44
- hooks_manager = options[:hooks_manager]
45
- hooks = hooks_manager.get_all
44
+ modules_manager = options[:modules_manager]
46
45
 
47
- # Run before hooks
46
+ # Run before modules
48
47
  result_options = options
49
- hooks.each do |hook|
50
- if hook.respond_to?(:call_before)
51
- result_options = hook.call_before(result_options)
52
- end
48
+ if modules_manager
49
+ result_options = modules_manager.run_before_modules(result_options)
53
50
  end
54
51
 
55
52
  # Evaluate
@@ -69,11 +66,9 @@ module Featurevisor
69
66
  evaluation[:variable_value] = options[:default_variable_value]
70
67
  end
71
68
 
72
- # Run after hooks
73
- hooks.each do |hook|
74
- if hook.respond_to?(:call_after)
75
- evaluation = hook.call_after(evaluation, result_options)
76
- end
69
+ # Run after modules
70
+ if modules_manager
71
+ evaluation = modules_manager.run_after_modules(evaluation, result_options)
77
72
  end
78
73
 
79
74
  evaluation
@@ -108,9 +103,7 @@ module Featurevisor
108
103
  logger = options[:logger]
109
104
  datafile_reader = options[:datafile_reader]
110
105
  sticky = options[:sticky]
111
- hooks_manager = options[:hooks_manager]
112
-
113
- hooks = hooks_manager.get_all
106
+ modules_manager = options[:modules_manager]
114
107
  evaluation = nil
115
108
 
116
109
  begin
@@ -422,24 +415,24 @@ module Featurevisor
422
415
  logger: logger
423
416
  })
424
417
 
425
- # Run bucket key hooks
426
- bucket_key = hooks_manager.run_bucket_key_hooks({
418
+ # Run bucket key modules
419
+ bucket_key = modules_manager.run_bucket_key_modules({
427
420
  feature_key: feature_key,
428
421
  context: context,
429
422
  bucket_by: feature[:bucketBy],
430
423
  bucket_key: bucket_key
431
- })
424
+ }) if modules_manager
432
425
 
433
426
  # bucketValue
434
427
  bucket_value = Featurevisor::Bucketer.get_bucketed_number(bucket_key)
435
428
 
436
- # Run bucket value hooks
437
- bucket_value = hooks_manager.run_bucket_value_hooks({
429
+ # Run bucket value modules
430
+ bucket_value = modules_manager.run_bucket_value_modules({
438
431
  feature_key: feature_key,
439
432
  bucket_key: bucket_key,
440
433
  context: context,
441
434
  bucket_value: bucket_value
442
- })
435
+ }) if modules_manager
443
436
 
444
437
  matched_traffic = nil
445
438
  matched_allocation = nil
@@ -24,7 +24,7 @@ module Featurevisor
24
24
  # @param previous_reader [DatafileReader] Previous datafile reader
25
25
  # @param new_reader [DatafileReader] New datafile reader
26
26
  # @return [Hash] Event parameters
27
- def self.get_params_for_datafile_set_event(previous_reader, new_reader)
27
+ def self.get_params_for_datafile_set_event(previous_reader, new_reader, replace = false)
28
28
  previous_revision = previous_reader.get_revision
29
29
  previous_feature_keys = previous_reader.get_feature_keys
30
30
 
@@ -67,9 +67,10 @@ module Featurevisor
67
67
 
68
68
  {
69
69
  revision: new_revision,
70
- previous_revision: previous_revision,
71
- revision_changed: previous_revision != new_revision,
72
- features: all_affected_features
70
+ previousRevision: previous_revision,
71
+ revisionChanged: previous_revision != new_revision,
72
+ features: all_affected_features,
73
+ replaced: replace
73
74
  }
74
75
  end
75
76
  end