featurevisor 0.2.0 → 1.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.
- checksums.yaml +4 -4
- data/README.md +172 -75
- data/bin/cli.rb +15 -2
- data/bin/commands/assess_distribution.rb +34 -15
- data/bin/commands/benchmark.rb +65 -63
- data/bin/commands/test.rb +250 -100
- data/lib/featurevisor/child_instance.rb +22 -24
- data/lib/featurevisor/datafile_reader.rb +18 -13
- data/lib/featurevisor/emitter.rb +2 -2
- data/lib/featurevisor/evaluate.rb +106 -100
- data/lib/featurevisor/events.rb +5 -4
- data/lib/featurevisor/instance.rb +225 -39
- data/lib/featurevisor/logger.rb +0 -7
- data/lib/featurevisor/modules.rb +184 -0
- data/lib/featurevisor/version.rb +1 -1
- data/lib/featurevisor.rb +4 -1
- metadata +16 -2
- data/lib/featurevisor/hooks.rb +0 -159
|
@@ -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]
|
|
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"]
|
|
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]
|
|
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"]
|
|
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
|
data/lib/featurevisor/emitter.rb
CHANGED
|
@@ -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
|
|
@@ -17,7 +17,8 @@ module Featurevisor
|
|
|
17
17
|
VARIABLE_NOT_FOUND = "variable_not_found" # variable's schema is not defined in the feature
|
|
18
18
|
VARIABLE_DEFAULT = "variable_default" # default variable value used
|
|
19
19
|
VARIABLE_DISABLED = "variable_disabled" # feature is disabled, and variable's disabledValue is used
|
|
20
|
-
|
|
20
|
+
VARIABLE_OVERRIDE_VARIATION = "variable_override_variation" # variable overridden from inside a variation
|
|
21
|
+
VARIABLE_OVERRIDE_RULE = "variable_override_rule" # variable overridden from inside a rule
|
|
21
22
|
|
|
22
23
|
# Common
|
|
23
24
|
NO_MATCH = "no_match" # no rules matched
|
|
@@ -35,44 +36,39 @@ module Featurevisor
|
|
|
35
36
|
# Evaluation module for feature flag evaluation
|
|
36
37
|
module Evaluate
|
|
37
38
|
|
|
38
|
-
# Evaluate with
|
|
39
|
+
# Evaluate with modules
|
|
39
40
|
# @param options [Hash] Evaluation options
|
|
40
41
|
# @return [Hash] Evaluation result
|
|
41
|
-
def self.
|
|
42
|
+
def self.evaluate_with_modules(options)
|
|
42
43
|
begin
|
|
43
|
-
|
|
44
|
-
hooks = hooks_manager.get_all
|
|
44
|
+
modules_manager = options[:modules_manager]
|
|
45
45
|
|
|
46
|
-
# Run before
|
|
46
|
+
# Run before modules
|
|
47
47
|
result_options = options
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
result_options = hook.call_before(result_options)
|
|
51
|
-
end
|
|
48
|
+
if modules_manager
|
|
49
|
+
result_options = modules_manager.run_before_modules(result_options)
|
|
52
50
|
end
|
|
53
51
|
|
|
54
52
|
# Evaluate
|
|
55
53
|
evaluation = evaluate(result_options)
|
|
56
54
|
|
|
57
55
|
# Default: variation
|
|
58
|
-
if options
|
|
56
|
+
if options.key?(:default_variation_value) &&
|
|
59
57
|
evaluation[:type] == "variation" &&
|
|
60
58
|
evaluation[:variation_value].nil?
|
|
61
59
|
evaluation[:variation_value] = options[:default_variation_value]
|
|
62
60
|
end
|
|
63
61
|
|
|
64
62
|
# Default: variable
|
|
65
|
-
if options
|
|
63
|
+
if options.key?(:default_variable_value) &&
|
|
66
64
|
evaluation[:type] == "variable" &&
|
|
67
65
|
evaluation[:variable_value].nil?
|
|
68
66
|
evaluation[:variable_value] = options[:default_variable_value]
|
|
69
67
|
end
|
|
70
68
|
|
|
71
|
-
# Run after
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
evaluation = hook.call_after(evaluation, result_options)
|
|
75
|
-
end
|
|
69
|
+
# Run after modules
|
|
70
|
+
if modules_manager
|
|
71
|
+
evaluation = modules_manager.run_after_modules(evaluation, result_options)
|
|
76
72
|
end
|
|
77
73
|
|
|
78
74
|
evaluation
|
|
@@ -107,9 +103,7 @@ module Featurevisor
|
|
|
107
103
|
logger = options[:logger]
|
|
108
104
|
datafile_reader = options[:datafile_reader]
|
|
109
105
|
sticky = options[:sticky]
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
hooks = hooks_manager.get_all
|
|
106
|
+
modules_manager = options[:modules_manager]
|
|
113
107
|
evaluation = nil
|
|
114
108
|
|
|
115
109
|
begin
|
|
@@ -132,10 +126,10 @@ module Featurevisor
|
|
|
132
126
|
if type == "variable"
|
|
133
127
|
if feature && variable_key &&
|
|
134
128
|
feature[:variablesSchema] &&
|
|
135
|
-
(feature[:variablesSchema]
|
|
136
|
-
variable_schema = feature[:variablesSchema]
|
|
129
|
+
has_key?(feature[:variablesSchema], variable_key)
|
|
130
|
+
variable_schema = fetch_with_symbol_key(feature[:variablesSchema], variable_key)
|
|
137
131
|
|
|
138
|
-
if variable_schema
|
|
132
|
+
if variable_schema.key?(:disabledValue)
|
|
139
133
|
# disabledValue: <value>
|
|
140
134
|
evaluation = {
|
|
141
135
|
type: type,
|
|
@@ -179,8 +173,8 @@ module Featurevisor
|
|
|
179
173
|
end
|
|
180
174
|
|
|
181
175
|
# Sticky
|
|
182
|
-
if sticky && (sticky
|
|
183
|
-
sticky_feature = sticky
|
|
176
|
+
if sticky && has_key?(sticky, feature_key)
|
|
177
|
+
sticky_feature = fetch_with_symbol_key(sticky, feature_key)
|
|
184
178
|
|
|
185
179
|
# flag
|
|
186
180
|
if type == "flag" && sticky_feature.key?(:enabled)
|
|
@@ -201,7 +195,7 @@ module Featurevisor
|
|
|
201
195
|
if type == "variation"
|
|
202
196
|
variation_value = sticky_feature[:variation]
|
|
203
197
|
|
|
204
|
-
|
|
198
|
+
unless variation_value.nil?
|
|
205
199
|
evaluation = {
|
|
206
200
|
type: type,
|
|
207
201
|
feature_key: feature_key,
|
|
@@ -219,8 +213,8 @@ module Featurevisor
|
|
|
219
213
|
if type == "variable" && variable_key
|
|
220
214
|
variables = sticky_feature[:variables]
|
|
221
215
|
|
|
222
|
-
if variables && (variables
|
|
223
|
-
variable_value = variables
|
|
216
|
+
if variables && has_key?(variables, variable_key)
|
|
217
|
+
variable_value = fetch_with_symbol_key(variables, variable_key)
|
|
224
218
|
evaluation = {
|
|
225
219
|
type: type,
|
|
226
220
|
feature_key: feature_key,
|
|
@@ -261,8 +255,8 @@ module Featurevisor
|
|
|
261
255
|
variable_schema = nil
|
|
262
256
|
|
|
263
257
|
if variable_key
|
|
264
|
-
if feature[:variablesSchema] && (feature[:variablesSchema]
|
|
265
|
-
variable_schema = feature[:variablesSchema]
|
|
258
|
+
if feature[:variablesSchema] && has_key?(feature[:variablesSchema], variable_key)
|
|
259
|
+
variable_schema = fetch_with_symbol_key(feature[:variablesSchema], variable_key)
|
|
266
260
|
end
|
|
267
261
|
|
|
268
262
|
# variable schema not found
|
|
@@ -343,8 +337,8 @@ module Featurevisor
|
|
|
343
337
|
end
|
|
344
338
|
|
|
345
339
|
# variable
|
|
346
|
-
if variable_key && force[:variables] && (force[:variables]
|
|
347
|
-
variable_value = force[:variables]
|
|
340
|
+
if variable_key && force[:variables] && has_key?(force[:variables], variable_key)
|
|
341
|
+
variable_value = fetch_with_symbol_key(force[:variables], variable_key)
|
|
348
342
|
evaluation = {
|
|
349
343
|
type: type,
|
|
350
344
|
feature_key: feature_key,
|
|
@@ -385,8 +379,8 @@ module Featurevisor
|
|
|
385
379
|
|
|
386
380
|
required_variation_value = nil
|
|
387
381
|
|
|
388
|
-
if required_variation_evaluation
|
|
389
|
-
required_variation_value = required_variation_evaluation
|
|
382
|
+
if has_key?(required_variation_evaluation, :variation_value)
|
|
383
|
+
required_variation_value = fetch_with_symbol_key(required_variation_evaluation, :variation_value)
|
|
390
384
|
elsif required_variation_evaluation[:variation]
|
|
391
385
|
required_variation_value = required_variation_evaluation[:variation][:value]
|
|
392
386
|
end
|
|
@@ -421,24 +415,24 @@ module Featurevisor
|
|
|
421
415
|
logger: logger
|
|
422
416
|
})
|
|
423
417
|
|
|
424
|
-
# Run bucket key
|
|
425
|
-
bucket_key =
|
|
418
|
+
# Run bucket key modules
|
|
419
|
+
bucket_key = modules_manager.run_bucket_key_modules({
|
|
426
420
|
feature_key: feature_key,
|
|
427
421
|
context: context,
|
|
428
422
|
bucket_by: feature[:bucketBy],
|
|
429
423
|
bucket_key: bucket_key
|
|
430
|
-
})
|
|
424
|
+
}) if modules_manager
|
|
431
425
|
|
|
432
426
|
# bucketValue
|
|
433
427
|
bucket_value = Featurevisor::Bucketer.get_bucketed_number(bucket_key)
|
|
434
428
|
|
|
435
|
-
# Run bucket value
|
|
436
|
-
bucket_value =
|
|
429
|
+
# Run bucket value modules
|
|
430
|
+
bucket_value = modules_manager.run_bucket_value_modules({
|
|
437
431
|
feature_key: feature_key,
|
|
438
432
|
bucket_key: bucket_key,
|
|
439
433
|
context: context,
|
|
440
434
|
bucket_value: bucket_value
|
|
441
|
-
})
|
|
435
|
+
}) if modules_manager
|
|
442
436
|
|
|
443
437
|
matched_traffic = nil
|
|
444
438
|
matched_allocation = nil
|
|
@@ -601,10 +595,50 @@ module Featurevisor
|
|
|
601
595
|
# variable
|
|
602
596
|
if type == "variable" && variable_key
|
|
603
597
|
# override from rule
|
|
598
|
+
if matched_traffic &&
|
|
599
|
+
matched_traffic[:variableOverrides] &&
|
|
600
|
+
has_key?(matched_traffic[:variableOverrides], variable_key)
|
|
601
|
+
overrides = fetch_with_symbol_key(matched_traffic[:variableOverrides], variable_key)
|
|
602
|
+
|
|
603
|
+
override_index = overrides.find_index do |o|
|
|
604
|
+
if o[:conditions]
|
|
605
|
+
conditions = o[:conditions].is_a?(String) && o[:conditions] != "*" ? JSON.parse(o[:conditions]) : o[:conditions]
|
|
606
|
+
datafile_reader.all_conditions_are_matched(conditions, context)
|
|
607
|
+
elsif o[:segments]
|
|
608
|
+
segments = datafile_reader.parse_segments_if_stringified(o[:segments])
|
|
609
|
+
datafile_reader.all_segments_are_matched(segments, context)
|
|
610
|
+
else
|
|
611
|
+
false
|
|
612
|
+
end
|
|
613
|
+
end
|
|
614
|
+
|
|
615
|
+
unless override_index.nil?
|
|
616
|
+
override = overrides[override_index]
|
|
617
|
+
|
|
618
|
+
evaluation = {
|
|
619
|
+
type: type,
|
|
620
|
+
feature_key: feature_key,
|
|
621
|
+
reason: Featurevisor::EvaluationReason::VARIABLE_OVERRIDE_RULE,
|
|
622
|
+
bucket_key: bucket_key,
|
|
623
|
+
bucket_value: bucket_value,
|
|
624
|
+
rule_key: matched_traffic[:key],
|
|
625
|
+
traffic: matched_traffic,
|
|
626
|
+
variable_key: variable_key,
|
|
627
|
+
variable_schema: variable_schema,
|
|
628
|
+
variable_value: override[:value],
|
|
629
|
+
variable_override_index: override_index
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
logger.debug("variable override from rule", evaluation)
|
|
633
|
+
|
|
634
|
+
return evaluation
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
|
|
604
638
|
if matched_traffic &&
|
|
605
639
|
matched_traffic[:variables] &&
|
|
606
|
-
(matched_traffic[:variables]
|
|
607
|
-
variable_value = matched_traffic[:variables]
|
|
640
|
+
has_key?(matched_traffic[:variables], variable_key)
|
|
641
|
+
variable_value = fetch_with_symbol_key(matched_traffic[:variables], variable_key)
|
|
608
642
|
evaluation = {
|
|
609
643
|
type: type,
|
|
610
644
|
feature_key: feature_key,
|
|
@@ -637,81 +671,38 @@ module Featurevisor
|
|
|
637
671
|
if variation_value && feature[:variations].is_a?(Array)
|
|
638
672
|
variation = feature[:variations].find { |v| v[:value] == variation_value }
|
|
639
673
|
|
|
640
|
-
if variation && variation[:variableOverrides] && (variation[:variableOverrides]
|
|
641
|
-
overrides = variation[:variableOverrides]
|
|
642
|
-
|
|
643
|
-
logger.debug("checking variableOverrides", {
|
|
644
|
-
feature_key: feature_key,
|
|
645
|
-
variable_key: variable_key,
|
|
646
|
-
overrides: overrides,
|
|
647
|
-
context: context
|
|
648
|
-
})
|
|
674
|
+
if variation && variation[:variableOverrides] && has_key?(variation[:variableOverrides], variable_key)
|
|
675
|
+
overrides = fetch_with_symbol_key(variation[:variableOverrides], variable_key)
|
|
649
676
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
override: o,
|
|
655
|
-
context: context
|
|
656
|
-
})
|
|
657
|
-
|
|
658
|
-
result = if o[:conditions]
|
|
659
|
-
matched = datafile_reader.all_conditions_are_matched(
|
|
660
|
-
o[:conditions].is_a?(String) && o[:conditions] != "*" ?
|
|
661
|
-
JSON.parse(o[:conditions]) : o[:conditions],
|
|
662
|
-
context
|
|
663
|
-
)
|
|
664
|
-
logger.debug("conditions match result", {
|
|
665
|
-
feature_key: feature_key,
|
|
666
|
-
variable_key: variable_key,
|
|
667
|
-
conditions: o[:conditions],
|
|
668
|
-
matched: matched
|
|
669
|
-
})
|
|
670
|
-
matched
|
|
677
|
+
override_index = overrides.find_index do |o|
|
|
678
|
+
if o[:conditions]
|
|
679
|
+
conditions = o[:conditions].is_a?(String) && o[:conditions] != "*" ? JSON.parse(o[:conditions]) : o[:conditions]
|
|
680
|
+
datafile_reader.all_conditions_are_matched(conditions, context)
|
|
671
681
|
elsif o[:segments]
|
|
672
682
|
segments = datafile_reader.parse_segments_if_stringified(o[:segments])
|
|
673
|
-
|
|
674
|
-
logger.debug("segments match result", {
|
|
675
|
-
feature_key: feature_key,
|
|
676
|
-
variable_key: variable_key,
|
|
677
|
-
segments: o[:segments],
|
|
678
|
-
parsed_segments: segments,
|
|
679
|
-
matched: matched
|
|
680
|
-
})
|
|
681
|
-
matched
|
|
683
|
+
datafile_reader.all_segments_are_matched(segments, context)
|
|
682
684
|
else
|
|
683
|
-
logger.debug("override has no conditions or segments", {
|
|
684
|
-
feature_key: feature_key,
|
|
685
|
-
variable_key: variable_key,
|
|
686
|
-
override: o
|
|
687
|
-
})
|
|
688
685
|
false
|
|
689
686
|
end
|
|
690
|
-
|
|
691
|
-
logger.debug("override evaluation result", {
|
|
692
|
-
feature_key: feature_key,
|
|
693
|
-
variable_key: variable_key,
|
|
694
|
-
result: result
|
|
695
|
-
})
|
|
696
|
-
|
|
697
|
-
result
|
|
698
687
|
end
|
|
699
688
|
|
|
700
|
-
|
|
689
|
+
unless override_index.nil?
|
|
690
|
+
override = overrides[override_index]
|
|
701
691
|
evaluation = {
|
|
702
692
|
type: type,
|
|
703
693
|
feature_key: feature_key,
|
|
704
|
-
reason: Featurevisor::EvaluationReason::
|
|
694
|
+
reason: Featurevisor::EvaluationReason::VARIABLE_OVERRIDE_VARIATION,
|
|
705
695
|
bucket_key: bucket_key,
|
|
706
696
|
bucket_value: bucket_value,
|
|
707
697
|
rule_key: matched_traffic&.[](:key),
|
|
708
698
|
traffic: matched_traffic,
|
|
709
699
|
variable_key: variable_key,
|
|
710
700
|
variable_schema: variable_schema,
|
|
711
|
-
variable_value: override[:value]
|
|
701
|
+
variable_value: override[:value],
|
|
702
|
+
variable_override_index: override_index
|
|
712
703
|
}
|
|
713
704
|
|
|
714
|
-
logger.debug("variable override", evaluation)
|
|
705
|
+
logger.debug("variable override from variation", evaluation)
|
|
715
706
|
|
|
716
707
|
return evaluation
|
|
717
708
|
end
|
|
@@ -719,8 +710,8 @@ module Featurevisor
|
|
|
719
710
|
|
|
720
711
|
if variation &&
|
|
721
712
|
variation[:variables] &&
|
|
722
|
-
(variation[:variables]
|
|
723
|
-
variable_value = variation[:variables]
|
|
713
|
+
has_key?(variation[:variables], variable_key)
|
|
714
|
+
variable_value = fetch_with_symbol_key(variation[:variables], variable_key)
|
|
724
715
|
evaluation = {
|
|
725
716
|
type: type,
|
|
726
717
|
feature_key: feature_key,
|
|
@@ -814,5 +805,20 @@ module Featurevisor
|
|
|
814
805
|
evaluation
|
|
815
806
|
end
|
|
816
807
|
end
|
|
808
|
+
|
|
809
|
+
def self.fetch_with_symbol_key(obj, key)
|
|
810
|
+
return obj[key] if obj.is_a?(Hash) && obj.key?(key)
|
|
811
|
+
|
|
812
|
+
symbol_key = key.to_sym
|
|
813
|
+
return obj[symbol_key] if obj.is_a?(Hash) && obj.key?(symbol_key)
|
|
814
|
+
|
|
815
|
+
nil
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
def self.has_key?(obj, key)
|
|
819
|
+
return false unless obj.is_a?(Hash)
|
|
820
|
+
|
|
821
|
+
obj.key?(key) || obj.key?(key.to_sym)
|
|
822
|
+
end
|
|
817
823
|
end
|
|
818
824
|
end
|
data/lib/featurevisor/events.rb
CHANGED
|
@@ -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
|
-
|
|
71
|
-
|
|
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
|