launchdarkly-server-sdk 6.4.0 → 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 +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 +28 -31
  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 +8 -121
  25. data/lib/ldclient-rb/impl/model/segment.rb +126 -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
@@ -0,0 +1,487 @@
1
+ require 'set'
2
+ require 'ldclient-rb/impl/context'
3
+ require 'ldclient-rb/reference'
4
+
5
+ module LaunchDarkly
6
+ # LDContext is a collection of attributes that can be referenced in flag
7
+ # evaluations and analytics events.
8
+ #
9
+ # To create an LDContext of a single kind, such as a user, you may use
10
+ # {LDContext#create} or {LDContext#with_key}.
11
+ #
12
+ # To create an LDContext with multiple kinds, use {LDContext#create_multi}.
13
+ #
14
+ # Each factory method will always return an LDContext. However, that
15
+ # LDContext may be invalid. You can check the validity of the resulting
16
+ # context, and the associated errors by calling {LDContext#valid?} and
17
+ # {LDContext#error}
18
+ class LDContext
19
+ KIND_DEFAULT = "user"
20
+ KIND_MULTI = "multi"
21
+
22
+ ERR_NOT_HASH = 'context data is not a hash'
23
+ private_constant :ERR_NOT_HASH
24
+ ERR_KEY_EMPTY = 'context key must not be null or empty'
25
+ private_constant :ERR_KEY_EMPTY
26
+ ERR_KIND_MULTI_NON_CONTEXT_ARRAY = 'context data must be an array of valid LDContexts'
27
+ private_constant :ERR_KIND_MULTI_NON_CONTEXT_ARRAY
28
+ ERR_KIND_MULTI_CANNOT_CONTAIN_MULTI = 'multi-kind context cannot contain another multi-kind context'
29
+ private_constant :ERR_KIND_MULTI_CANNOT_CONTAIN_MULTI
30
+ ERR_KIND_MULTI_WITH_NO_KINDS = 'multi-context must contain at least one kind'
31
+ private_constant :ERR_KIND_MULTI_WITH_NO_KINDS
32
+ ERR_KIND_MULTI_DUPLICATES = 'multi-kind context cannot have same kind more than once'
33
+ private_constant :ERR_KIND_MULTI_DUPLICATES
34
+ ERR_CUSTOM_NON_HASH = 'context custom must be a hash'
35
+ private_constant :ERR_CUSTOM_NON_HASH
36
+ ERR_PRIVATE_NON_ARRAY = 'context private attributes must be an array'
37
+
38
+ # @return [String, nil] Returns the key for this context
39
+ attr_reader :key
40
+
41
+ # @return [String, nil] Returns the fully qualified key for this context
42
+ attr_reader :fully_qualified_key
43
+
44
+ # @return [String, nil] Returns the kind for this context
45
+ attr_reader :kind
46
+
47
+ # @return [String, nil] Returns the error associated with this LDContext if invalid
48
+ attr_reader :error
49
+
50
+ # @return [Array<Reference>] Returns the private attributes associated with this LDContext
51
+ attr_reader :private_attributes
52
+
53
+ #
54
+ # @private
55
+ # @param key [String, nil]
56
+ # @param fully_qualified_key [String, nil]
57
+ # @param kind [String, nil]
58
+ # @param name [String, nil]
59
+ # @param anonymous [Boolean, nil]
60
+ # @param attributes [Hash, nil]
61
+ # @param private_attributes [Array<String>, nil]
62
+ # @param error [String, nil]
63
+ # @param contexts [Array<LDContext>, nil]
64
+ #
65
+ def initialize(key, fully_qualified_key, kind, name = nil, anonymous = nil, attributes = nil, private_attributes = nil, error = nil, contexts = nil)
66
+ @key = key
67
+ @fully_qualified_key = fully_qualified_key
68
+ @kind = kind
69
+ @name = name
70
+ @anonymous = anonymous || false
71
+ @attributes = attributes
72
+ @private_attributes = []
73
+ (private_attributes || []).each do |attribute|
74
+ reference = Reference.create(attribute)
75
+ @private_attributes << reference if reference.error.nil?
76
+ end
77
+ @error = error
78
+ @contexts = contexts
79
+ @is_multi = !contexts.nil?
80
+ end
81
+ private_class_method :new
82
+
83
+ #
84
+ # @return [Boolean] Is this LDContext a multi-kind context?
85
+ #
86
+ def multi_kind?
87
+ @is_multi
88
+ end
89
+
90
+ #
91
+ # @return [Boolean] Determine if this LDContext is considered valid
92
+ #
93
+ def valid?
94
+ @error.nil?
95
+ end
96
+
97
+ #
98
+ # Returns a hash mapping each context's kind to its key.
99
+ #
100
+ # @return [Hash<Symbol, String>]
101
+ #
102
+ def keys
103
+ return {} unless valid?
104
+ return Hash[kind, key] unless multi_kind?
105
+
106
+ @contexts.map { |c| [c.kind, c.key] }.to_h
107
+ end
108
+
109
+ #
110
+ # Returns an array of context kinds.
111
+ #
112
+ # @return [Array<String>]
113
+ #
114
+ def kinds
115
+ return [] unless valid?
116
+ return [kind] unless multi_kind?
117
+
118
+ @contexts.map { |c| c.kind }
119
+ end
120
+
121
+ #
122
+ # Return an array of top level attribute keys (excluding built-in attributes)
123
+ #
124
+ # @return [Array<Symbol>]
125
+ #
126
+ def get_custom_attribute_names
127
+ return [] if @attributes.nil?
128
+
129
+ @attributes.keys
130
+ end
131
+
132
+ #
133
+ # get_value looks up the value of any attribute of the Context by name.
134
+ # This includes only attributes that are addressable in evaluations-- not
135
+ # metadata such as private attributes.
136
+ #
137
+ # For a single-kind context, the attribute name can be any custom attribute.
138
+ # It can also be one of the built-in ones like "kind", "key", or "name".
139
+ #
140
+ # For a multi-kind context, the only supported attribute name is "kind".
141
+ # Use {#individual_context} to inspect a Context for a particular kind and
142
+ # then get its attributes.
143
+ #
144
+ # This method does not support complex expressions for getting individual
145
+ # values out of JSON objects or arrays, such as "/address/street". Use
146
+ # {#get_value_for_reference} for that purpose.
147
+ #
148
+ # If the value is found, the return value is the attribute value;
149
+ # otherwise, it is nil.
150
+ #
151
+ # @param attribute [String, Symbol]
152
+ # @return [any]
153
+ #
154
+ def get_value(attribute)
155
+ reference = Reference.create_literal(attribute)
156
+ get_value_for_reference(reference)
157
+ end
158
+
159
+ #
160
+ # get_value_for_reference looks up the value of any attribute of the
161
+ # Context, or a value contained within an attribute, based on a {Reference}
162
+ # instance. This includes only attributes that are addressable in
163
+ # evaluations-- not metadata such as private attributes.
164
+ #
165
+ # This implements the same behavior that the SDK uses to resolve attribute
166
+ # references during a flag evaluation. In a single-kind context, the
167
+ # {Reference} can represent a simple attribute name-- either a built-in one
168
+ # like "name" or "key", or a custom attribute -- or, it can be a
169
+ # slash-delimited path using a JSON-Pointer-like syntax. See {Reference}
170
+ # for more details.
171
+ #
172
+ # For a multi-kind context, the only supported attribute name is "kind".
173
+ # Use {#individual_context} to inspect a Context for a particular kind and
174
+ # then get its attributes.
175
+ #
176
+ # If the value is found, the return value is the attribute value;
177
+ # otherwise, it is nil.
178
+ #
179
+ # @param reference [Reference]
180
+ # @return [any]
181
+ #
182
+ def get_value_for_reference(reference)
183
+ return nil unless valid?
184
+ return nil unless reference.is_a?(Reference)
185
+ return nil unless reference.error.nil?
186
+
187
+ first_component = reference.component(0)
188
+ return nil if first_component.nil?
189
+
190
+ if multi_kind?
191
+ if reference.depth == 1 && first_component == :kind
192
+ return kind
193
+ end
194
+
195
+ # Multi-kind contexts have no other addressable attributes
196
+ return nil
197
+ end
198
+
199
+ value = get_top_level_addressable_attribute_single_kind(first_component)
200
+ return nil if value.nil?
201
+
202
+ (1...reference.depth).each do |i|
203
+ name = reference.component(i)
204
+
205
+ return nil unless value.is_a?(Hash)
206
+ return nil unless value.has_key?(name)
207
+
208
+ value = value[name]
209
+ end
210
+
211
+ value
212
+ end
213
+
214
+ #
215
+ # Returns the number of context kinds in this context.
216
+ #
217
+ # For a valid individual context, this returns 1. For a multi-context, it
218
+ # returns the number of context kinds. For an invalid context, it returns
219
+ # zero.
220
+ #
221
+ # @return [Integer] the number of context kinds
222
+ #
223
+ def individual_context_count
224
+ return 0 unless valid?
225
+ return 1 if @contexts.nil?
226
+ @contexts.count
227
+ end
228
+
229
+ #
230
+ # Returns the single-kind LDContext corresponding to one of the kinds in
231
+ # this context.
232
+ #
233
+ # The `kind` parameter can be either a number representing a zero-based
234
+ # index, or a string representing a context kind.
235
+ #
236
+ # If this method is called on a single-kind LDContext, then the only
237
+ # allowable value for `kind` is either zero or the same value as {#kind},
238
+ # and the return value on success is the same LDContext.
239
+ #
240
+ # If the method is called on a multi-context, and `kind` is a number, it
241
+ # must be a non-negative index that is less than the number of kinds (that
242
+ # is, less than the return value of {#individual_context_count}, and the
243
+ # return value on success is one of the individual LDContexts within. Or,
244
+ # if `kind` is a string, it must match the context kind of one of the
245
+ # individual contexts.
246
+ #
247
+ # If there is no context corresponding to `kind`, the method returns nil.
248
+ #
249
+ # @param kind [Integer, String] the index or string value of a context kind
250
+ # @return [LDContext, nil] the context corresponding to that index or kind,
251
+ # or null if none.
252
+ #
253
+ def individual_context(kind)
254
+ return nil unless valid?
255
+
256
+ if kind.is_a?(Integer)
257
+ unless multi_kind?
258
+ return kind == 0 ? self : nil
259
+ end
260
+
261
+ return kind >= 0 && kind < @contexts.count ? @contexts[kind] : nil
262
+ end
263
+
264
+ return nil unless kind.is_a?(String)
265
+
266
+ unless multi_kind?
267
+ return self.kind == kind ? self : nil
268
+ end
269
+
270
+ @contexts.each do |context|
271
+ return context if context.kind == kind
272
+ end
273
+
274
+ nil
275
+ end
276
+
277
+ #
278
+ # Retrieve the value of any top level, addressable attribute.
279
+ #
280
+ # This method returns an array of two values. The first element is the
281
+ # value of the requested attribute or nil if it does not exist. The second
282
+ # value will be true if the attribute exists; otherwise, it will be false.
283
+ #
284
+ # @param name [Symbol]
285
+ # @return [any]
286
+ #
287
+ private def get_top_level_addressable_attribute_single_kind(name)
288
+ case name
289
+ when :kind
290
+ kind
291
+ when :key
292
+ key
293
+ when :name
294
+ @name
295
+ when :anonymous
296
+ @anonymous
297
+ else
298
+ @attributes&.fetch(name, nil)
299
+ end
300
+ end
301
+
302
+ #
303
+ # Convenience method to create a simple single kind context providing only
304
+ # a key and kind type.
305
+ #
306
+ # @param key [String]
307
+ # @param kind [String]
308
+ #
309
+ def self.with_key(key, kind = KIND_DEFAULT)
310
+ create({key: key, kind: kind})
311
+ end
312
+
313
+ #
314
+ # Create a single kind context from the provided hash.
315
+ #
316
+ # The provided hash must match the format as outlined in the
317
+ # {https://docs.launchdarkly.com/sdk/features/user-config SDK
318
+ # documentation}.
319
+ #
320
+ # @param data [Hash]
321
+ # @return [LDContext]
322
+ #
323
+ def self.create(data)
324
+ return create_invalid_context(ERR_NOT_HASH) unless data.is_a?(Hash)
325
+ return create_legacy_context(data) unless data.has_key?(:kind)
326
+
327
+ kind = data[:kind]
328
+ if kind == KIND_MULTI
329
+ contexts = []
330
+ data.each do |key, value|
331
+ next if key == :kind
332
+ contexts << create_single_context(value, key.to_s)
333
+ end
334
+
335
+ return create_multi(contexts)
336
+ end
337
+
338
+ create_single_context(data, kind)
339
+ end
340
+
341
+ #
342
+ # Create a multi-kind context from the array of LDContexts provided.
343
+ #
344
+ # A multi-kind context is comprised of two or more single kind contexts.
345
+ # You cannot include a multi-kind context instead another multi-kind
346
+ # context.
347
+ #
348
+ # Additionally, the kind of each single-kind context must be unique. For
349
+ # instance, you cannot create a multi-kind context that includes two user
350
+ # kind contexts.
351
+ #
352
+ # If you attempt to create a multi-kind context from one single-kind
353
+ # context, this method will return the single-kind context instead of a new
354
+ # multi-kind context wrapping that one single-kind.
355
+ #
356
+ # @param contexts [Array<LDContext>]
357
+ # @return [LDContext]
358
+ #
359
+ def self.create_multi(contexts)
360
+ return create_invalid_context(ERR_KIND_MULTI_NON_CONTEXT_ARRAY) unless contexts.is_a?(Array)
361
+ return create_invalid_context(ERR_KIND_MULTI_WITH_NO_KINDS) if contexts.empty?
362
+
363
+ kinds = Set.new
364
+ contexts.each do |context|
365
+ if !context.is_a?(LDContext)
366
+ return create_invalid_context(ERR_KIND_MULTI_NON_CONTEXT_ARRAY)
367
+ elsif !context.valid?
368
+ return create_invalid_context(ERR_KIND_MULTI_NON_CONTEXT_ARRAY)
369
+ elsif context.multi_kind?
370
+ return create_invalid_context(ERR_KIND_MULTI_CANNOT_CONTAIN_MULTI)
371
+ elsif kinds.include? context.kind
372
+ return create_invalid_context(ERR_KIND_MULTI_DUPLICATES)
373
+ end
374
+
375
+ kinds.add(context.kind)
376
+ end
377
+
378
+ return contexts[0] if contexts.length == 1
379
+
380
+ full_key = contexts.sort_by(&:kind)
381
+ .map { |c| LaunchDarkly::Impl::Context::canonicalize_key_for_kind(c.kind, c.key) }
382
+ .join(":")
383
+
384
+ new(nil, full_key, "multi", nil, false, nil, nil, nil, contexts)
385
+ end
386
+
387
+ #
388
+ # @param error [String]
389
+ # @return [LDContext]
390
+ #
391
+ private_class_method def self.create_invalid_context(error)
392
+ new(nil, nil, nil, nil, false, nil, nil, error)
393
+ end
394
+
395
+ #
396
+ # @param data [Hash]
397
+ # @return [LDContext]
398
+ #
399
+ private_class_method def self.create_legacy_context(data)
400
+ key = data[:key]
401
+
402
+ # Legacy users are allowed to have "" as a key but they cannot have nil as a key.
403
+ return create_invalid_context(ERR_KEY_EMPTY) if key.nil?
404
+
405
+ name = data[:name]
406
+ name_error = LaunchDarkly::Impl::Context.validate_name(name)
407
+ return create_invalid_context(name_error) unless name_error.nil?
408
+
409
+ anonymous = data[:anonymous]
410
+ anonymous_error = LaunchDarkly::Impl::Context.validate_anonymous(anonymous, true)
411
+ return create_invalid_context(anonymous_error) unless anonymous_error.nil?
412
+
413
+ custom = data[:custom]
414
+ unless custom.nil? || custom.is_a?(Hash)
415
+ return create_invalid_context(ERR_CUSTOM_NON_HASH)
416
+ end
417
+
418
+ # We only need to create an attribute hash if one of these keys exist.
419
+ # Everything else is stored in dedicated instance variables.
420
+ attributes = custom.clone
421
+ data.each do |k, v|
422
+ case k
423
+ when :ip, :email, :avatar, :firstName, :lastName, :country
424
+ attributes ||= {}
425
+ attributes[k] = v.clone
426
+ else
427
+ next
428
+ end
429
+ end
430
+
431
+ private_attributes = data[:privateAttributeNames]
432
+ if private_attributes && !private_attributes.is_a?(Array)
433
+ return create_invalid_context(ERR_PRIVATE_NON_ARRAY)
434
+ end
435
+
436
+ new(key.to_s, key.to_s, KIND_DEFAULT, name, anonymous, attributes, private_attributes)
437
+ end
438
+
439
+ #
440
+ # @param data [Hash]
441
+ # @param kind [String]
442
+ # @return [LaunchDarkly::LDContext]
443
+ #
444
+ private_class_method def self.create_single_context(data, kind)
445
+ unless data.is_a?(Hash)
446
+ return create_invalid_context(ERR_NOT_HASH)
447
+ end
448
+
449
+ kind_error = LaunchDarkly::Impl::Context.validate_kind(kind)
450
+ return create_invalid_context(kind_error) unless kind_error.nil?
451
+
452
+ key = data[:key]
453
+ key_error = LaunchDarkly::Impl::Context.validate_key(key)
454
+ return create_invalid_context(key_error) unless key_error.nil?
455
+
456
+ name = data[:name]
457
+ name_error = LaunchDarkly::Impl::Context.validate_name(name)
458
+ return create_invalid_context(name_error) unless name_error.nil?
459
+
460
+ anonymous = data.fetch(:anonymous, false)
461
+ anonymous_error = LaunchDarkly::Impl::Context.validate_anonymous(anonymous, false)
462
+ return create_invalid_context(anonymous_error) unless anonymous_error.nil?
463
+
464
+ meta = data.fetch(:_meta, {})
465
+ private_attributes = meta[:privateAttributes]
466
+ if private_attributes && !private_attributes.is_a?(Array)
467
+ return create_invalid_context(ERR_PRIVATE_NON_ARRAY)
468
+ end
469
+
470
+ # We only need to create an attribute hash if there are keys set outside
471
+ # of the ones we store in dedicated instance variables.
472
+ attributes = nil
473
+ data.each do |k, v|
474
+ case k
475
+ when :kind, :key, :name, :anonymous, :_meta
476
+ next
477
+ else
478
+ attributes ||= {}
479
+ attributes[k] = v.clone
480
+ end
481
+ end
482
+
483
+ full_key = kind == LDContext::KIND_DEFAULT ? key.to_s : LaunchDarkly::Impl::Context::canonicalize_key_for_kind(kind, key.to_s)
484
+ new(key.to_s, full_key, kind, name, anonymous, attributes, private_attributes)
485
+ end
486
+ end
487
+ end
@@ -12,7 +12,7 @@ module LaunchDarkly
12
12
  # @raise [ArgumentError] if `variation_index` or `reason` is not of the correct type
13
13
  def initialize(value, variation_index, reason)
14
14
  raise ArgumentError.new("variation_index must be a number") if !variation_index.nil? && !(variation_index.is_a? Numeric)
15
- raise ArgumentError.new("reason must be an EvaluationReason") if !(reason.is_a? EvaluationReason)
15
+ raise ArgumentError.new("reason must be an EvaluationReason") unless reason.is_a? EvaluationReason
16
16
  @value = value
17
17
  @variation_index = variation_index
18
18
  @reason = reason
@@ -70,20 +70,20 @@ module LaunchDarkly
70
70
  class EvaluationReason
71
71
  # Value for {#kind} indicating that the flag was off and therefore returned its configured off value.
72
72
  OFF = :OFF
73
-
74
- # Value for {#kind} indicating that the flag was on but the user did not match any targets or rules.
73
+
74
+ # Value for {#kind} indicating that the flag was on but the context did not match any targets or rules.
75
75
  FALLTHROUGH = :FALLTHROUGH
76
-
77
- # Value for {#kind} indicating that the user key was specifically targeted for this flag.
76
+
77
+ # Value for {#kind} indicating that the context key was specifically targeted for this flag.
78
78
  TARGET_MATCH = :TARGET_MATCH
79
-
80
- # Value for {#kind} indicating that the user matched one of the flag's rules.
79
+
80
+ # Value for {#kind} indicating that the context matched one of the flag's rules.
81
81
  RULE_MATCH = :RULE_MATCH
82
-
82
+
83
83
  # Value for {#kind} indicating that the flag was considered off because it had at least one
84
84
  # prerequisite flag that either was off or did not return the desired variation.
85
85
  PREREQUISITE_FAILED = :PREREQUISITE_FAILED
86
-
86
+
87
87
  # Value for {#kind} indicating that the flag could not be evaluated, e.g. because it does not exist
88
88
  # or due to an unexpected error. In this case the result value will be the application default value
89
89
  # that the caller passed to the client. Check {#error_kind} for more details on the problem.
@@ -100,8 +100,8 @@ module LaunchDarkly
100
100
  # a rule specified a nonexistent variation. An error message will always be logged in this case.
101
101
  ERROR_MALFORMED_FLAG = :MALFORMED_FLAG
102
102
 
103
- # Value for {#error_kind} indicating that the caller passed `nil` for the user parameter, or the
104
- # user lacked a key.
103
+ # Value for {#error_kind} indicating that the caller passed `nil` for the context parameter, or the
104
+ # context was invalid.
105
105
  ERROR_USER_NOT_SPECIFIED = :USER_NOT_SPECIFIED
106
106
 
107
107
  # Value for {#error_kind} indicating that an unexpected exception stopped flag evaluation. An error
@@ -141,7 +141,7 @@ module LaunchDarkly
141
141
  # querying at least one Big Segment. Otherwise it returns `nil`. Possible values are defined by
142
142
  # {BigSegmentsStatus}.
143
143
  #
144
- # Big Segments are a specific kind of user segments. For more information, read the LaunchDarkly
144
+ # Big Segments are a specific kind of context segments. For more information, read the LaunchDarkly
145
145
  # documentation: https://docs.launchdarkly.com/home/users/big-segments
146
146
  # @return [Symbol]
147
147
  attr_reader :big_segments_status
@@ -176,9 +176,9 @@ module LaunchDarkly
176
176
  # @return [EvaluationReason]
177
177
  # @raise [ArgumentError] if `rule_index` is not a number or `rule_id` is not a string
178
178
  def self.rule_match(rule_index, rule_id, in_experiment=false)
179
- raise ArgumentError.new("rule_index must be a number") if !(rule_index.is_a? Numeric)
179
+ raise ArgumentError.new("rule_index must be a number") unless rule_index.is_a? Numeric
180
180
  raise ArgumentError.new("rule_id must be a string") if !rule_id.nil? && !(rule_id.is_a? String) # in test data, ID could be nil
181
-
181
+
182
182
  if in_experiment
183
183
  er = new(:RULE_MATCH, rule_index, rule_id, nil, nil, true)
184
184
  else
@@ -193,7 +193,7 @@ module LaunchDarkly
193
193
  # @return [EvaluationReason]
194
194
  # @raise [ArgumentError] if `prerequisite_key` is nil or not a string
195
195
  def self.prerequisite_failed(prerequisite_key)
196
- raise ArgumentError.new("prerequisite_key must be a string") if !(prerequisite_key.is_a? String)
196
+ raise ArgumentError.new("prerequisite_key must be a string") unless prerequisite_key.is_a? String
197
197
  new(:PREREQUISITE_FAILED, nil, nil, prerequisite_key, nil)
198
198
  end
199
199
 
@@ -203,7 +203,7 @@ module LaunchDarkly
203
203
  # @return [EvaluationReason]
204
204
  # @raise [ArgumentError] if `error_kind` is not a symbol
205
205
  def self.error(error_kind)
206
- raise ArgumentError.new("error_kind must be a symbol") if !(error_kind.is_a? Symbol)
206
+ raise ArgumentError.new("error_kind must be a symbol") unless error_kind.is_a? Symbol
207
207
  e = @@error_instances[error_kind]
208
208
  e.nil? ? make_error(error_kind) : e
209
209
  end
@@ -279,7 +279,7 @@ module LaunchDarkly
279
279
  else
280
280
  { kind: @kind }
281
281
  end
282
- if !@big_segments_status.nil?
282
+ unless @big_segments_status.nil?
283
283
  ret[:bigSegmentsStatus] = @big_segments_status
284
284
  end
285
285
  ret
@@ -327,9 +327,9 @@ module LaunchDarkly
327
327
  @kind = kind.to_sym
328
328
  @rule_index = rule_index
329
329
  @rule_id = rule_id
330
- @rule_id.freeze if !rule_id.nil?
330
+ @rule_id.freeze unless rule_id.nil?
331
331
  @prerequisite_key = prerequisite_key
332
- @prerequisite_key.freeze if !prerequisite_key.nil?
332
+ @prerequisite_key.freeze unless prerequisite_key.nil?
333
333
  @error_kind = error_kind
334
334
  @in_experiment = in_experiment
335
335
  @big_segments_status = big_segments_status
@@ -348,7 +348,7 @@ module LaunchDarkly
348
348
  ERROR_FLAG_NOT_FOUND => make_error(ERROR_FLAG_NOT_FOUND),
349
349
  ERROR_MALFORMED_FLAG => make_error(ERROR_MALFORMED_FLAG),
350
350
  ERROR_USER_NOT_SPECIFIED => make_error(ERROR_USER_NOT_SPECIFIED),
351
- ERROR_EXCEPTION => make_error(ERROR_EXCEPTION)
351
+ ERROR_EXCEPTION => make_error(ERROR_EXCEPTION),
352
352
  }
353
353
  end
354
354