launchdarkly-server-sdk 6.3.4 → 7.0.0

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 +121 -55
  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 +378 -139
  12. data/lib/ldclient-rb/impl/evaluator_bucketing.rb +40 -41
  13. data/lib/ldclient-rb/impl/evaluator_helpers.rb +50 -0
  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 +39 -0
  23. data/lib/ldclient-rb/impl/model/feature_flag.rb +213 -0
  24. data/lib/ldclient-rb/impl/model/preprocessed_data.rb +64 -0
  25. data/lib/ldclient-rb/impl/model/segment.rb +126 -0
  26. data/lib/ldclient-rb/impl/model/serialization.rb +54 -44
  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 +59 -1
  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 +7 -7
  46. data/lib/ldclient-rb/stream.rb +8 -9
  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 +36 -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
@@ -163,30 +163,30 @@ module LaunchDarkly
163
163
  end
164
164
 
165
165
  #
166
- # Queries the store for a snapshot of the current segment state for a specific user.
166
+ # Queries the store for a snapshot of the current segment state for a specific context.
167
167
  #
168
- # The user_hash is a base64-encoded string produced by hashing the user key as defined by
168
+ # The context_hash is a base64-encoded string produced by hashing the context key as defined by
169
169
  # the Big Segments specification; the store implementation does not need to know the details
170
170
  # of how this is done, because it deals only with already-hashed keys, but the string can be
171
171
  # assumed to only contain characters that are valid in base64.
172
172
  #
173
- # The return value should be either a Hash, or nil if the user is not referenced in any big
173
+ # The return value should be either a Hash, or nil if the context is not referenced in any big
174
174
  # segments. Each key in the Hash is a "segment reference", which is how segments are
175
175
  # identified in Big Segment data. This string is not identical to the segment key-- the SDK
176
176
  # will add other information. The store implementation should not be concerned with the
177
- # format of the string. Each value in the Hash is true if the user is explicitly included in
178
- # the segment, false if the user is explicitly excluded from the segment-- and is not also
177
+ # format of the string. Each value in the Hash is true if the context is explicitly included in
178
+ # the segment, false if the context is explicitly excluded from the segment-- and is not also
179
179
  # explicitly included (that is, if both an include and an exclude existed in the data, the
180
- # include would take precedence). If the user's status in a particular segment is undefined,
180
+ # include would take precedence). If the context's status in a particular segment is undefined,
181
181
  # there should be no key or value for that segment.
182
182
  #
183
183
  # This Hash may be cached by the SDK, so it should not be modified after it is created. It
184
184
  # is a snapshot of the segment membership state at one point in time.
185
185
  #
186
- # @param user_hash [String]
187
- # @return [Hash] true/false values for Big Segments that reference this user
186
+ # @param context_hash [String]
187
+ # @return [Hash] true/false values for Big Segments that reference this context
188
188
  #
189
- def get_membership(user_hash)
189
+ def get_membership(context_hash)
190
190
  end
191
191
 
192
192
  #
@@ -216,7 +216,7 @@ module LaunchDarkly
216
216
  #
217
217
  # Information about the status of a Big Segment store, provided by {BigSegmentStoreStatusProvider}.
218
218
  #
219
- # Big Segments are a specific type of user segments. For more information, read the LaunchDarkly
219
+ # Big Segments are a specific type of segments. For more information, read the LaunchDarkly
220
220
  # documentation: https://docs.launchdarkly.com/home/users/big-segments
221
221
  #
222
222
  class BigSegmentStoreStatus
@@ -226,11 +226,11 @@ module LaunchDarkly
226
226
  end
227
227
 
228
228
  # True if the Big Segment store is able to respond to queries, so that the SDK can evaluate
229
- # whether a user is in a segment or not.
229
+ # whether a context is in a segment or not.
230
230
  #
231
231
  # If this property is false, the store is not able to make queries (for instance, it may not have
232
232
  # a valid database connection). In this case, the SDK will treat any reference to a Big Segment
233
- # as if no users are included in that segment. Also, the {EvaluationReason} associated with
233
+ # as if no contexts are included in that segment. Also, the {EvaluationReason} associated with
234
234
  # with any flag evaluation that references a Big Segment when the store is not available will
235
235
  # have a `big_segments_status` of `STORE_ERROR`.
236
236
  #
@@ -259,14 +259,14 @@ module LaunchDarkly
259
259
  #
260
260
  # The Big Segment store is the component that receives information about Big Segments, normally
261
261
  # from a database populated by the LaunchDarkly Relay Proxy. Big Segments are a specific type
262
- # of user segments. For more information, read the LaunchDarkly documentation:
262
+ # of segments. For more information, read the LaunchDarkly documentation:
263
263
  # https://docs.launchdarkly.com/home/users/big-segments
264
264
  #
265
265
  # An implementation of this interface is returned by {LDClient#big_segment_store_status_provider}.
266
266
  # Application code never needs to implement this interface.
267
267
  #
268
268
  # There are two ways to interact with the status. One is to simply get the current status; if its
269
- # `available` property is true, then the SDK is able to evaluate user membership in Big Segments,
269
+ # `available` property is true, then the SDK is able to evaluate context membership in Big Segments,
270
270
  # and the `stale`` property indicates whether the data might be out of date.
271
271
  #
272
272
  # The other way is to subscribe to status change notifications. Applications may wish to know if
@@ -59,7 +59,7 @@ module LaunchDarkly
59
59
 
60
60
  get_flag = lambda { |key| @store.get(FEATURES, key) }
61
61
  get_segment = lambda { |key| @store.get(SEGMENTS, key) }
62
- get_big_segments_membership = lambda { |key| @big_segment_store_manager.get_user_membership(key) }
62
+ get_big_segments_membership = lambda { |key| @big_segment_store_manager.get_context_membership(key) }
63
63
  @evaluator = LaunchDarkly::Impl::Evaluator.new(get_flag, get_segment, get_big_segments_membership, @config.logger)
64
64
 
65
65
  if !@config.offline? && @config.send_events && !@config.diagnostic_opt_out?
@@ -120,26 +120,20 @@ module LaunchDarkly
120
120
  end
121
121
 
122
122
  #
123
- # @param key [String] the feature flag key
124
- # @param user [Hash] the user properties
125
- # @param default [Boolean] (false) the value to use if the flag cannot be evaluated
126
- # @return [Boolean] the flag value
127
- # @deprecated Use {#variation} instead.
128
- #
129
- def toggle?(key, user, default = false)
130
- @config.logger.warn { "[LDClient] toggle? is deprecated. Use variation instead" }
131
- variation(key, user, default)
132
- end
133
-
134
- #
135
- # Creates a hash string that can be used by the JavaScript SDK to identify a user.
123
+ # Creates a hash string that can be used by the JavaScript SDK to identify a context.
136
124
  # For more information, see [Secure mode](https://docs.launchdarkly.com/sdk/features/secure-mode#ruby).
137
125
  #
138
- # @param user [Hash] the user properties
139
- # @return [String] a hash string
126
+ # @param context [Hash, LDContext]
127
+ # @return [String, nil] a hash string or nil if the provided context was invalid
140
128
  #
141
- def secure_mode_hash(user)
142
- OpenSSL::HMAC.hexdigest("sha256", @sdk_key, user[:key].to_s)
129
+ def secure_mode_hash(context)
130
+ context = Impl::Context::make_context(context)
131
+ unless context.valid?
132
+ @config.logger.warn("secure_mode_hash called with invalid context: #{context.error}")
133
+ return nil
134
+ end
135
+
136
+ OpenSSL::HMAC.hexdigest("sha256", @sdk_key, context.fully_qualified_key)
143
137
  end
144
138
 
145
139
  #
@@ -165,44 +159,22 @@ module LaunchDarkly
165
159
  end
166
160
 
167
161
  #
168
- # Determines the variation of a feature flag to present to a user.
169
- #
170
- # At a minimum, the user hash should contain a `:key`, which should be the unique
171
- # identifier for your user (or, for an anonymous user, a session identifier or
172
- # cookie).
173
- #
174
- # Other supported user attributes include IP address, country code, and an arbitrary hash of
175
- # custom attributes. For more about the supported user properties and how they work in
176
- # LaunchDarkly, see [Targeting users](https://docs.launchdarkly.com/home/flags/targeting-users).
177
- #
178
- # The optional `:privateAttributeNames` user property allows you to specify a list of
179
- # attribute names that should not be sent back to LaunchDarkly.
180
- # [Private attributes](https://docs.launchdarkly.com/home/users/attributes#creating-private-user-attributes)
181
- # can also be configured globally in {Config}.
182
- #
183
- # @example Basic user hash
184
- # {key: "my-user-id"}
185
- #
186
- # @example More complete user hash
187
- # {key: "my-user-id", ip: "127.0.0.1", country: "US", custom: {customer_rank: 1000}}
188
- #
189
- # @example User with a private attribute
190
- # {key: "my-user-id", email: "email@example.com", privateAttributeNames: ["email"]}
162
+ # Determines the variation of a feature flag to present for a context.
191
163
  #
192
164
  # @param key [String] the unique feature key for the feature flag, as shown
193
165
  # on the LaunchDarkly dashboard
194
- # @param user [Hash] a hash containing parameters for the end user requesting the flag
166
+ # @param context [Hash, LDContext] a hash or LDContext instance describing the context requesting the flag
195
167
  # @param default the default value of the flag; this is used if there is an error
196
168
  # condition making it impossible to find or evaluate the flag
197
169
  #
198
- # @return the variation to show the user, or the default value if there's an an error
170
+ # @return the variation for the provided context, or the default value if there's an an error
199
171
  #
200
- def variation(key, user, default)
201
- evaluate_internal(key, user, default, false).value
172
+ def variation(key, context, default)
173
+ evaluate_internal(key, context, default, false).value
202
174
  end
203
175
 
204
176
  #
205
- # Determines the variation of a feature flag for a user, like {#variation}, but also
177
+ # Determines the variation of a feature flag for a context, like {#variation}, but also
206
178
  # provides additional information about how this value was calculated.
207
179
  #
208
180
  # The return value of `variation_detail` is an {EvaluationDetail} object, which has
@@ -218,43 +190,48 @@ module LaunchDarkly
218
190
  #
219
191
  # @param key [String] the unique feature key for the feature flag, as shown
220
192
  # on the LaunchDarkly dashboard
221
- # @param user [Hash] a hash containing parameters for the end user requesting the flag
193
+ # @param context [Hash, LDContext] a hash or object describing the context requesting the flag,
222
194
  # @param default the default value of the flag; this is used if there is an error
223
195
  # condition making it impossible to find or evaluate the flag
224
196
  #
225
197
  # @return [EvaluationDetail] an object describing the result
226
198
  #
227
- def variation_detail(key, user, default)
228
- evaluate_internal(key, user, default, true)
199
+ def variation_detail(key, context, default)
200
+ evaluate_internal(key, context, default, true)
229
201
  end
230
202
 
231
203
  #
232
- # Registers the user. This method simply creates an analytics event containing the user
233
- # properties, so that LaunchDarkly will know about that user if it does not already.
204
+ # Registers the context. This method simply creates an analytics event containing the context
205
+ # properties, so that LaunchDarkly will know about that context if it does not already.
234
206
  #
235
- # Calling {#variation} or {#variation_detail} also sends the user information to
207
+ # Calling {#variation} or {#variation_detail} also sends the context information to
236
208
  # LaunchDarkly (if events are enabled), so you only need to use {#identify} if you
237
- # want to identify the user without evaluating a flag.
209
+ # want to identify the context without evaluating a flag.
238
210
  #
239
211
  # Note that event delivery is asynchronous, so the event may not actually be sent
240
212
  # until later; see {#flush}.
241
213
  #
242
- # @param user [Hash] The user to register; this can have all the same user properties
243
- # described in {#variation}
214
+ # @param context [Hash, LDContext] a hash or object describing the context to register
244
215
  # @return [void]
245
216
  #
246
- def identify(user)
247
- if !user || user[:key].nil? || user[:key].empty?
248
- @config.logger.warn("Identify called with nil user or empty user key!")
217
+ def identify(context)
218
+ context = LaunchDarkly::Impl::Context.make_context(context)
219
+ unless context.valid?
220
+ @config.logger.warn("Identify called with invalid context: #{context.error}")
221
+ return
222
+ end
223
+
224
+ if context.key == ""
225
+ @config.logger.warn("Identify called with empty key")
249
226
  return
250
227
  end
251
- sanitize_user(user)
252
- @event_processor.record_identify_event(user)
228
+
229
+ @event_processor.record_identify_event(context)
253
230
  end
254
231
 
255
232
  #
256
- # Tracks that a user performed an event. This method creates a "custom" analytics event
257
- # containing the specified event name (key), user properties, and optional data.
233
+ # Tracks that a context performed an event. This method creates a "custom" analytics event
234
+ # containing the specified event name (key), context properties, and optional data.
258
235
  #
259
236
  # Note that event delivery is asynchronous, so the event may not actually be sent
260
237
  # until later; see {#flush}.
@@ -265,8 +242,7 @@ module LaunchDarkly
265
242
  # for the latest status.
266
243
  #
267
244
  # @param event_name [String] The name of the event
268
- # @param user [Hash] The user to register; this can have all the same user properties
269
- # described in {#variation}
245
+ # @param context [Hash, LDContext] a hash or object describing the context to track
270
246
  # @param data [Hash] An optional hash containing any additional data associated with the event
271
247
  # @param metric_value [Number] A numeric value used by the LaunchDarkly experimentation
272
248
  # feature in numeric custom metrics. Can be omitted if this event is used by only
@@ -274,52 +250,22 @@ module LaunchDarkly
274
250
  # for Data Export.
275
251
  # @return [void]
276
252
  #
277
- def track(event_name, user, data = nil, metric_value = nil)
278
- if !user || user[:key].nil?
279
- @config.logger.warn("Track called with nil user or nil user key!")
280
- return
281
- end
282
- sanitize_user(user)
283
- @event_processor.record_custom_event(user, event_name, data, metric_value)
284
- end
285
-
286
- #
287
- # Associates a new and old user object for analytics purposes via an alias event.
288
- #
289
- # @param current_context [Hash] The current version of a user.
290
- # @param previous_context [Hash] The previous version of a user.
291
- # @return [void]
292
- #
293
- def alias(current_context, previous_context)
294
- if !current_context || current_context[:key].nil? || !previous_context || previous_context[:key].nil?
295
- @config.logger.warn("Alias called with nil user or nil user key!")
253
+ def track(event_name, context, data = nil, metric_value = nil)
254
+ context = LaunchDarkly::Impl::Context.make_context(context)
255
+ unless context.valid?
256
+ @config.logger.warn("Track called with invalid context: #{context.error}")
296
257
  return
297
258
  end
298
- sanitize_user(current_context)
299
- sanitize_user(previous_context)
300
- @event_processor.record_alias_event(current_context, previous_context)
301
- end
302
259
 
303
- #
304
- # Returns all feature flag values for the given user.
305
- #
306
- # @deprecated Please use {#all_flags_state} instead. Current versions of the
307
- # client-side SDK will not generate analytics events correctly if you pass the
308
- # result of `all_flags`.
309
- #
310
- # @param user [Hash] The end user requesting the feature flags
311
- # @return [Hash] a hash of feature flag keys to values
312
- #
313
- def all_flags(user)
314
- all_flags_state(user).values_map
260
+ @event_processor.record_custom_event(context, event_name, data, metric_value)
315
261
  end
316
262
 
317
263
  #
318
- # Returns a {FeatureFlagsState} object that encapsulates the state of all feature flags for a given user,
264
+ # Returns a {FeatureFlagsState} object that encapsulates the state of all feature flags for a given context,
319
265
  # including the flag values and also metadata that can be used on the front end. This method does not
320
266
  # send analytics events back to LaunchDarkly.
321
267
  #
322
- # @param user [Hash] The end user requesting the feature flags
268
+ # @param context [Hash, LDContext] a hash or object describing the context requesting the flags,
323
269
  # @param options [Hash] Optional parameters to control how the state is generated
324
270
  # @option options [Boolean] :client_side_only (false) True if only flags marked for use with the
325
271
  # client-side SDK should be included in the state. By default, all flags are included.
@@ -331,10 +277,10 @@ module LaunchDarkly
331
277
  # of the JSON data if you are passing the flag state to the front end.
332
278
  # @return [FeatureFlagsState] a {FeatureFlagsState} object which can be serialized to JSON
333
279
  #
334
- def all_flags_state(user, options={})
280
+ def all_flags_state(context, options={})
335
281
  return FeatureFlagsState.new(false) if @config.offline?
336
282
 
337
- if !initialized?
283
+ unless initialized?
338
284
  if @store.initialized?
339
285
  @config.logger.warn { "Called all_flags_state before client initialization; using last known values from data store" }
340
286
  else
@@ -343,8 +289,9 @@ module LaunchDarkly
343
289
  end
344
290
  end
345
291
 
346
- unless user && !user[:key].nil?
347
- @config.logger.error { "[LDClient] User and user key must be specified in all_flags_state" }
292
+ context = Impl::Context::make_context(context)
293
+ unless context.valid?
294
+ @config.logger.error { "[LDClient] Context was invalid for all_flags_state (#{context.error})" }
348
295
  return FeatureFlagsState.new(false)
349
296
  end
350
297
 
@@ -364,13 +311,13 @@ module LaunchDarkly
364
311
  next
365
312
  end
366
313
  begin
367
- detail = @evaluator.evaluate(f, user).detail
314
+ detail = @evaluator.evaluate(f, context).detail
368
315
  rescue => exn
369
316
  detail = EvaluationDetail.new(nil, nil, EvaluationReason::error(EvaluationReason::ERROR_EXCEPTION))
370
317
  Util.log_exception(@config.logger, "Error evaluating flag \"#{k}\" in all_flags_state", exn)
371
318
  end
372
319
 
373
- requires_experiment_data = is_experiment(f, detail.reason)
320
+ requires_experiment_data = experiment?(f, detail.reason)
374
321
  flag_state = {
375
322
  key: f[:key],
376
323
  value: detail.value,
@@ -425,32 +372,34 @@ module LaunchDarkly
425
372
  end
426
373
  end
427
374
 
375
+ # @param context [Hash, LDContext]
428
376
  # @return [EvaluationDetail]
429
- def evaluate_internal(key, user, default, with_reasons)
377
+ def evaluate_internal(key, context, default, with_reasons)
430
378
  if @config.offline?
431
379
  return Evaluator.error_result(EvaluationReason::ERROR_CLIENT_NOT_READY, default)
432
380
  end
433
381
 
434
- unless user
435
- @config.logger.error { "[LDClient] Must specify user" }
382
+ if context.nil?
383
+ @config.logger.error { "[LDClient] Must specify context" }
436
384
  detail = Evaluator.error_result(EvaluationReason::ERROR_USER_NOT_SPECIFIED, default)
437
385
  return detail
438
386
  end
439
387
 
440
- if user[:key].nil?
441
- @config.logger.warn { "[LDClient] Variation called with nil user key; returning default value" }
388
+ context = Impl::Context::make_context(context)
389
+ unless context.valid?
390
+ @config.logger.error { "[LDClient] Context was invalid for flag evaluation (#{context.error}); returning default value" }
442
391
  detail = Evaluator.error_result(EvaluationReason::ERROR_USER_NOT_SPECIFIED, default)
443
392
  return detail
444
393
  end
445
394
 
446
- if !initialized?
395
+ unless initialized?
447
396
  if @store.initialized?
448
397
  @config.logger.warn { "[LDClient] Client has not finished initializing; using last known values from feature store" }
449
398
  else
450
399
  @config.logger.error { "[LDClient] Client has not finished initializing; feature store unavailable, returning default value" }
451
400
  detail = Evaluator.error_result(EvaluationReason::ERROR_CLIENT_NOT_READY, default)
452
- record_unknown_flag_eval(key, user, default, detail.reason, with_reasons)
453
- return detail
401
+ record_unknown_flag_eval(key, context, default, detail.reason, with_reasons)
402
+ return detail
454
403
  end
455
404
  end
456
405
 
@@ -459,35 +408,35 @@ module LaunchDarkly
459
408
  if feature.nil?
460
409
  @config.logger.info { "[LDClient] Unknown feature flag \"#{key}\". Returning default value" }
461
410
  detail = Evaluator.error_result(EvaluationReason::ERROR_FLAG_NOT_FOUND, default)
462
- record_unknown_flag_eval(key, user, default, detail.reason, with_reasons)
411
+ record_unknown_flag_eval(key, context, default, detail.reason, with_reasons)
463
412
  return detail
464
413
  end
465
414
 
466
415
  begin
467
- res = @evaluator.evaluate(feature, user)
468
- if !res.prereq_evals.nil?
416
+ res = @evaluator.evaluate(feature, context)
417
+ unless res.prereq_evals.nil?
469
418
  res.prereq_evals.each do |prereq_eval|
470
- record_prereq_flag_eval(prereq_eval.prereq_flag, prereq_eval.prereq_of_flag, user, prereq_eval.detail, with_reasons)
419
+ record_prereq_flag_eval(prereq_eval.prereq_flag, prereq_eval.prereq_of_flag, context, prereq_eval.detail, with_reasons)
471
420
  end
472
421
  end
473
422
  detail = res.detail
474
423
  if detail.default_value?
475
424
  detail = EvaluationDetail.new(default, nil, detail.reason)
476
425
  end
477
- record_flag_eval(feature, user, detail, default, with_reasons)
478
- return detail
426
+ record_flag_eval(feature, context, detail, default, with_reasons)
427
+ detail
479
428
  rescue => exn
480
429
  Util.log_exception(@config.logger, "Error evaluating feature flag \"#{key}\"", exn)
481
430
  detail = Evaluator.error_result(EvaluationReason::ERROR_EXCEPTION, default)
482
- record_flag_eval_error(feature, user, default, detail.reason, with_reasons)
483
- return detail
431
+ record_flag_eval_error(feature, context, default, detail.reason, with_reasons)
432
+ detail
484
433
  end
485
434
  end
486
435
 
487
- private def record_flag_eval(flag, user, detail, default, with_reasons)
488
- add_experiment_data = is_experiment(flag, detail.reason)
436
+ private def record_flag_eval(flag, context, detail, default, with_reasons)
437
+ add_experiment_data = experiment?(flag, detail.reason)
489
438
  @event_processor.record_eval_event(
490
- user,
439
+ context,
491
440
  flag[:key],
492
441
  flag[:version],
493
442
  detail.variation_index,
@@ -499,11 +448,11 @@ module LaunchDarkly
499
448
  nil
500
449
  )
501
450
  end
502
-
503
- private def record_prereq_flag_eval(prereq_flag, prereq_of_flag, user, detail, with_reasons)
504
- add_experiment_data = is_experiment(prereq_flag, detail.reason)
451
+
452
+ private def record_prereq_flag_eval(prereq_flag, prereq_of_flag, context, detail, with_reasons)
453
+ add_experiment_data = experiment?(prereq_flag, detail.reason)
505
454
  @event_processor.record_eval_event(
506
- user,
455
+ context,
507
456
  prereq_flag[:key],
508
457
  prereq_flag[:version],
509
458
  detail.variation_index,
@@ -515,19 +464,26 @@ module LaunchDarkly
515
464
  prereq_of_flag[:key]
516
465
  )
517
466
  end
518
-
519
- private def record_flag_eval_error(flag, user, default, reason, with_reasons)
520
- @event_processor.record_eval_event(user, flag[:key], flag[:version], nil, default, with_reasons ? reason : nil, default,
467
+
468
+ private def record_flag_eval_error(flag, context, default, reason, with_reasons)
469
+ @event_processor.record_eval_event(context, flag[:key], flag[:version], nil, default, with_reasons ? reason : nil, default,
521
470
  flag[:trackEvents], flag[:debugEventsUntilDate], nil)
522
471
  end
523
472
 
524
- private def record_unknown_flag_eval(flag_key, user, default, reason, with_reasons)
525
- @event_processor.record_eval_event(user, flag_key, nil, nil, default, with_reasons ? reason : nil, default,
473
+ #
474
+ # @param flag_key [String]
475
+ # @param context [LaunchDarkly::LDContext]
476
+ # @param default [any]
477
+ # @param reason [LaunchDarkly::EvaluationReason]
478
+ # @param with_reasons [Boolean]
479
+ #
480
+ private def record_unknown_flag_eval(flag_key, context, default, reason, with_reasons)
481
+ @event_processor.record_eval_event(context, flag_key, nil, nil, default, with_reasons ? reason : nil, default,
526
482
  false, nil, nil)
527
483
  end
528
484
 
529
- private def is_experiment(flag, reason)
530
- return false if !reason
485
+ private def experiment?(flag, reason)
486
+ return false unless reason
531
487
 
532
488
  if reason.in_experiment
533
489
  return true
@@ -536,7 +492,7 @@ module LaunchDarkly
536
492
  case reason[:kind]
537
493
  when 'RULE_MATCH'
538
494
  index = reason[:ruleIndex]
539
- if !index.nil?
495
+ unless index.nil?
540
496
  rules = flag[:rules] || []
541
497
  return index >= 0 && index < rules.length && rules[index][:trackEvents]
542
498
  end
@@ -545,12 +501,6 @@ module LaunchDarkly
545
501
  end
546
502
  false
547
503
  end
548
-
549
- private def sanitize_user(user)
550
- if user[:key]
551
- user[:key] = user[:key].to_s
552
- end
553
- end
554
504
  end
555
505
 
556
506
  #
@@ -14,7 +14,7 @@ module LaunchDarkly
14
14
 
15
15
  def get
16
16
  @mutex.synchronize do
17
- if !@inited
17
+ unless @inited
18
18
  @value = @generator.call
19
19
  @inited = true
20
20
  end
@@ -17,7 +17,7 @@ module LaunchDarkly
17
17
  # Attempts to submit a job, but only if a worker is available. Unlike the regular post method,
18
18
  # this returns a value: true if the job was submitted, false if all workers are busy.
19
19
  def post
20
- if !@semaphore.try_acquire(1)
20
+ unless @semaphore.try_acquire(1)
21
21
  return
22
22
  end
23
23
  @pool.post do
@@ -43,8 +43,8 @@ module LaunchDarkly
43
43
  end
44
44
  rescue UnexpectedResponseError => e
45
45
  message = Util.http_error_message(e.status, "polling request", "will retry")
46
- @config.logger.error { "[LDClient] #{message}" };
47
- if !Util.http_error_recoverable?(e.status)
46
+ @config.logger.error { "[LDClient] #{message}" }
47
+ unless Util.http_error_recoverable?(e.status)
48
48
  @ready.set # if client was waiting on us, make it stop waiting - has no effect if already set
49
49
  stop
50
50
  end