launchdarkly-server-sdk 6.4.0 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
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