featurevisor 1.1.0 → 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.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/README.md +9 -2
- data/bin/commands/test.rb +1 -1
- data/lib/featurevisor/bucketer.rb +62 -8
- data/lib/featurevisor/child_instance.rb +43 -1
- data/lib/featurevisor/conditions.rb +63 -34
- data/lib/featurevisor/{logger.rb → diagnostics.rb} +19 -52
- data/lib/featurevisor/evaluate.rb +51 -50
- data/lib/featurevisor/{datafile_reader.rb → evaluation_data_provider.rb} +27 -16
- data/lib/featurevisor/events.rb +2 -2
- data/lib/featurevisor/instance.rb +74 -40
- data/lib/featurevisor/version.rb +1 -1
- data/lib/featurevisor.rb +4 -4
- metadata +3 -3
|
@@ -55,14 +55,15 @@ module Featurevisor
|
|
|
55
55
|
# Default: variation
|
|
56
56
|
if options.key?(:default_variation_value) &&
|
|
57
57
|
evaluation[:type] == "variation" &&
|
|
58
|
-
evaluation
|
|
58
|
+
!evaluation.key?(:variation_value) &&
|
|
59
|
+
!evaluation.key?(:variation)
|
|
59
60
|
evaluation[:variation_value] = options[:default_variation_value]
|
|
60
61
|
end
|
|
61
62
|
|
|
62
63
|
# Default: variable
|
|
63
64
|
if options.key?(:default_variable_value) &&
|
|
64
65
|
evaluation[:type] == "variable" &&
|
|
65
|
-
evaluation
|
|
66
|
+
!evaluation.key?(:variable_value)
|
|
66
67
|
evaluation[:variable_value] = options[:default_variable_value]
|
|
67
68
|
end
|
|
68
69
|
|
|
@@ -76,7 +77,7 @@ module Featurevisor
|
|
|
76
77
|
type = options[:type]
|
|
77
78
|
feature_key = options[:feature_key]
|
|
78
79
|
variable_key = options[:variable_key]
|
|
79
|
-
|
|
80
|
+
diagnostics = options[:diagnostics]
|
|
80
81
|
|
|
81
82
|
evaluation = {
|
|
82
83
|
type: type,
|
|
@@ -86,7 +87,7 @@ module Featurevisor
|
|
|
86
87
|
error: e
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
diagnostics.error("Error during evaluation", evaluation)
|
|
90
91
|
|
|
91
92
|
evaluation
|
|
92
93
|
end
|
|
@@ -100,8 +101,8 @@ module Featurevisor
|
|
|
100
101
|
feature_key = options[:feature_key]
|
|
101
102
|
variable_key = options[:variable_key]
|
|
102
103
|
context = options[:context]
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
diagnostics = options[:diagnostics]
|
|
105
|
+
datafile = options[:datafile]
|
|
105
106
|
sticky = options[:sticky]
|
|
106
107
|
modules_manager = options[:modules_manager]
|
|
107
108
|
evaluation = nil
|
|
@@ -120,7 +121,7 @@ module Featurevisor
|
|
|
120
121
|
reason: Featurevisor::EvaluationReason::DISABLED
|
|
121
122
|
}
|
|
122
123
|
|
|
123
|
-
feature =
|
|
124
|
+
feature = datafile.get_feature(feature_key)
|
|
124
125
|
|
|
125
126
|
# serve variable default value if feature is disabled (if explicitly specified)
|
|
126
127
|
if type == "variable"
|
|
@@ -156,7 +157,7 @@ module Featurevisor
|
|
|
156
157
|
end
|
|
157
158
|
|
|
158
159
|
# serve disabled variation value if feature is disabled (if explicitly specified)
|
|
159
|
-
if type == "variation" && feature && feature
|
|
160
|
+
if type == "variation" && feature && feature.key?(:disabledVariationValue)
|
|
160
161
|
evaluation = {
|
|
161
162
|
type: type,
|
|
162
163
|
feature_key: feature_key,
|
|
@@ -166,7 +167,7 @@ module Featurevisor
|
|
|
166
167
|
}
|
|
167
168
|
end
|
|
168
169
|
|
|
169
|
-
|
|
170
|
+
diagnostics.debug("feature is disabled", evaluation)
|
|
170
171
|
|
|
171
172
|
return evaluation
|
|
172
173
|
end
|
|
@@ -186,7 +187,7 @@ module Featurevisor
|
|
|
186
187
|
enabled: sticky_feature[:enabled]
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
|
|
190
|
+
diagnostics.debug("using sticky enabled", evaluation)
|
|
190
191
|
|
|
191
192
|
return evaluation
|
|
192
193
|
end
|
|
@@ -195,7 +196,7 @@ module Featurevisor
|
|
|
195
196
|
if type == "variation"
|
|
196
197
|
variation_value = sticky_feature[:variation]
|
|
197
198
|
|
|
198
|
-
|
|
199
|
+
if sticky_feature.key?(:variation)
|
|
199
200
|
evaluation = {
|
|
200
201
|
type: type,
|
|
201
202
|
feature_key: feature_key,
|
|
@@ -203,7 +204,7 @@ module Featurevisor
|
|
|
203
204
|
variation_value: variation_value
|
|
204
205
|
}
|
|
205
206
|
|
|
206
|
-
|
|
207
|
+
diagnostics.debug("using sticky variation", evaluation)
|
|
207
208
|
|
|
208
209
|
return evaluation
|
|
209
210
|
end
|
|
@@ -223,7 +224,7 @@ module Featurevisor
|
|
|
223
224
|
variable_value: variable_value
|
|
224
225
|
}
|
|
225
226
|
|
|
226
|
-
|
|
227
|
+
diagnostics.debug("using sticky variable", evaluation)
|
|
227
228
|
|
|
228
229
|
return evaluation
|
|
229
230
|
end
|
|
@@ -231,7 +232,7 @@ module Featurevisor
|
|
|
231
232
|
end
|
|
232
233
|
|
|
233
234
|
# Feature
|
|
234
|
-
feature = feature_key.is_a?(String) ?
|
|
235
|
+
feature = feature_key.is_a?(String) ? datafile.get_feature(feature_key) : feature_key
|
|
235
236
|
|
|
236
237
|
# feature: not found
|
|
237
238
|
unless feature
|
|
@@ -241,14 +242,14 @@ module Featurevisor
|
|
|
241
242
|
reason: Featurevisor::EvaluationReason::FEATURE_NOT_FOUND
|
|
242
243
|
}
|
|
243
244
|
|
|
244
|
-
|
|
245
|
+
diagnostics.warn("feature not found", evaluation)
|
|
245
246
|
|
|
246
247
|
return evaluation
|
|
247
248
|
end
|
|
248
249
|
|
|
249
250
|
# feature: deprecated
|
|
250
251
|
if type == "flag" && feature[:deprecated]
|
|
251
|
-
|
|
252
|
+
diagnostics.warn("feature is deprecated", { feature_key: feature_key })
|
|
252
253
|
end
|
|
253
254
|
|
|
254
255
|
# variableSchema
|
|
@@ -268,13 +269,13 @@ module Featurevisor
|
|
|
268
269
|
variable_key: variable_key
|
|
269
270
|
}
|
|
270
271
|
|
|
271
|
-
|
|
272
|
+
diagnostics.warn("variable schema not found", evaluation)
|
|
272
273
|
|
|
273
274
|
return evaluation
|
|
274
275
|
end
|
|
275
276
|
|
|
276
277
|
if variable_schema[:deprecated]
|
|
277
|
-
|
|
278
|
+
diagnostics.warn("variable is deprecated", {
|
|
278
279
|
feature_key: feature_key,
|
|
279
280
|
variable_key: variable_key
|
|
280
281
|
})
|
|
@@ -289,13 +290,13 @@ module Featurevisor
|
|
|
289
290
|
reason: Featurevisor::EvaluationReason::NO_VARIATIONS
|
|
290
291
|
}
|
|
291
292
|
|
|
292
|
-
|
|
293
|
+
diagnostics.warn("no variations", evaluation)
|
|
293
294
|
|
|
294
295
|
return evaluation
|
|
295
296
|
end
|
|
296
297
|
|
|
297
298
|
# Forced
|
|
298
|
-
force_result =
|
|
299
|
+
force_result = datafile.get_matched_force(feature, context)
|
|
299
300
|
force = force_result[:force]
|
|
300
301
|
force_index = force_result[:forceIndex]
|
|
301
302
|
|
|
@@ -311,7 +312,7 @@ module Featurevisor
|
|
|
311
312
|
enabled: force[:enabled]
|
|
312
313
|
}
|
|
313
314
|
|
|
314
|
-
|
|
315
|
+
diagnostics.debug("forced enabled found", evaluation)
|
|
315
316
|
|
|
316
317
|
return evaluation
|
|
317
318
|
end
|
|
@@ -330,7 +331,7 @@ module Featurevisor
|
|
|
330
331
|
variation: variation
|
|
331
332
|
}
|
|
332
333
|
|
|
333
|
-
|
|
334
|
+
diagnostics.debug("forced variation found", evaluation)
|
|
334
335
|
|
|
335
336
|
return evaluation
|
|
336
337
|
end
|
|
@@ -350,7 +351,7 @@ module Featurevisor
|
|
|
350
351
|
variable_value: variable_value
|
|
351
352
|
}
|
|
352
353
|
|
|
353
|
-
|
|
354
|
+
diagnostics.debug("forced variable", evaluation)
|
|
354
355
|
|
|
355
356
|
return evaluation
|
|
356
357
|
end
|
|
@@ -400,7 +401,7 @@ module Featurevisor
|
|
|
400
401
|
enabled: required_features_are_enabled
|
|
401
402
|
}
|
|
402
403
|
|
|
403
|
-
|
|
404
|
+
diagnostics.debug("required features not enabled", evaluation)
|
|
404
405
|
|
|
405
406
|
return evaluation
|
|
406
407
|
end
|
|
@@ -412,7 +413,7 @@ module Featurevisor
|
|
|
412
413
|
feature_key: feature_key,
|
|
413
414
|
bucket_by: feature[:bucketBy],
|
|
414
415
|
context: context,
|
|
415
|
-
|
|
416
|
+
diagnostics: diagnostics
|
|
416
417
|
})
|
|
417
418
|
|
|
418
419
|
# Run bucket key modules
|
|
@@ -438,13 +439,13 @@ module Featurevisor
|
|
|
438
439
|
matched_allocation = nil
|
|
439
440
|
|
|
440
441
|
if type != "flag"
|
|
441
|
-
matched_traffic =
|
|
442
|
+
matched_traffic = datafile.get_matched_traffic(feature[:traffic], context)
|
|
442
443
|
|
|
443
444
|
if matched_traffic
|
|
444
|
-
matched_allocation =
|
|
445
|
+
matched_allocation = datafile.get_matched_allocation(matched_traffic, bucket_value)
|
|
445
446
|
end
|
|
446
447
|
else
|
|
447
|
-
matched_traffic =
|
|
448
|
+
matched_traffic = datafile.get_matched_traffic(feature[:traffic], context)
|
|
448
449
|
end
|
|
449
450
|
|
|
450
451
|
if matched_traffic
|
|
@@ -461,7 +462,7 @@ module Featurevisor
|
|
|
461
462
|
enabled: false
|
|
462
463
|
}
|
|
463
464
|
|
|
464
|
-
|
|
465
|
+
diagnostics.debug("matched rule with 0 percentage", evaluation)
|
|
465
466
|
|
|
466
467
|
return evaluation
|
|
467
468
|
end
|
|
@@ -487,7 +488,7 @@ module Featurevisor
|
|
|
487
488
|
enabled: matched_traffic[:enabled].nil? ? true : matched_traffic[:enabled]
|
|
488
489
|
}
|
|
489
490
|
|
|
490
|
-
|
|
491
|
+
diagnostics.debug("matched", evaluation)
|
|
491
492
|
|
|
492
493
|
return evaluation
|
|
493
494
|
end
|
|
@@ -502,7 +503,7 @@ module Featurevisor
|
|
|
502
503
|
enabled: false
|
|
503
504
|
}
|
|
504
505
|
|
|
505
|
-
|
|
506
|
+
diagnostics.debug("not matched", evaluation)
|
|
506
507
|
|
|
507
508
|
return evaluation
|
|
508
509
|
end
|
|
@@ -520,7 +521,7 @@ module Featurevisor
|
|
|
520
521
|
enabled: matched_traffic[:enabled]
|
|
521
522
|
}
|
|
522
523
|
|
|
523
|
-
|
|
524
|
+
diagnostics.debug("override from rule", evaluation)
|
|
524
525
|
|
|
525
526
|
return evaluation
|
|
526
527
|
end
|
|
@@ -538,7 +539,7 @@ module Featurevisor
|
|
|
538
539
|
enabled: true
|
|
539
540
|
}
|
|
540
541
|
|
|
541
|
-
|
|
542
|
+
diagnostics.debug("matched traffic", evaluation)
|
|
542
543
|
|
|
543
544
|
return evaluation
|
|
544
545
|
end
|
|
@@ -562,7 +563,7 @@ module Featurevisor
|
|
|
562
563
|
variation: variation
|
|
563
564
|
}
|
|
564
565
|
|
|
565
|
-
|
|
566
|
+
diagnostics.debug("override from rule", evaluation)
|
|
566
567
|
|
|
567
568
|
return evaluation
|
|
568
569
|
end
|
|
@@ -584,7 +585,7 @@ module Featurevisor
|
|
|
584
585
|
variation: variation
|
|
585
586
|
}
|
|
586
587
|
|
|
587
|
-
|
|
588
|
+
diagnostics.debug("allocated variation", evaluation)
|
|
588
589
|
|
|
589
590
|
return evaluation
|
|
590
591
|
end
|
|
@@ -603,10 +604,10 @@ module Featurevisor
|
|
|
603
604
|
override_index = overrides.find_index do |o|
|
|
604
605
|
if o[:conditions]
|
|
605
606
|
conditions = o[:conditions].is_a?(String) && o[:conditions] != "*" ? JSON.parse(o[:conditions]) : o[:conditions]
|
|
606
|
-
|
|
607
|
+
datafile.all_conditions_are_matched(conditions, context)
|
|
607
608
|
elsif o[:segments]
|
|
608
|
-
segments =
|
|
609
|
-
|
|
609
|
+
segments = datafile.parse_segments_if_stringified(o[:segments])
|
|
610
|
+
datafile.all_segments_are_matched(segments, context)
|
|
610
611
|
else
|
|
611
612
|
false
|
|
612
613
|
end
|
|
@@ -629,7 +630,7 @@ module Featurevisor
|
|
|
629
630
|
variable_override_index: override_index
|
|
630
631
|
}
|
|
631
632
|
|
|
632
|
-
|
|
633
|
+
diagnostics.debug("variable override from rule", evaluation)
|
|
633
634
|
|
|
634
635
|
return evaluation
|
|
635
636
|
end
|
|
@@ -652,7 +653,7 @@ module Featurevisor
|
|
|
652
653
|
variable_value: variable_value
|
|
653
654
|
}
|
|
654
655
|
|
|
655
|
-
|
|
656
|
+
diagnostics.debug("override from rule", evaluation)
|
|
656
657
|
|
|
657
658
|
return evaluation
|
|
658
659
|
end
|
|
@@ -677,10 +678,10 @@ module Featurevisor
|
|
|
677
678
|
override_index = overrides.find_index do |o|
|
|
678
679
|
if o[:conditions]
|
|
679
680
|
conditions = o[:conditions].is_a?(String) && o[:conditions] != "*" ? JSON.parse(o[:conditions]) : o[:conditions]
|
|
680
|
-
|
|
681
|
+
datafile.all_conditions_are_matched(conditions, context)
|
|
681
682
|
elsif o[:segments]
|
|
682
|
-
segments =
|
|
683
|
-
|
|
683
|
+
segments = datafile.parse_segments_if_stringified(o[:segments])
|
|
684
|
+
datafile.all_segments_are_matched(segments, context)
|
|
684
685
|
else
|
|
685
686
|
false
|
|
686
687
|
end
|
|
@@ -702,7 +703,7 @@ module Featurevisor
|
|
|
702
703
|
variable_override_index: override_index
|
|
703
704
|
}
|
|
704
705
|
|
|
705
|
-
|
|
706
|
+
diagnostics.debug("variable override from variation", evaluation)
|
|
706
707
|
|
|
707
708
|
return evaluation
|
|
708
709
|
end
|
|
@@ -725,7 +726,7 @@ module Featurevisor
|
|
|
725
726
|
variable_value: variable_value
|
|
726
727
|
}
|
|
727
728
|
|
|
728
|
-
|
|
729
|
+
diagnostics.debug("allocated variable", evaluation)
|
|
729
730
|
|
|
730
731
|
return evaluation
|
|
731
732
|
end
|
|
@@ -742,7 +743,7 @@ module Featurevisor
|
|
|
742
743
|
bucket_value: bucket_value
|
|
743
744
|
}
|
|
744
745
|
|
|
745
|
-
|
|
746
|
+
diagnostics.debug("no matched variation", evaluation)
|
|
746
747
|
|
|
747
748
|
return evaluation
|
|
748
749
|
end
|
|
@@ -760,7 +761,7 @@ module Featurevisor
|
|
|
760
761
|
variable_value: variable_schema[:defaultValue]
|
|
761
762
|
}
|
|
762
763
|
|
|
763
|
-
|
|
764
|
+
diagnostics.debug("using default value", evaluation)
|
|
764
765
|
|
|
765
766
|
return evaluation
|
|
766
767
|
end
|
|
@@ -774,7 +775,7 @@ module Featurevisor
|
|
|
774
775
|
bucket_value: bucket_value
|
|
775
776
|
}
|
|
776
777
|
|
|
777
|
-
|
|
778
|
+
diagnostics.debug("variable not found", evaluation)
|
|
778
779
|
|
|
779
780
|
return evaluation
|
|
780
781
|
end
|
|
@@ -788,7 +789,7 @@ module Featurevisor
|
|
|
788
789
|
enabled: false
|
|
789
790
|
}
|
|
790
791
|
|
|
791
|
-
|
|
792
|
+
diagnostics.debug("nothing matched", evaluation)
|
|
792
793
|
|
|
793
794
|
evaluation
|
|
794
795
|
rescue => e
|
|
@@ -800,7 +801,7 @@ module Featurevisor
|
|
|
800
801
|
error: e
|
|
801
802
|
}
|
|
802
803
|
|
|
803
|
-
|
|
804
|
+
diagnostics.error("Error during evaluation", evaluation)
|
|
804
805
|
|
|
805
806
|
evaluation
|
|
806
807
|
end
|
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
5
|
module Featurevisor
|
|
6
|
-
#
|
|
7
|
-
class
|
|
8
|
-
attr_reader :schema_version, :revision, :featurevisor_version, :segments, :features, :
|
|
6
|
+
# Private datafile and matching adapter used by the evaluator.
|
|
7
|
+
class InstanceEvaluationDataProvider
|
|
8
|
+
attr_reader :schema_version, :revision, :featurevisor_version, :segments, :features, :diagnostics, :regex_cache
|
|
9
9
|
|
|
10
|
-
# Initialize a new
|
|
11
|
-
# @param options [Hash] Options hash containing datafile and
|
|
10
|
+
# Initialize a new evaluation data provider.
|
|
11
|
+
# @param options [Hash] Options hash containing datafile and diagnostics
|
|
12
12
|
# @option options [Hash] :datafile Datafile content
|
|
13
|
-
# @option options [
|
|
13
|
+
# @option options [DiagnosticReporter] :diagnostics Diagnostic reporter
|
|
14
14
|
def initialize(options)
|
|
15
15
|
datafile = options[:datafile]
|
|
16
|
-
@
|
|
16
|
+
@diagnostics = options[:diagnostics]
|
|
17
17
|
|
|
18
18
|
@schema_version = datafile[:schemaVersion]
|
|
19
19
|
@revision = datafile[:revision]
|
|
@@ -133,7 +133,15 @@ module Featurevisor
|
|
|
133
133
|
|
|
134
134
|
return @regex_cache[cache_key] if @regex_cache[cache_key]
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
ruby_flags = 0
|
|
137
|
+
ruby_flags |= Regexp::IGNORECASE if flags.include?("i")
|
|
138
|
+
# Ruby's MULTILINE option controls dot matching newlines, which is the
|
|
139
|
+
# JavaScript `s` behavior. Ruby anchors already operate per line.
|
|
140
|
+
ruby_flags |= Regexp::MULTILINE if flags.include?("s")
|
|
141
|
+
invalid_flags = flags.delete("gimsuy")
|
|
142
|
+
raise ArgumentError, "invalid regular expression flags: #{invalid_flags}" unless invalid_flags.empty?
|
|
143
|
+
|
|
144
|
+
regex = Regexp.new(regex_string, ruby_flags)
|
|
137
145
|
@regex_cache[cache_key] = regex
|
|
138
146
|
@regex_cache[cache_key]
|
|
139
147
|
end
|
|
@@ -155,12 +163,11 @@ module Featurevisor
|
|
|
155
163
|
result = Conditions.condition_is_matched(conditions, context, get_regex_proc)
|
|
156
164
|
return result
|
|
157
165
|
rescue => e
|
|
158
|
-
@
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
166
|
+
@diagnostics.warn(e.message, {
|
|
167
|
+
code: "condition_match_error",
|
|
168
|
+
error: e,
|
|
169
|
+
condition: conditions,
|
|
170
|
+
context: context
|
|
164
171
|
})
|
|
165
172
|
return false
|
|
166
173
|
end
|
|
@@ -183,10 +190,12 @@ module Featurevisor
|
|
|
183
190
|
end
|
|
184
191
|
|
|
185
192
|
if conditions.is_a?(Hash) && conditions[:not] && conditions[:not].is_a?(Array)
|
|
193
|
+
return false if conditions[:not].empty?
|
|
186
194
|
return !all_conditions_are_matched({ and: conditions[:not] }, context)
|
|
187
195
|
end
|
|
188
196
|
|
|
189
197
|
if conditions.is_a?(Hash) && conditions["not"] && conditions["not"].is_a?(Array)
|
|
198
|
+
return false if conditions["not"].empty?
|
|
190
199
|
return !all_conditions_are_matched({ "and" => conditions["not"] }, context)
|
|
191
200
|
end
|
|
192
201
|
|
|
@@ -244,10 +253,12 @@ module Featurevisor
|
|
|
244
253
|
end
|
|
245
254
|
|
|
246
255
|
if group_segments[:not] && group_segments[:not].is_a?(Array)
|
|
256
|
+
return false if group_segments[:not].empty?
|
|
247
257
|
return !all_segments_are_matched({ and: group_segments[:not] }, context)
|
|
248
258
|
end
|
|
249
259
|
|
|
250
260
|
if group_segments["not"] && group_segments["not"].is_a?(Array)
|
|
261
|
+
return false if group_segments["not"].empty?
|
|
251
262
|
return !all_segments_are_matched({ "and" => group_segments["not"] }, context)
|
|
252
263
|
end
|
|
253
264
|
|
|
@@ -333,7 +344,7 @@ module Featurevisor
|
|
|
333
344
|
begin
|
|
334
345
|
JSON.parse(conditions)
|
|
335
346
|
rescue => e
|
|
336
|
-
@
|
|
347
|
+
@diagnostics.error("Error parsing conditions", {
|
|
337
348
|
error: e,
|
|
338
349
|
details: {
|
|
339
350
|
conditions: conditions
|
|
@@ -355,5 +366,5 @@ module Featurevisor
|
|
|
355
366
|
end
|
|
356
367
|
end
|
|
357
368
|
|
|
358
|
-
private_constant :
|
|
369
|
+
private_constant :InstanceEvaluationDataProvider
|
|
359
370
|
end
|
data/lib/featurevisor/events.rb
CHANGED
|
@@ -21,8 +21,8 @@ module Featurevisor
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
# Get parameters for datafile set event
|
|
24
|
-
# @param previous_reader [
|
|
25
|
-
# @param new_reader [
|
|
24
|
+
# @param previous_reader [InstanceEvaluationDataProvider] Previous datafile
|
|
25
|
+
# @param new_reader [InstanceEvaluationDataProvider] New datafile
|
|
26
26
|
# @return [Hash] Event parameters
|
|
27
27
|
def self.get_params_for_datafile_set_event(previous_reader, new_reader, replace = false)
|
|
28
28
|
previous_revision = previous_reader.get_revision
|