launchdarkly-server-sdk 6.4.0 → 7.0.1
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/lib/ldclient-rb/config.rb +102 -56
- data/lib/ldclient-rb/context.rb +487 -0
- data/lib/ldclient-rb/evaluation_detail.rb +20 -20
- data/lib/ldclient-rb/events.rb +77 -132
- data/lib/ldclient-rb/flags_state.rb +4 -4
- data/lib/ldclient-rb/impl/big_segments.rb +17 -17
- data/lib/ldclient-rb/impl/context.rb +96 -0
- data/lib/ldclient-rb/impl/context_filter.rb +145 -0
- data/lib/ldclient-rb/impl/diagnostic_events.rb +9 -10
- data/lib/ldclient-rb/impl/evaluator.rb +379 -131
- data/lib/ldclient-rb/impl/evaluator_bucketing.rb +40 -41
- data/lib/ldclient-rb/impl/evaluator_helpers.rb +31 -34
- data/lib/ldclient-rb/impl/evaluator_operators.rb +26 -55
- data/lib/ldclient-rb/impl/event_sender.rb +6 -6
- data/lib/ldclient-rb/impl/event_summarizer.rb +12 -7
- data/lib/ldclient-rb/impl/event_types.rb +18 -30
- data/lib/ldclient-rb/impl/integrations/consul_impl.rb +7 -7
- data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +29 -29
- data/lib/ldclient-rb/impl/integrations/file_data_source.rb +8 -8
- data/lib/ldclient-rb/impl/integrations/redis_impl.rb +92 -12
- data/lib/ldclient-rb/impl/model/clause.rb +45 -0
- data/lib/ldclient-rb/impl/model/feature_flag.rb +232 -0
- data/lib/ldclient-rb/impl/model/preprocessed_data.rb +8 -121
- data/lib/ldclient-rb/impl/model/segment.rb +132 -0
- data/lib/ldclient-rb/impl/model/serialization.rb +52 -12
- data/lib/ldclient-rb/impl/repeating_task.rb +1 -1
- data/lib/ldclient-rb/impl/store_data_set_sorter.rb +2 -2
- data/lib/ldclient-rb/impl/unbounded_pool.rb +1 -1
- data/lib/ldclient-rb/impl/util.rb +2 -2
- data/lib/ldclient-rb/in_memory_store.rb +2 -2
- data/lib/ldclient-rb/integrations/consul.rb +1 -1
- data/lib/ldclient-rb/integrations/dynamodb.rb +1 -1
- data/lib/ldclient-rb/integrations/file_data.rb +3 -3
- data/lib/ldclient-rb/integrations/redis.rb +4 -4
- data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +218 -62
- data/lib/ldclient-rb/integrations/test_data.rb +16 -12
- data/lib/ldclient-rb/integrations/util/store_wrapper.rb +9 -9
- data/lib/ldclient-rb/interfaces.rb +14 -14
- data/lib/ldclient-rb/ldclient.rb +94 -144
- data/lib/ldclient-rb/memoized_value.rb +1 -1
- data/lib/ldclient-rb/non_blocking_thread_pool.rb +1 -1
- data/lib/ldclient-rb/polling.rb +2 -2
- data/lib/ldclient-rb/reference.rb +274 -0
- data/lib/ldclient-rb/requestor.rb +5 -5
- data/lib/ldclient-rb/stream.rb +7 -8
- data/lib/ldclient-rb/util.rb +4 -19
- data/lib/ldclient-rb/version.rb +1 -1
- data/lib/ldclient-rb.rb +2 -3
- metadata +34 -17
- data/lib/ldclient-rb/file_data_source.rb +0 -23
- data/lib/ldclient-rb/newrelic.rb +0 -17
- data/lib/ldclient-rb/redis_store.rb +0 -88
- data/lib/ldclient-rb/user_filter.rb +0 -52
@@ -45,7 +45,7 @@ module LaunchDarkly
|
|
45
45
|
|
46
46
|
#
|
47
47
|
# Specifies the fallthrough variation. The fallthrough is the value
|
48
|
-
# that is returned if targeting is on and the
|
48
|
+
# that is returned if targeting is on and the context was not matched by a more specific
|
49
49
|
# target or rule.
|
50
50
|
#
|
51
51
|
# If the flag was previously configured with other variations and the variation specified is a boolean,
|
@@ -56,7 +56,7 @@ module LaunchDarkly
|
|
56
56
|
# @return [FlagBuilder] the builder
|
57
57
|
#
|
58
58
|
def fallthrough_variation(variation)
|
59
|
-
if LaunchDarkly::Impl::Util.
|
59
|
+
if LaunchDarkly::Impl::Util.bool? variation
|
60
60
|
boolean_flag.fallthrough_variation(variation_for_boolean(variation))
|
61
61
|
else
|
62
62
|
@fallthrough_variation = variation
|
@@ -76,7 +76,7 @@ module LaunchDarkly
|
|
76
76
|
# @return [FlagBuilder] the builder
|
77
77
|
#
|
78
78
|
def off_variation(variation)
|
79
|
-
if LaunchDarkly::Impl::Util.
|
79
|
+
if LaunchDarkly::Impl::Util.bool? variation
|
80
80
|
boolean_flag.off_variation(variation_for_boolean(variation))
|
81
81
|
else
|
82
82
|
@off_variation = variation
|
@@ -108,7 +108,7 @@ module LaunchDarkly
|
|
108
108
|
end
|
109
109
|
|
110
110
|
#
|
111
|
-
# Sets the flag to always return the specified variation for all
|
111
|
+
# Sets the flag to always return the specified variation for all contexts.
|
112
112
|
#
|
113
113
|
# The variation is specified, Targeting is switched on, and any existing targets or rules are removed.
|
114
114
|
# The fallthrough variation is set to the specified value. The off variation is left unchanged.
|
@@ -120,31 +120,41 @@ module LaunchDarkly
|
|
120
120
|
# 0 for the first, 1 for the second, etc.
|
121
121
|
# @return [FlagBuilder] the builder
|
122
122
|
#
|
123
|
-
def
|
124
|
-
if LaunchDarkly::Impl::Util.
|
125
|
-
boolean_flag.
|
123
|
+
def variation_for_all(variation)
|
124
|
+
if LaunchDarkly::Impl::Util.bool? variation
|
125
|
+
boolean_flag.variation_for_all(variation_for_boolean(variation))
|
126
126
|
else
|
127
|
-
on(true).clear_rules.
|
127
|
+
on(true).clear_rules.clear_targets.fallthrough_variation(variation)
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
131
|
#
|
132
|
-
#
|
132
|
+
# @deprecated Backwards compatibility alias for #variation_for_all
|
133
|
+
#
|
134
|
+
alias_method :variation_for_all_users, :variation_for_all
|
135
|
+
|
136
|
+
#
|
137
|
+
# Sets the flag to always return the specified variation value for all context.
|
133
138
|
#
|
134
139
|
# The value may be of any valid JSON type. This method changes the
|
135
140
|
# flag to have only a single variation, which is this value, and to return the same
|
136
141
|
# variation regardless of whether targeting is on or off. Any existing targets or rules
|
137
142
|
# are removed.
|
138
143
|
#
|
139
|
-
# @param value [Object] the desired value to be returned for all
|
144
|
+
# @param value [Object] the desired value to be returned for all contexts
|
140
145
|
# @return [FlagBuilder] the builder
|
141
146
|
#
|
142
|
-
def
|
143
|
-
variations(value).
|
147
|
+
def value_for_all(value)
|
148
|
+
variations(value).variation_for_all(0)
|
144
149
|
end
|
145
150
|
|
146
151
|
#
|
147
|
-
#
|
152
|
+
# @deprecated Backwards compatibility alias for #value_for_all
|
153
|
+
#
|
154
|
+
alias_method :value_for_all_users, :value_for_all
|
155
|
+
|
156
|
+
#
|
157
|
+
# Sets the flag to return the specified variation for a specific context key when targeting
|
148
158
|
# is on.
|
149
159
|
#
|
150
160
|
# This has no effect when targeting is turned off for the flag.
|
@@ -152,36 +162,87 @@ module LaunchDarkly
|
|
152
162
|
# If the flag was previously configured with other variations and the variation specified is a boolean,
|
153
163
|
# this also changes it to a boolean flag.
|
154
164
|
#
|
155
|
-
# @param
|
165
|
+
# @param context_kind [String] a context kind
|
166
|
+
# @param context_key [String] a context key
|
156
167
|
# @param variation [Boolean, Integer] true or false or the desired variation index to return:
|
157
168
|
# 0 for the first, 1 for the second, etc.
|
158
169
|
# @return [FlagBuilder] the builder
|
159
170
|
#
|
160
|
-
def
|
161
|
-
if LaunchDarkly::Impl::Util.
|
162
|
-
boolean_flag.
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
171
|
+
def variation_for_key(context_kind, context_key, variation)
|
172
|
+
if LaunchDarkly::Impl::Util.bool? variation
|
173
|
+
return boolean_flag.variation_for_key(context_kind, context_key, variation_for_boolean(variation))
|
174
|
+
end
|
175
|
+
|
176
|
+
if @targets.nil?
|
177
|
+
@targets = Hash.new
|
178
|
+
end
|
179
|
+
|
180
|
+
targets = @targets[context_kind] || []
|
181
|
+
@variations.count.times do | i |
|
182
|
+
if i == variation
|
183
|
+
if targets[i].nil?
|
184
|
+
targets[i] = [context_key]
|
185
|
+
else
|
186
|
+
targets[i].push(context_key)
|
176
187
|
end
|
188
|
+
elsif not targets[i].nil?
|
189
|
+
targets[i].delete(context_key)
|
177
190
|
end
|
178
|
-
self
|
179
191
|
end
|
192
|
+
|
193
|
+
@targets[context_kind] = targets
|
194
|
+
|
195
|
+
self
|
196
|
+
end
|
197
|
+
|
198
|
+
#
|
199
|
+
# Sets the flag to return the specified variation for a specific user key when targeting
|
200
|
+
# is on.
|
201
|
+
#
|
202
|
+
# This is a shortcut for calling {variation_for_key} with
|
203
|
+
# `LaunchDarkly::LDContext::KIND_DEFAULT` as the context kind.
|
204
|
+
#
|
205
|
+
# This has no effect when targeting is turned off for the flag.
|
206
|
+
#
|
207
|
+
# If the flag was previously configured with other variations and the variation specified is a boolean,
|
208
|
+
# this also changes it to a boolean flag.
|
209
|
+
#
|
210
|
+
# @param user_key [String] a user key
|
211
|
+
# @param variation [Boolean, Integer] true or false or the desired variation index to return:
|
212
|
+
# 0 for the first, 1 for the second, etc.
|
213
|
+
# @return [FlagBuilder] the builder
|
214
|
+
#
|
215
|
+
def variation_for_user(user_key, variation)
|
216
|
+
variation_for_key(LaunchDarkly::LDContext::KIND_DEFAULT, user_key, variation)
|
180
217
|
end
|
181
218
|
|
182
219
|
#
|
183
220
|
# Starts defining a flag rule, using the "is one of" operator.
|
184
221
|
#
|
222
|
+
# @example create a rule that returns `true` if the name is "Patsy" or "Edina" and the context kind is "user"
|
223
|
+
# testData.flag("flag")
|
224
|
+
# .if_match_context("user", :name, 'Patsy', 'Edina')
|
225
|
+
# .then_return(true);
|
226
|
+
#
|
227
|
+
# @param context_kind [String] a context kind
|
228
|
+
# @param attribute [Symbol] the context attribute to match against
|
229
|
+
# @param values [Array<Object>] values to compare to
|
230
|
+
# @return [FlagRuleBuilder] a flag rule builder
|
231
|
+
#
|
232
|
+
# @see FlagRuleBuilder#then_return
|
233
|
+
# @see FlagRuleBuilder#and_match
|
234
|
+
# @see FlagRuleBuilder#and_not_match
|
235
|
+
#
|
236
|
+
def if_match_context(context_kind, attribute, *values)
|
237
|
+
FlagRuleBuilder.new(self).and_match_context(context_kind, attribute, *values)
|
238
|
+
end
|
239
|
+
|
240
|
+
#
|
241
|
+
# Starts defining a flag rule, using the "is one of" operator.
|
242
|
+
#
|
243
|
+
# This is a shortcut for calling {if_match_context} with
|
244
|
+
# `LaunchDarkly::LDContext::KIND_DEFAULT` as the context kind.
|
245
|
+
#
|
185
246
|
# @example create a rule that returns `true` if the name is "Patsy" or "Edina"
|
186
247
|
# testData.flag("flag")
|
187
248
|
# .if_match(:name, 'Patsy', 'Edina')
|
@@ -196,12 +257,36 @@ module LaunchDarkly
|
|
196
257
|
# @see FlagRuleBuilder#and_not_match
|
197
258
|
#
|
198
259
|
def if_match(attribute, *values)
|
199
|
-
|
260
|
+
if_match_context(LaunchDarkly::LDContext::KIND_DEFAULT, attribute, *values)
|
261
|
+
end
|
262
|
+
|
263
|
+
#
|
264
|
+
# Starts defining a flag rule, using the "is not one of" operator.
|
265
|
+
#
|
266
|
+
# @example create a rule that returns `true` if the name is neither "Saffron" nor "Bubble"
|
267
|
+
# testData.flag("flag")
|
268
|
+
# .if_not_match_context("user", :name, 'Saffron', 'Bubble')
|
269
|
+
# .then_return(true)
|
270
|
+
#
|
271
|
+
# @param context_kind [String] a context kind
|
272
|
+
# @param attribute [Symbol] the context attribute to match against
|
273
|
+
# @param values [Array<Object>] values to compare to
|
274
|
+
# @return [FlagRuleBuilder] a flag rule builder
|
275
|
+
#
|
276
|
+
# @see FlagRuleBuilder#then_return
|
277
|
+
# @see FlagRuleBuilder#and_match
|
278
|
+
# @see FlagRuleBuilder#and_not_match
|
279
|
+
#
|
280
|
+
def if_not_match_context(context_kind, attribute, *values)
|
281
|
+
FlagRuleBuilder.new(self).and_not_match_context(context_kind, attribute, *values)
|
200
282
|
end
|
201
283
|
|
202
284
|
#
|
203
285
|
# Starts defining a flag rule, using the "is not one of" operator.
|
204
286
|
#
|
287
|
+
# This is a shortcut for calling {if_not_match_context} with
|
288
|
+
# `LaunchDarkly::LDContext::KIND_DEFAULT` as the context kind.
|
289
|
+
#
|
205
290
|
# @example create a rule that returns `true` if the name is neither "Saffron" nor "Bubble"
|
206
291
|
# testData.flag("flag")
|
207
292
|
# .if_not_match(:name, 'Saffron', 'Bubble')
|
@@ -216,20 +301,25 @@ module LaunchDarkly
|
|
216
301
|
# @see FlagRuleBuilder#and_not_match
|
217
302
|
#
|
218
303
|
def if_not_match(attribute, *values)
|
219
|
-
|
304
|
+
if_not_match_context(LaunchDarkly::LDContext::KIND_DEFAULT, attribute, *values)
|
220
305
|
end
|
221
306
|
|
222
307
|
#
|
223
|
-
# Removes any existing
|
224
|
-
# This undoes the effect of methods like {#
|
308
|
+
# Removes any existing targets from the flag.
|
309
|
+
# This undoes the effect of methods like {#variation_for_key}
|
225
310
|
#
|
226
311
|
# @return [FlagBuilder] the same builder
|
227
312
|
#
|
228
|
-
def
|
313
|
+
def clear_targets
|
229
314
|
@targets = nil
|
230
315
|
self
|
231
316
|
end
|
232
317
|
|
318
|
+
#
|
319
|
+
# @deprecated Backwards compatibility alias for #clear_targets
|
320
|
+
#
|
321
|
+
alias_method :clear_user_targets, :clear_targets
|
322
|
+
|
233
323
|
#
|
234
324
|
# Removes any existing rules from the flag.
|
235
325
|
# This undoes the effect of methods like {#if_match}
|
@@ -243,7 +333,7 @@ module LaunchDarkly
|
|
243
333
|
|
244
334
|
# @private
|
245
335
|
def add_rule(rule)
|
246
|
-
if @rules.nil?
|
336
|
+
if @rules.nil?
|
247
337
|
@rules = Array.new
|
248
338
|
end
|
249
339
|
@rules.push(rule)
|
@@ -261,7 +351,7 @@ module LaunchDarkly
|
|
261
351
|
# @return [FlagBuilder] the builder
|
262
352
|
#
|
263
353
|
def boolean_flag
|
264
|
-
if
|
354
|
+
if boolean_flag?
|
265
355
|
self
|
266
356
|
else
|
267
357
|
variations(true, false)
|
@@ -278,22 +368,36 @@ module LaunchDarkly
|
|
278
368
|
variations: @variations,
|
279
369
|
}
|
280
370
|
|
281
|
-
unless @off_variation.nil?
|
371
|
+
unless @off_variation.nil?
|
282
372
|
res[:offVariation] = @off_variation
|
283
373
|
end
|
284
374
|
|
285
|
-
unless @fallthrough_variation.nil?
|
375
|
+
unless @fallthrough_variation.nil?
|
286
376
|
res[:fallthrough] = { variation: @fallthrough_variation }
|
287
377
|
end
|
288
378
|
|
289
|
-
unless @targets.nil?
|
290
|
-
|
291
|
-
|
379
|
+
unless @targets.nil?
|
380
|
+
targets = []
|
381
|
+
context_targets = []
|
382
|
+
|
383
|
+
@targets.each do |kind, targets_for_kind|
|
384
|
+
targets_for_kind.each_with_index do |values, variation|
|
385
|
+
next if values.nil?
|
386
|
+
if kind == LaunchDarkly::LDContext::KIND_DEFAULT
|
387
|
+
targets << { variation: variation, values: values }
|
388
|
+
context_targets << { contextKind: LaunchDarkly::LDContext::KIND_DEFAULT, variation: variation, values: [] }
|
389
|
+
else
|
390
|
+
context_targets << { contextKind: kind, variation: variation, values: values }
|
391
|
+
end
|
392
|
+
end
|
292
393
|
end
|
394
|
+
|
395
|
+
res[:targets] = targets
|
396
|
+
res[:contextTargets] = context_targets
|
293
397
|
end
|
294
398
|
|
295
|
-
unless @rules.nil?
|
296
|
-
res[:rules] = @rules.each_with_index.
|
399
|
+
unless @rules.nil?
|
400
|
+
res[:rules] = @rules.each_with_index.map { | rule, i | rule.build(i) }
|
297
401
|
end
|
298
402
|
|
299
403
|
res
|
@@ -303,8 +407,8 @@ module LaunchDarkly
|
|
303
407
|
# A builder for feature flag rules to be used with {FlagBuilder}.
|
304
408
|
#
|
305
409
|
# In the LaunchDarkly model, a flag can have any number of rules, and a rule can have any number of
|
306
|
-
# clauses. A clause is an individual test such as "name is 'X'". A rule matches a
|
307
|
-
# rule's clauses match the
|
410
|
+
# clauses. A clause is an individual test such as "name is 'X'". A rule matches a context if all of the
|
411
|
+
# rule's clauses match the context.
|
308
412
|
#
|
309
413
|
# To start defining a rule, use one of the flag builder's matching methods such as
|
310
414
|
# {FlagBuilder#if_match}. This defines the first clause for the rule.
|
@@ -314,7 +418,7 @@ module LaunchDarkly
|
|
314
418
|
#
|
315
419
|
class FlagRuleBuilder
|
316
420
|
# @private
|
317
|
-
FlagRuleClause = Struct.new(:attribute, :op, :values, :negate, keyword_init: true)
|
421
|
+
FlagRuleClause = Struct.new(:contextKind, :attribute, :op, :values, :negate, keyword_init: true)
|
318
422
|
|
319
423
|
# @private
|
320
424
|
def initialize(flag_builder)
|
@@ -331,6 +435,34 @@ module LaunchDarkly
|
|
331
435
|
#
|
332
436
|
# Adds another clause, using the "is one of" operator.
|
333
437
|
#
|
438
|
+
# @example create a rule that returns `true` if the name is "Patsy", the country is "gb", and the context kind is "user"
|
439
|
+
# testData.flag("flag")
|
440
|
+
# .if_match_context("user", :name, 'Patsy')
|
441
|
+
# .and_match_context("user", :country, 'gb')
|
442
|
+
# .then_return(true)
|
443
|
+
#
|
444
|
+
# @param context_kind [String] a context kind
|
445
|
+
# @param attribute [Symbol] the context attribute to match against
|
446
|
+
# @param values [Array<Object>] values to compare to
|
447
|
+
# @return [FlagRuleBuilder] the rule builder
|
448
|
+
#
|
449
|
+
def and_match_context(context_kind, attribute, *values)
|
450
|
+
@clauses.push(FlagRuleClause.new(
|
451
|
+
contextKind: context_kind,
|
452
|
+
attribute: attribute,
|
453
|
+
op: 'in',
|
454
|
+
values: values,
|
455
|
+
negate: false
|
456
|
+
))
|
457
|
+
self
|
458
|
+
end
|
459
|
+
|
460
|
+
#
|
461
|
+
# Adds another clause, using the "is one of" operator.
|
462
|
+
#
|
463
|
+
# This is a shortcut for calling {and_match_context} with
|
464
|
+
# `LaunchDarkly::LDContext::KIND_DEFAULT` as the context kind.
|
465
|
+
#
|
334
466
|
# @example create a rule that returns `true` if the name is "Patsy" and the country is "gb"
|
335
467
|
# testData.flag("flag")
|
336
468
|
# .if_match(:name, 'Patsy')
|
@@ -342,11 +474,30 @@ module LaunchDarkly
|
|
342
474
|
# @return [FlagRuleBuilder] the rule builder
|
343
475
|
#
|
344
476
|
def and_match(attribute, *values)
|
477
|
+
and_match_context(LaunchDarkly::LDContext::KIND_DEFAULT, attribute, *values)
|
478
|
+
end
|
479
|
+
|
480
|
+
#
|
481
|
+
# Adds another clause, using the "is not one of" operator.
|
482
|
+
#
|
483
|
+
# @example create a rule that returns `true` if the name is "Patsy" and the country is not "gb"
|
484
|
+
# testData.flag("flag")
|
485
|
+
# .if_match_context("user", :name, 'Patsy')
|
486
|
+
# .and_not_match_context("user", :country, 'gb')
|
487
|
+
# .then_return(true)
|
488
|
+
#
|
489
|
+
# @param context_kind [String] a context kind
|
490
|
+
# @param attribute [Symbol] the context attribute to match against
|
491
|
+
# @param values [Array<Object>] values to compare to
|
492
|
+
# @return [FlagRuleBuilder] the rule builder
|
493
|
+
#
|
494
|
+
def and_not_match_context(context_kind, attribute, *values)
|
345
495
|
@clauses.push(FlagRuleClause.new(
|
496
|
+
contextKind: context_kind,
|
346
497
|
attribute: attribute,
|
347
498
|
op: 'in',
|
348
499
|
values: values,
|
349
|
-
negate:
|
500
|
+
negate: true
|
350
501
|
))
|
351
502
|
self
|
352
503
|
end
|
@@ -354,6 +505,9 @@ module LaunchDarkly
|
|
354
505
|
#
|
355
506
|
# Adds another clause, using the "is not one of" operator.
|
356
507
|
#
|
508
|
+
# This is a shortcut for calling {and_not_match} with
|
509
|
+
# `LaunchDarkly::LDContext::KIND_DEFAULT` as the context kind.
|
510
|
+
#
|
357
511
|
# @example create a rule that returns `true` if the name is "Patsy" and the country is not "gb"
|
358
512
|
# testData.flag("flag")
|
359
513
|
# .if_match(:name, 'Patsy')
|
@@ -365,13 +519,7 @@ module LaunchDarkly
|
|
365
519
|
# @return [FlagRuleBuilder] the rule builder
|
366
520
|
#
|
367
521
|
def and_not_match(attribute, *values)
|
368
|
-
|
369
|
-
attribute: attribute,
|
370
|
-
op: 'in',
|
371
|
-
values: values,
|
372
|
-
negate: true
|
373
|
-
))
|
374
|
-
self
|
522
|
+
and_not_match_context(LaunchDarkly::LDContext::KIND_DEFAULT, attribute, *values)
|
375
523
|
end
|
376
524
|
|
377
525
|
#
|
@@ -386,7 +534,7 @@ module LaunchDarkly
|
|
386
534
|
# @return [FlagBuilder] the flag builder with this rule added
|
387
535
|
#
|
388
536
|
def then_return(variation)
|
389
|
-
if LaunchDarkly::Impl::Util.
|
537
|
+
if LaunchDarkly::Impl::Util.bool? variation
|
390
538
|
@variation = @flag_builder.variation_for_boolean(variation)
|
391
539
|
@flag_builder.boolean_flag.add_rule(self)
|
392
540
|
else
|
@@ -400,7 +548,7 @@ module LaunchDarkly
|
|
400
548
|
{
|
401
549
|
id: 'rule' + ri.to_s,
|
402
550
|
variation: @variation,
|
403
|
-
clauses: @clauses.
|
551
|
+
clauses: @clauses.map(&:to_h),
|
404
552
|
}
|
405
553
|
end
|
406
554
|
end
|
@@ -415,15 +563,23 @@ module LaunchDarkly
|
|
415
563
|
TRUE_VARIATION_INDEX = 0
|
416
564
|
FALSE_VARIATION_INDEX = 1
|
417
565
|
|
418
|
-
def
|
566
|
+
def boolean_flag?
|
419
567
|
@variations.size == 2 &&
|
420
|
-
|
421
|
-
|
568
|
+
@variations[TRUE_VARIATION_INDEX] == true &&
|
569
|
+
@variations[FALSE_VARIATION_INDEX] == false
|
422
570
|
end
|
423
571
|
|
424
572
|
def deep_copy_hash(from)
|
425
573
|
to = Hash.new
|
426
|
-
from.each
|
574
|
+
from.each do |k, v|
|
575
|
+
if v.is_a?(Hash)
|
576
|
+
to[k] = deep_copy_hash(v)
|
577
|
+
elsif v.is_a?(Array)
|
578
|
+
to[k] = deep_copy_array(v)
|
579
|
+
else
|
580
|
+
to[k] = v.clone
|
581
|
+
end
|
582
|
+
end
|
427
583
|
to
|
428
584
|
end
|
429
585
|
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'ldclient-rb/impl/integrations/test_data/test_data_source'
|
2
|
+
require 'ldclient-rb/impl/model/feature_flag'
|
3
|
+
require 'ldclient-rb/impl/model/segment'
|
2
4
|
require 'ldclient-rb/integrations/test_data/flag_builder'
|
3
5
|
|
4
6
|
require 'concurrent/atomics'
|
@@ -14,12 +16,12 @@ module LaunchDarkly
|
|
14
16
|
#
|
15
17
|
# @example
|
16
18
|
# td = LaunchDarkly::Integrations::TestData.data_source
|
17
|
-
# td.update(td.flag("flag-key-1").
|
19
|
+
# td.update(td.flag("flag-key-1").variation_for_all(true))
|
18
20
|
# config = LaunchDarkly::Config.new(data_source: td)
|
19
21
|
# client = LaunchDarkly::LDClient.new('sdkKey', config)
|
20
22
|
# # flags can be updated at any time:
|
21
23
|
# td.update(td.flag("flag-key-2")
|
22
|
-
# .
|
24
|
+
# .variation_for_key("user", some-user-key", true)
|
23
25
|
# .fallthrough_variation(false))
|
24
26
|
#
|
25
27
|
# The above example uses a simple boolean flag, but more complex configurations are possible using
|
@@ -77,7 +79,7 @@ module LaunchDarkly
|
|
77
79
|
# starts with the same configuration that was last provided for this flag.
|
78
80
|
#
|
79
81
|
# Otherwise, it starts with a new default configuration in which the flag has `true` and
|
80
|
-
# `false` variations, is `true` for all
|
82
|
+
# `false` variations, is `true` for all contexts when targeting is turned on and
|
81
83
|
# `false` otherwise, and currently has targeting turned on. You can change any of those
|
82
84
|
# properties, and provide more complex behavior, using the {FlagBuilder} methods.
|
83
85
|
#
|
@@ -119,7 +121,7 @@ module LaunchDarkly
|
|
119
121
|
if @current_flags[flag_key] then
|
120
122
|
version = @current_flags[flag_key][:version]
|
121
123
|
end
|
122
|
-
new_flag = flag_builder.build(version+1)
|
124
|
+
new_flag = Impl::Model.deserialize(FEATURES, flag_builder.build(version+1))
|
123
125
|
@current_flags[flag_key] = new_flag
|
124
126
|
end
|
125
127
|
update_item(FEATURES, new_flag)
|
@@ -149,15 +151,15 @@ module LaunchDarkly
|
|
149
151
|
end
|
150
152
|
|
151
153
|
#
|
152
|
-
# Copies a full
|
154
|
+
# Copies a full segment data model object into the test data.
|
153
155
|
#
|
154
156
|
# It immediately propagates the change to any `LDClient` instance(s) that you have already
|
155
157
|
# configured to use this `TestData`. If no `LDClient` has been started yet, it simply adds
|
156
158
|
# this segment to the test data which will be provided to any LDClient that you subsequently
|
157
159
|
# configure.
|
158
160
|
#
|
159
|
-
# This method is currently the only way to inject
|
160
|
-
# API for segments. It is mainly intended for the SDK's own tests of
|
161
|
+
# This method is currently the only way to inject segment data, since there is no builder
|
162
|
+
# API for segments. It is mainly intended for the SDK's own tests of segment functionality,
|
161
163
|
# since application tests that need to produce a desired evaluation state could do so more easily
|
162
164
|
# by just setting flag values.
|
163
165
|
#
|
@@ -169,12 +171,14 @@ module LaunchDarkly
|
|
169
171
|
end
|
170
172
|
|
171
173
|
private def use_preconfigured_item(kind, item, current)
|
172
|
-
|
174
|
+
item = Impl::Model.deserialize(kind, item)
|
175
|
+
key = item.key.to_sym
|
173
176
|
@lock.with_write_lock do
|
174
177
|
old_item = current[key]
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
+
unless old_item.nil? then
|
179
|
+
data = item.as_json
|
180
|
+
data[:version] = old_item.version + 1
|
181
|
+
item = Impl::Model.deserialize(kind, data)
|
178
182
|
end
|
179
183
|
current[key] = item
|
180
184
|
end
|
@@ -195,7 +199,7 @@ module LaunchDarkly
|
|
195
199
|
@lock.with_read_lock do
|
196
200
|
{
|
197
201
|
FEATURES => @current_flags.clone,
|
198
|
-
SEGMENTS => @current_segments.clone
|
202
|
+
SEGMENTS => @current_segments.clone,
|
199
203
|
}
|
200
204
|
end
|
201
205
|
end
|
@@ -22,7 +22,7 @@ module LaunchDarkly
|
|
22
22
|
#
|
23
23
|
class CachingStoreWrapper
|
24
24
|
include LaunchDarkly::Interfaces::FeatureStore
|
25
|
-
|
25
|
+
|
26
26
|
#
|
27
27
|
# Creates a new store wrapper instance.
|
28
28
|
#
|
@@ -49,7 +49,7 @@ module LaunchDarkly
|
|
49
49
|
@core.init_internal(all_data)
|
50
50
|
@inited.make_true
|
51
51
|
|
52
|
-
|
52
|
+
unless @cache.nil?
|
53
53
|
@cache.clear
|
54
54
|
all_data.each do |kind, items|
|
55
55
|
@cache[kind] = items_if_not_deleted(items)
|
@@ -61,15 +61,15 @@ module LaunchDarkly
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def get(kind, key)
|
64
|
-
|
64
|
+
unless @cache.nil?
|
65
65
|
cache_key = item_cache_key(kind, key)
|
66
66
|
cached = @cache[cache_key] # note, item entries in the cache are wrapped in an array so we can cache nil values
|
67
|
-
return item_if_not_deleted(cached[0])
|
67
|
+
return item_if_not_deleted(cached[0]) unless cached.nil?
|
68
68
|
end
|
69
69
|
|
70
70
|
item = @core.get_internal(kind, key)
|
71
71
|
|
72
|
-
|
72
|
+
unless @cache.nil?
|
73
73
|
@cache[cache_key] = [item]
|
74
74
|
end
|
75
75
|
|
@@ -77,20 +77,20 @@ module LaunchDarkly
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def all(kind)
|
80
|
-
|
80
|
+
unless @cache.nil?
|
81
81
|
items = @cache[all_cache_key(kind)]
|
82
|
-
return items
|
82
|
+
return items unless items.nil?
|
83
83
|
end
|
84
84
|
|
85
85
|
items = items_if_not_deleted(@core.get_all_internal(kind))
|
86
|
-
@cache[all_cache_key(kind)] = items
|
86
|
+
@cache[all_cache_key(kind)] = items unless @cache.nil?
|
87
87
|
items
|
88
88
|
end
|
89
89
|
|
90
90
|
def upsert(kind, item)
|
91
91
|
new_state = @core.upsert_internal(kind, item)
|
92
92
|
|
93
|
-
|
93
|
+
unless @cache.nil?
|
94
94
|
@cache[item_cache_key(kind, item[:key])] = [new_state]
|
95
95
|
@cache.delete(all_cache_key(kind))
|
96
96
|
end
|