ff-ruby-server-sdk 0.0.2 → 1.0.2.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.run/sdk_test.rb.run.xml +3 -3
- data/CHANGELOG.md +12 -2
- data/Gemfile +17 -3
- data/README.md +155 -7
- data/api.yaml +736 -0
- data/example/example.rb +100 -3
- data/lib/ff/ruby/server/generated/lib/openapi_client/api/client_api.rb +545 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/api/metrics_api.rb +89 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/api_client.rb +390 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/api_error.rb +57 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/configuration.rb +282 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/authentication_request.rb +232 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/authentication_request_target.rb +250 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/authentication_response.rb +223 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/clause.rb +281 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/distribution.rb +239 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/error.rb +237 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/evaluation.rb +260 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/feature_config.rb +418 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/feature_state.rb +37 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/key_value.rb +237 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/metrics.rb +231 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/metrics_data.rb +303 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/pagination.rb +274 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/prerequisite.rb +239 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/segment.rb +320 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/serve.rb +227 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/serving_rule.rb +267 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/tag.rb +233 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/target.rb +331 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/target_data.rb +253 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/target_map.rb +232 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/variation.rb +255 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/variation_map.rb +245 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/models/weighted_variation.rb +237 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client/version.rb +15 -0
- data/lib/ff/ruby/server/generated/lib/openapi_client.rb +65 -0
- data/lib/ff/ruby/server/sdk/api/auth_service.rb +91 -0
- data/lib/ff/ruby/server/sdk/api/cf_client.rb +93 -0
- data/lib/ff/ruby/server/sdk/api/client_callback.rb +45 -0
- data/lib/ff/ruby/server/sdk/api/config.rb +140 -0
- data/lib/ff/ruby/server/sdk/api/config_builder.rb +116 -0
- data/lib/ff/ruby/server/sdk/api/default_cache.rb +112 -0
- data/lib/ff/ruby/server/sdk/api/evaluation.rb +29 -0
- data/lib/ff/ruby/server/sdk/api/evaluator.rb +526 -0
- data/lib/ff/ruby/server/sdk/api/file_map_store.rb +60 -0
- data/lib/ff/ruby/server/sdk/api/flag_evaluate_callback.rb +13 -0
- data/lib/ff/ruby/server/sdk/api/inner_client.rb +311 -0
- data/lib/ff/ruby/server/sdk/api/inner_client_flag_evaluate_callback.rb +30 -0
- data/lib/ff/ruby/server/sdk/api/inner_client_metrics_callback.rb +33 -0
- data/lib/ff/ruby/server/sdk/api/inner_client_repository_callback.rb +44 -0
- data/lib/ff/ruby/server/sdk/api/inner_client_updater.rb +63 -0
- data/lib/ff/ruby/server/sdk/api/metrics_callback.rb +19 -0
- data/lib/ff/ruby/server/sdk/api/metrics_event.rb +16 -0
- data/lib/ff/ruby/server/sdk/api/metrics_processor.rb +297 -0
- data/lib/ff/ruby/server/sdk/api/operators.rb +20 -0
- data/lib/ff/ruby/server/sdk/api/polling_processor.rb +164 -0
- data/lib/ff/ruby/server/sdk/api/repository_callback.rb +28 -0
- data/lib/ff/ruby/server/sdk/api/storage_repository.rb +263 -0
- data/lib/ff/ruby/server/sdk/api/summary_metrics.rb +16 -0
- data/lib/ff/ruby/server/sdk/api/update_processor.rb +149 -0
- data/lib/ff/ruby/server/sdk/common/cache.rb +27 -0
- data/lib/ff/ruby/server/sdk/common/closeable.rb +7 -0
- data/lib/ff/ruby/server/sdk/common/destroyable.rb +12 -0
- data/lib/ff/ruby/server/sdk/common/repository.rb +45 -0
- data/lib/ff/ruby/server/sdk/common/storage.rb +29 -0
- data/lib/ff/ruby/server/sdk/connector/connector.rb +44 -0
- data/lib/ff/ruby/server/sdk/connector/events.rb +118 -0
- data/lib/ff/ruby/server/sdk/connector/harness_connector.rb +236 -0
- data/lib/ff/ruby/server/sdk/connector/service.rb +19 -0
- data/lib/ff/ruby/server/sdk/connector/updater.rb +32 -0
- data/lib/ff/ruby/server/sdk/dto/message.rb +13 -0
- data/lib/ff/ruby/server/sdk/dto/target.rb +24 -0
- data/lib/ff/ruby/server/sdk/version.rb +2 -1
- data/lib/ff/ruby/server/sdk.rb +39 -3
- data/openapitools.json +7 -0
- data/scripts/install.sh +8 -2
- data/scripts/openapi.sh +76 -0
- data/scripts/publish.sh +1 -1
- data/scripts/sdk_specs.sh +1 -1
- metadata +263 -11
- data/lib/ff/ruby/server/sdk/cf_client.rb +0 -6
@@ -0,0 +1,526 @@
|
|
1
|
+
require "json"
|
2
|
+
require "murmurhash3"
|
3
|
+
|
4
|
+
require_relative "evaluation"
|
5
|
+
require_relative "../common/repository"
|
6
|
+
|
7
|
+
class Evaluator < Evaluation
|
8
|
+
|
9
|
+
def initialize(repository, logger = nil)
|
10
|
+
|
11
|
+
unless repository.kind_of?(Repository)
|
12
|
+
|
13
|
+
raise "The 'repository' parameter must be of '" + Repository.to_s + "' data type"
|
14
|
+
end
|
15
|
+
|
16
|
+
if logger != nil
|
17
|
+
|
18
|
+
@logger = logger
|
19
|
+
else
|
20
|
+
|
21
|
+
@logger = Logger.new(STDOUT)
|
22
|
+
end
|
23
|
+
|
24
|
+
@repository = repository
|
25
|
+
end
|
26
|
+
|
27
|
+
def bool_variation(identifier, target, default_value, callback)
|
28
|
+
|
29
|
+
variation = evaluate(identifier, target, "boolean", callback)
|
30
|
+
|
31
|
+
if variation != nil
|
32
|
+
|
33
|
+
return variation.value == "true"
|
34
|
+
end
|
35
|
+
|
36
|
+
default_value
|
37
|
+
end
|
38
|
+
|
39
|
+
def string_variation(identifier, target, default_value, callback)
|
40
|
+
|
41
|
+
variation = evaluate(identifier, target, "string", callback)
|
42
|
+
|
43
|
+
if variation != nil
|
44
|
+
|
45
|
+
return variation.value
|
46
|
+
end
|
47
|
+
|
48
|
+
default_value
|
49
|
+
end
|
50
|
+
|
51
|
+
def number_variation(identifier, target, default_value, callback)
|
52
|
+
|
53
|
+
variation = evaluate(identifier, target, "int", callback)
|
54
|
+
|
55
|
+
if variation != nil
|
56
|
+
|
57
|
+
return variation.value.to_i
|
58
|
+
end
|
59
|
+
|
60
|
+
default_value
|
61
|
+
end
|
62
|
+
|
63
|
+
def json_variation(identifier, target, default_value, callback)
|
64
|
+
|
65
|
+
variation = evaluate(identifier, target, "json", callback)
|
66
|
+
|
67
|
+
if variation != nil
|
68
|
+
|
69
|
+
return JSON.parse(variation.value)
|
70
|
+
end
|
71
|
+
|
72
|
+
default_value
|
73
|
+
end
|
74
|
+
|
75
|
+
def evaluate(identifier, target, expected, callback)
|
76
|
+
|
77
|
+
if callback != nil
|
78
|
+
|
79
|
+
unless callback.kind_of?(FlagEvaluateCallback)
|
80
|
+
|
81
|
+
raise "The 'callback' parameter must be of '" + FlagEvaluateCallback.to_s + "' data type"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
flag = @repository.get_flag(identifier)
|
86
|
+
|
87
|
+
if flag != nil && flag.kind == expected
|
88
|
+
|
89
|
+
unless flag.prerequisites.empty?
|
90
|
+
|
91
|
+
pre_req = check_pre_requisite(flag, target)
|
92
|
+
|
93
|
+
unless pre_req
|
94
|
+
|
95
|
+
return find_variation(flag.variations, flag.off_variation)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
variation = evaluate_flag(flag, target)
|
100
|
+
|
101
|
+
if variation != nil
|
102
|
+
|
103
|
+
if callback != nil
|
104
|
+
|
105
|
+
callback.process_evaluation(flag, target, variation)
|
106
|
+
end
|
107
|
+
|
108
|
+
return variation
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
115
|
+
protected
|
116
|
+
|
117
|
+
def get_attr_value(target, attribute)
|
118
|
+
|
119
|
+
if attribute != nil && !attribute.empty?
|
120
|
+
|
121
|
+
if target.respond_to?(attribute, :include_private)
|
122
|
+
|
123
|
+
@logger.debug "The attribute " + attribute.to_s + " exists (1)"
|
124
|
+
|
125
|
+
return target.send(attribute)
|
126
|
+
else
|
127
|
+
|
128
|
+
result = target.attributes.key?(attribute)
|
129
|
+
|
130
|
+
if result == nil
|
131
|
+
|
132
|
+
@logger.debug "The attribute " + attribute.to_s + " does not exist"
|
133
|
+
|
134
|
+
else
|
135
|
+
|
136
|
+
@logger.debug "The attribute " + attribute.to_s + " exists (2)"
|
137
|
+
end
|
138
|
+
|
139
|
+
return result
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
@logger.debug "The passed attribute is empty"
|
144
|
+
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
|
148
|
+
def find_variation(variations, identifier)
|
149
|
+
|
150
|
+
if identifier != nil && !identifier.empty?
|
151
|
+
|
152
|
+
variations.each do |v|
|
153
|
+
|
154
|
+
if v.identifier == identifier
|
155
|
+
|
156
|
+
return v
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
|
164
|
+
def get_normalized_number(property, bucket_by)
|
165
|
+
|
166
|
+
joined = property.to_s + ":" + bucket_by.to_s
|
167
|
+
hash = MurmurHash3::V32.str_hash(joined, joined.length)
|
168
|
+
(hash % 100) + 1
|
169
|
+
end
|
170
|
+
|
171
|
+
def is_enabled(target, bucket_by, percentage)
|
172
|
+
|
173
|
+
property = get_attr_value(target, bucket_by)
|
174
|
+
|
175
|
+
if property != nil
|
176
|
+
|
177
|
+
bucket_id = get_normalized_number(property, bucket_by)
|
178
|
+
|
179
|
+
return percentage > 0 && bucket_id <= percentage
|
180
|
+
end
|
181
|
+
|
182
|
+
false
|
183
|
+
end
|
184
|
+
|
185
|
+
def evaluate_distribution(distribution, target)
|
186
|
+
|
187
|
+
if distribution != nil
|
188
|
+
|
189
|
+
variation = nil
|
190
|
+
|
191
|
+
distribution.variations.each do |weighted_variation|
|
192
|
+
|
193
|
+
variation = weighted_variation.variation
|
194
|
+
|
195
|
+
if is_enabled(target, distribution.bucket_by, weighted_variation.weight)
|
196
|
+
|
197
|
+
return variation
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
return variation
|
202
|
+
end
|
203
|
+
|
204
|
+
nil
|
205
|
+
end
|
206
|
+
|
207
|
+
def evaluate_clauses(clauses, target)
|
208
|
+
|
209
|
+
clauses.each do |clause|
|
210
|
+
|
211
|
+
unless evaluate_clause(clause, target)
|
212
|
+
|
213
|
+
return false
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
true
|
218
|
+
end
|
219
|
+
|
220
|
+
def evaluate_clause(clause, target)
|
221
|
+
|
222
|
+
if clause == nil
|
223
|
+
|
224
|
+
return false
|
225
|
+
end
|
226
|
+
|
227
|
+
operator = clause.op
|
228
|
+
|
229
|
+
if operator == nil || operator.empty?
|
230
|
+
|
231
|
+
return false
|
232
|
+
end
|
233
|
+
|
234
|
+
if operator == "segmentMatch"
|
235
|
+
|
236
|
+
return is_target_included_or_excluded_in_segment(clause.values, target)
|
237
|
+
end
|
238
|
+
|
239
|
+
if clause.values.empty?
|
240
|
+
|
241
|
+
return false
|
242
|
+
end
|
243
|
+
|
244
|
+
value = clause.values[0]
|
245
|
+
attr_value = get_attr_value(target, clause.attribute)
|
246
|
+
|
247
|
+
if attr_value == nil
|
248
|
+
|
249
|
+
return false
|
250
|
+
end
|
251
|
+
|
252
|
+
object = attr_value.to_s
|
253
|
+
|
254
|
+
if operator == "starts_with"
|
255
|
+
|
256
|
+
return object.start_with?(value)
|
257
|
+
end
|
258
|
+
|
259
|
+
if operator == "ends_with"
|
260
|
+
|
261
|
+
return object.end_with?(value)
|
262
|
+
end
|
263
|
+
|
264
|
+
if operator == "match"
|
265
|
+
|
266
|
+
match = object.match?(value)
|
267
|
+
return match != nil && !match.empty?
|
268
|
+
end
|
269
|
+
|
270
|
+
if operator == "contains"
|
271
|
+
|
272
|
+
return object.include?(value)
|
273
|
+
end
|
274
|
+
|
275
|
+
if operator == "equal"
|
276
|
+
|
277
|
+
return object.casecmp?(value)
|
278
|
+
end
|
279
|
+
|
280
|
+
if operator == "equal_sensitive"
|
281
|
+
|
282
|
+
return object == value
|
283
|
+
end
|
284
|
+
|
285
|
+
if operator == "in"
|
286
|
+
|
287
|
+
return object.include?(value)
|
288
|
+
end
|
289
|
+
|
290
|
+
if operator == "segmentMatch"
|
291
|
+
|
292
|
+
return is_target_included_or_excluded_in_segment(clause.values, target)
|
293
|
+
end
|
294
|
+
|
295
|
+
false
|
296
|
+
end
|
297
|
+
|
298
|
+
def is_target_included_or_excluded_in_segment(segment_list, target)
|
299
|
+
|
300
|
+
segment_list.each do |segment_identifier|
|
301
|
+
|
302
|
+
segment = @repository.get_segment(segment_identifier)
|
303
|
+
|
304
|
+
if segment != nil
|
305
|
+
|
306
|
+
if is_target_in_list(target, segment.excluded)
|
307
|
+
|
308
|
+
@logger.debug "Target " + target.name.to_s + " excluded from segment " + segment.name.to_s + " via exclude list"
|
309
|
+
|
310
|
+
return false
|
311
|
+
end
|
312
|
+
|
313
|
+
if is_target_in_list(target, segment.included)
|
314
|
+
|
315
|
+
@logger.debug "Target " + target.name.to_s + " included in segment " + segment.name.to_s + " via include list"
|
316
|
+
|
317
|
+
return true
|
318
|
+
end
|
319
|
+
|
320
|
+
rules = segment.rules
|
321
|
+
|
322
|
+
if rules != nil && !rules.empty? && evaluate_clauses(rules, target)
|
323
|
+
|
324
|
+
@logger.debug "Target " + target.name.to_s + " included in segment " + segment.name.to_s + " via rules"
|
325
|
+
|
326
|
+
return true
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
false
|
332
|
+
end
|
333
|
+
|
334
|
+
def evaluate_rules(serving_rules, target)
|
335
|
+
|
336
|
+
if target == nil || serving_rules == nil
|
337
|
+
|
338
|
+
return nil
|
339
|
+
end
|
340
|
+
|
341
|
+
sorted = serving_rules.sort do |a, b|
|
342
|
+
|
343
|
+
b.priority <=> a.priority
|
344
|
+
end
|
345
|
+
|
346
|
+
sorted.each do |rule|
|
347
|
+
|
348
|
+
next unless evaluate_rule(rule, target)
|
349
|
+
|
350
|
+
if rule.serve.distribution != nil
|
351
|
+
|
352
|
+
return evaluate_distribution(rule.serve.distribution, target)
|
353
|
+
end
|
354
|
+
|
355
|
+
if rule.serve.variation != nil
|
356
|
+
|
357
|
+
return rule.serve.variation
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
nil
|
362
|
+
end
|
363
|
+
|
364
|
+
def evaluate_rule(serving_rule, target)
|
365
|
+
|
366
|
+
evaluate_clauses(serving_rule.clauses, target)
|
367
|
+
end
|
368
|
+
|
369
|
+
def evaluate_variation_map(variation_maps, target)
|
370
|
+
|
371
|
+
if target == nil
|
372
|
+
|
373
|
+
return nil
|
374
|
+
end
|
375
|
+
|
376
|
+
variation_maps.each do |variation_map|
|
377
|
+
|
378
|
+
targets = variation_map.targets
|
379
|
+
|
380
|
+
if targets != nil
|
381
|
+
|
382
|
+
found = nil
|
383
|
+
|
384
|
+
targets.each do |t|
|
385
|
+
|
386
|
+
if t.identifier != nil && t.identifier == target.identifier
|
387
|
+
|
388
|
+
found = t
|
389
|
+
break
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
if found != nil
|
394
|
+
|
395
|
+
return variation_map.variation
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
segment_identifiers = variation_map.target_segments
|
400
|
+
|
401
|
+
if segment_identifiers != nil && is_target_included_or_excluded_in_segment(segment_identifiers, target)
|
402
|
+
|
403
|
+
return variation_map.variation
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
nil
|
408
|
+
end
|
409
|
+
|
410
|
+
def evaluate_flag(feature_config, target)
|
411
|
+
|
412
|
+
variation = feature_config.off_variation
|
413
|
+
|
414
|
+
if feature_config.state == OpenapiClient::FeatureState::ON
|
415
|
+
|
416
|
+
variation = nil
|
417
|
+
|
418
|
+
if feature_config.variation_to_target_map != nil
|
419
|
+
|
420
|
+
variation = evaluate_variation_map(feature_config.variation_to_target_map, target)
|
421
|
+
end
|
422
|
+
|
423
|
+
if variation == nil
|
424
|
+
|
425
|
+
variation = evaluate_rules(feature_config.rules, target)
|
426
|
+
end
|
427
|
+
|
428
|
+
if variation == nil
|
429
|
+
|
430
|
+
variation = evaluate_distribution(feature_config.default_serve.distribution, target)
|
431
|
+
end
|
432
|
+
|
433
|
+
if variation == nil
|
434
|
+
|
435
|
+
variation = feature_config.default_serve.variation
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
if variation != nil
|
440
|
+
|
441
|
+
return find_variation(feature_config.variations, variation)
|
442
|
+
end
|
443
|
+
|
444
|
+
nil
|
445
|
+
end
|
446
|
+
|
447
|
+
def check_pre_requisite(parent_feature_config, target)
|
448
|
+
|
449
|
+
prerequisites = parent_feature_config.prerequisites
|
450
|
+
|
451
|
+
if prerequisites != nil && !prerequisites.empty?
|
452
|
+
|
453
|
+
@logger.debug "Checking pre requisites " + prerequisites.to_s + " of parent feature " + parent_feature_config.feature.to_s
|
454
|
+
|
455
|
+
prerequisites.each do |pqs|
|
456
|
+
|
457
|
+
pre_req_feature = pqs.feature
|
458
|
+
|
459
|
+
pre_req_feature_config = @repository.get_flag(pre_req_feature)
|
460
|
+
|
461
|
+
if pre_req_feature_config == nil
|
462
|
+
|
463
|
+
@logger.debug "Could not retrieve the pre requisite details of feature flag: " + pre_req_feature.to_s
|
464
|
+
|
465
|
+
return true
|
466
|
+
end
|
467
|
+
|
468
|
+
pre_req_evaluated_variation = evaluate_flag(pre_req_feature_config, target)
|
469
|
+
|
470
|
+
if pre_req_evaluated_variation == nil
|
471
|
+
|
472
|
+
@logger.debug "Could not evaluate the prerequisite details of feature flag: " + pre_req_feature.to_s
|
473
|
+
|
474
|
+
return true
|
475
|
+
end
|
476
|
+
|
477
|
+
@logger.debug "Pre requisite flag " + pre_req_feature_config.feature + " has variation " +
|
478
|
+
pre_req_evaluated_variation.to_s + " for target " + target.to_s
|
479
|
+
|
480
|
+
valid_pre_req_variations = pqs.variations
|
481
|
+
|
482
|
+
@logger.debug "Pre requisite flag " + pre_req_feature_config.to_s + " should have the variations " +
|
483
|
+
valid_pre_req_variations.to_s
|
484
|
+
|
485
|
+
none_match = true
|
486
|
+
|
487
|
+
valid_pre_req_variations.each do |element|
|
488
|
+
|
489
|
+
if element.include?(pre_req_evaluated_variation.value)
|
490
|
+
|
491
|
+
none_match = false
|
492
|
+
break
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
if none_match
|
497
|
+
|
498
|
+
return false
|
499
|
+
else
|
500
|
+
|
501
|
+
return check_pre_requisite(pre_req_feature_config, target)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
true
|
507
|
+
end
|
508
|
+
|
509
|
+
private
|
510
|
+
|
511
|
+
def is_target_in_list(target, list_of_targets)
|
512
|
+
|
513
|
+
if list_of_targets != nil
|
514
|
+
|
515
|
+
list_of_targets.each do |included_target|
|
516
|
+
|
517
|
+
if included_target.identifier.include?(target.identifier)
|
518
|
+
|
519
|
+
return true
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
false
|
525
|
+
end
|
526
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "moneta"
|
2
|
+
require_relative "../common/storage"
|
3
|
+
|
4
|
+
class FileMapStore < Storage
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
|
8
|
+
@keys = Set[]
|
9
|
+
@store = Moneta.new(:File, dir: "moneta")
|
10
|
+
end
|
11
|
+
|
12
|
+
def set(key, value)
|
13
|
+
|
14
|
+
check_init
|
15
|
+
|
16
|
+
@store[key] = value
|
17
|
+
keys.add(key)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(key)
|
21
|
+
|
22
|
+
check_init
|
23
|
+
|
24
|
+
@store[key]
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete(key)
|
28
|
+
|
29
|
+
check_init
|
30
|
+
|
31
|
+
@store.delete(key)
|
32
|
+
keys.delete(key)
|
33
|
+
end
|
34
|
+
|
35
|
+
def keys
|
36
|
+
|
37
|
+
check_init
|
38
|
+
|
39
|
+
@keys
|
40
|
+
end
|
41
|
+
|
42
|
+
def close
|
43
|
+
|
44
|
+
if @store != nil
|
45
|
+
|
46
|
+
@store.close
|
47
|
+
@keys = Set[]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def check_init
|
54
|
+
|
55
|
+
if @store == nil
|
56
|
+
|
57
|
+
raise "Not initialized"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|