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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ldclient-rb/config.rb +102 -56
  3. data/lib/ldclient-rb/context.rb +487 -0
  4. data/lib/ldclient-rb/evaluation_detail.rb +20 -20
  5. data/lib/ldclient-rb/events.rb +77 -132
  6. data/lib/ldclient-rb/flags_state.rb +4 -4
  7. data/lib/ldclient-rb/impl/big_segments.rb +17 -17
  8. data/lib/ldclient-rb/impl/context.rb +96 -0
  9. data/lib/ldclient-rb/impl/context_filter.rb +145 -0
  10. data/lib/ldclient-rb/impl/diagnostic_events.rb +9 -10
  11. data/lib/ldclient-rb/impl/evaluator.rb +379 -131
  12. data/lib/ldclient-rb/impl/evaluator_bucketing.rb +40 -41
  13. data/lib/ldclient-rb/impl/evaluator_helpers.rb +31 -34
  14. data/lib/ldclient-rb/impl/evaluator_operators.rb +26 -55
  15. data/lib/ldclient-rb/impl/event_sender.rb +6 -6
  16. data/lib/ldclient-rb/impl/event_summarizer.rb +12 -7
  17. data/lib/ldclient-rb/impl/event_types.rb +18 -30
  18. data/lib/ldclient-rb/impl/integrations/consul_impl.rb +7 -7
  19. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +29 -29
  20. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +8 -8
  21. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +92 -12
  22. data/lib/ldclient-rb/impl/model/clause.rb +45 -0
  23. data/lib/ldclient-rb/impl/model/feature_flag.rb +232 -0
  24. data/lib/ldclient-rb/impl/model/preprocessed_data.rb +8 -121
  25. data/lib/ldclient-rb/impl/model/segment.rb +132 -0
  26. data/lib/ldclient-rb/impl/model/serialization.rb +52 -12
  27. data/lib/ldclient-rb/impl/repeating_task.rb +1 -1
  28. data/lib/ldclient-rb/impl/store_data_set_sorter.rb +2 -2
  29. data/lib/ldclient-rb/impl/unbounded_pool.rb +1 -1
  30. data/lib/ldclient-rb/impl/util.rb +2 -2
  31. data/lib/ldclient-rb/in_memory_store.rb +2 -2
  32. data/lib/ldclient-rb/integrations/consul.rb +1 -1
  33. data/lib/ldclient-rb/integrations/dynamodb.rb +1 -1
  34. data/lib/ldclient-rb/integrations/file_data.rb +3 -3
  35. data/lib/ldclient-rb/integrations/redis.rb +4 -4
  36. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +218 -62
  37. data/lib/ldclient-rb/integrations/test_data.rb +16 -12
  38. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +9 -9
  39. data/lib/ldclient-rb/interfaces.rb +14 -14
  40. data/lib/ldclient-rb/ldclient.rb +94 -144
  41. data/lib/ldclient-rb/memoized_value.rb +1 -1
  42. data/lib/ldclient-rb/non_blocking_thread_pool.rb +1 -1
  43. data/lib/ldclient-rb/polling.rb +2 -2
  44. data/lib/ldclient-rb/reference.rb +274 -0
  45. data/lib/ldclient-rb/requestor.rb +5 -5
  46. data/lib/ldclient-rb/stream.rb +7 -8
  47. data/lib/ldclient-rb/util.rb +4 -19
  48. data/lib/ldclient-rb/version.rb +1 -1
  49. data/lib/ldclient-rb.rb +2 -3
  50. metadata +34 -17
  51. data/lib/ldclient-rb/file_data_source.rb +0 -23
  52. data/lib/ldclient-rb/newrelic.rb +0 -17
  53. data/lib/ldclient-rb/redis_store.rb +0 -88
  54. 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 user was not matched by a more specific
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.is_bool variation then
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.is_bool variation then
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 users.
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 variation_for_all_users(variation)
124
- if LaunchDarkly::Impl::Util.is_bool variation then
125
- boolean_flag.variation_for_all_users(variation_for_boolean(variation))
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.clear_user_targets.fallthrough_variation(variation)
127
+ on(true).clear_rules.clear_targets.fallthrough_variation(variation)
128
128
  end
129
129
  end
130
130
 
131
131
  #
132
- # Sets the flag to always return the specified variation value for all users.
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 users
144
+ # @param value [Object] the desired value to be returned for all contexts
140
145
  # @return [FlagBuilder] the builder
141
146
  #
142
- def value_for_all_users(value)
143
- variations(value).variation_for_all_users(0)
147
+ def value_for_all(value)
148
+ variations(value).variation_for_all(0)
144
149
  end
145
150
 
146
151
  #
147
- # Sets the flag to return the specified variation for a specific user key when targeting
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 user_key [String] a user key
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 variation_for_user(user_key, variation)
161
- if LaunchDarkly::Impl::Util.is_bool variation then
162
- boolean_flag.variation_for_user(user_key, variation_for_boolean(variation))
163
- else
164
- if @targets.nil? then
165
- @targets = Hash.new
166
- end
167
- @variations.count.times do | i |
168
- if i == variation then
169
- if @targets[i].nil? then
170
- @targets[i] = [user_key]
171
- else
172
- @targets[i].push(user_key)
173
- end
174
- elsif not @targets[i].nil? then
175
- @targets[i].delete(user_key)
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
- FlagRuleBuilder.new(self).and_match(attribute, *values)
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
- FlagRuleBuilder.new(self).and_not_match(attribute, *values)
304
+ if_not_match_context(LaunchDarkly::LDContext::KIND_DEFAULT, attribute, *values)
220
305
  end
221
306
 
222
307
  #
223
- # Removes any existing user targets from the flag.
224
- # This undoes the effect of methods like {#variation_for_user}
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 clear_user_targets
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? then
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 is_boolean_flag then
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? then
371
+ unless @off_variation.nil?
282
372
  res[:offVariation] = @off_variation
283
373
  end
284
374
 
285
- unless @fallthrough_variation.nil? then
375
+ unless @fallthrough_variation.nil?
286
376
  res[:fallthrough] = { variation: @fallthrough_variation }
287
377
  end
288
378
 
289
- unless @targets.nil? then
290
- res[:targets] = @targets.collect do | variation, values |
291
- { variation: variation, values: values }
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? then
296
- res[:rules] = @rules.each_with_index.collect { | rule, i | rule.build(i) }
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 user if all of the
307
- # rule's clauses match the user.
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: false
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
- @clauses.push(FlagRuleClause.new(
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.is_bool variation then
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.collect(&:to_h)
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 is_boolean_flag
566
+ def boolean_flag?
419
567
  @variations.size == 2 &&
420
- @variations[TRUE_VARIATION_INDEX] == true &&
421
- @variations[FALSE_VARIATION_INDEX] == false
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 { |k, v| to[k] = v.clone }
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").variation_for_all_users(true))
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
- # .variation_for_user("some-user-key", true)
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 users when targeting is turned on and
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 user segment data model object into the test data.
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 user segment data, since there is no builder
160
- # API for segments. It is mainly intended for the SDK's own tests of user segment functionality,
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
- key = item[:key].to_sym
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
- if !old_item.nil? then
176
- item = item.clone
177
- item[:version] = old_item[:version] + 1
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
- if !@cache.nil?
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
- if !@cache.nil?
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]) if !cached.nil?
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
- if !@cache.nil?
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
- if !@cache.nil?
80
+ unless @cache.nil?
81
81
  items = @cache[all_cache_key(kind)]
82
- return items if !items.nil?
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 if !@cache.nil?
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
- if !@cache.nil?
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