launchdarkly-server-sdk 6.3.0 → 8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -4
  3. data/lib/ldclient-rb/config.rb +112 -62
  4. data/lib/ldclient-rb/context.rb +444 -0
  5. data/lib/ldclient-rb/evaluation_detail.rb +26 -22
  6. data/lib/ldclient-rb/events.rb +256 -146
  7. data/lib/ldclient-rb/flags_state.rb +26 -15
  8. data/lib/ldclient-rb/impl/big_segments.rb +18 -18
  9. data/lib/ldclient-rb/impl/broadcaster.rb +78 -0
  10. data/lib/ldclient-rb/impl/context.rb +96 -0
  11. data/lib/ldclient-rb/impl/context_filter.rb +145 -0
  12. data/lib/ldclient-rb/impl/data_source.rb +188 -0
  13. data/lib/ldclient-rb/impl/data_store.rb +59 -0
  14. data/lib/ldclient-rb/impl/dependency_tracker.rb +102 -0
  15. data/lib/ldclient-rb/impl/diagnostic_events.rb +9 -10
  16. data/lib/ldclient-rb/impl/evaluator.rb +386 -142
  17. data/lib/ldclient-rb/impl/evaluator_bucketing.rb +40 -41
  18. data/lib/ldclient-rb/impl/evaluator_helpers.rb +50 -0
  19. data/lib/ldclient-rb/impl/evaluator_operators.rb +26 -55
  20. data/lib/ldclient-rb/impl/event_sender.rb +7 -6
  21. data/lib/ldclient-rb/impl/event_summarizer.rb +68 -0
  22. data/lib/ldclient-rb/impl/event_types.rb +136 -0
  23. data/lib/ldclient-rb/impl/flag_tracker.rb +58 -0
  24. data/lib/ldclient-rb/impl/integrations/consul_impl.rb +19 -7
  25. data/lib/ldclient-rb/impl/integrations/dynamodb_impl.rb +38 -30
  26. data/lib/ldclient-rb/impl/integrations/file_data_source.rb +24 -11
  27. data/lib/ldclient-rb/impl/integrations/redis_impl.rb +109 -12
  28. data/lib/ldclient-rb/impl/migrations/migrator.rb +287 -0
  29. data/lib/ldclient-rb/impl/migrations/tracker.rb +136 -0
  30. data/lib/ldclient-rb/impl/model/clause.rb +45 -0
  31. data/lib/ldclient-rb/impl/model/feature_flag.rb +255 -0
  32. data/lib/ldclient-rb/impl/model/preprocessed_data.rb +64 -0
  33. data/lib/ldclient-rb/impl/model/segment.rb +132 -0
  34. data/lib/ldclient-rb/impl/model/serialization.rb +54 -44
  35. data/lib/ldclient-rb/impl/repeating_task.rb +3 -4
  36. data/lib/ldclient-rb/impl/sampler.rb +25 -0
  37. data/lib/ldclient-rb/impl/store_client_wrapper.rb +102 -8
  38. data/lib/ldclient-rb/impl/store_data_set_sorter.rb +2 -2
  39. data/lib/ldclient-rb/impl/unbounded_pool.rb +1 -1
  40. data/lib/ldclient-rb/impl/util.rb +59 -1
  41. data/lib/ldclient-rb/in_memory_store.rb +9 -2
  42. data/lib/ldclient-rb/integrations/consul.rb +2 -2
  43. data/lib/ldclient-rb/integrations/dynamodb.rb +2 -2
  44. data/lib/ldclient-rb/integrations/file_data.rb +4 -4
  45. data/lib/ldclient-rb/integrations/redis.rb +5 -5
  46. data/lib/ldclient-rb/integrations/test_data/flag_builder.rb +287 -62
  47. data/lib/ldclient-rb/integrations/test_data.rb +18 -14
  48. data/lib/ldclient-rb/integrations/util/store_wrapper.rb +20 -9
  49. data/lib/ldclient-rb/interfaces.rb +600 -14
  50. data/lib/ldclient-rb/ldclient.rb +314 -134
  51. data/lib/ldclient-rb/memoized_value.rb +1 -1
  52. data/lib/ldclient-rb/migrations.rb +230 -0
  53. data/lib/ldclient-rb/non_blocking_thread_pool.rb +1 -1
  54. data/lib/ldclient-rb/polling.rb +52 -6
  55. data/lib/ldclient-rb/reference.rb +274 -0
  56. data/lib/ldclient-rb/requestor.rb +9 -11
  57. data/lib/ldclient-rb/stream.rb +96 -34
  58. data/lib/ldclient-rb/util.rb +97 -14
  59. data/lib/ldclient-rb/version.rb +1 -1
  60. data/lib/ldclient-rb.rb +3 -4
  61. metadata +65 -23
  62. data/lib/ldclient-rb/event_summarizer.rb +0 -55
  63. data/lib/ldclient-rb/file_data_source.rb +0 -23
  64. data/lib/ldclient-rb/impl/event_factory.rb +0 -126
  65. data/lib/ldclient-rb/newrelic.rb +0 -17
  66. data/lib/ldclient-rb/redis_store.rb +0 -88
  67. data/lib/ldclient-rb/user_filter.rb +0 -52
@@ -0,0 +1,444 @@
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
+ # @deprecated The old user format will be removed in 8.0.0. Please use the new context specific format.
321
+ #
322
+ # @param data [Hash]
323
+ # @return [LDContext]
324
+ #
325
+ def self.create(data)
326
+ return create_invalid_context(ERR_NOT_HASH) unless data.is_a?(Hash)
327
+
328
+ kind = data[:kind]
329
+ if kind == KIND_MULTI
330
+ contexts = []
331
+ data.each do |key, value|
332
+ next if key == :kind
333
+ contexts << create_single_context(value, key.to_s)
334
+ end
335
+
336
+ return create_multi(contexts)
337
+ end
338
+
339
+ create_single_context(data, kind)
340
+ end
341
+
342
+ #
343
+ # Create a multi-kind context from the array of LDContexts provided.
344
+ #
345
+ # A multi-kind context is comprised of two or more single kind contexts.
346
+ # You cannot include a multi-kind context instead another multi-kind
347
+ # context.
348
+ #
349
+ # Additionally, the kind of each single-kind context must be unique. For
350
+ # instance, you cannot create a multi-kind context that includes two user
351
+ # kind contexts.
352
+ #
353
+ # If you attempt to create a multi-kind context from one single-kind
354
+ # context, this method will return the single-kind context instead of a new
355
+ # multi-kind context wrapping that one single-kind.
356
+ #
357
+ # @param contexts [Array<LDContext>]
358
+ # @return [LDContext]
359
+ #
360
+ def self.create_multi(contexts)
361
+ return create_invalid_context(ERR_KIND_MULTI_NON_CONTEXT_ARRAY) unless contexts.is_a?(Array)
362
+ return create_invalid_context(ERR_KIND_MULTI_WITH_NO_KINDS) if contexts.empty?
363
+
364
+ kinds = Set.new
365
+ contexts.each do |context|
366
+ if !context.is_a?(LDContext)
367
+ return create_invalid_context(ERR_KIND_MULTI_NON_CONTEXT_ARRAY)
368
+ elsif !context.valid?
369
+ return create_invalid_context(ERR_KIND_MULTI_NON_CONTEXT_ARRAY)
370
+ elsif context.multi_kind?
371
+ return create_invalid_context(ERR_KIND_MULTI_CANNOT_CONTAIN_MULTI)
372
+ elsif kinds.include? context.kind
373
+ return create_invalid_context(ERR_KIND_MULTI_DUPLICATES)
374
+ end
375
+
376
+ kinds.add(context.kind)
377
+ end
378
+
379
+ return contexts[0] if contexts.length == 1
380
+
381
+ full_key = contexts.sort_by(&:kind)
382
+ .map { |c| LaunchDarkly::Impl::Context::canonicalize_key_for_kind(c.kind, c.key) }
383
+ .join(":")
384
+
385
+ new(nil, full_key, "multi", nil, false, nil, nil, nil, contexts)
386
+ end
387
+
388
+ #
389
+ # @param error [String]
390
+ # @return [LDContext]
391
+ #
392
+ private_class_method def self.create_invalid_context(error)
393
+ new(nil, nil, nil, nil, false, nil, nil, error)
394
+ end
395
+
396
+ #
397
+ # @param data [Hash]
398
+ # @param kind [String]
399
+ # @return [LaunchDarkly::LDContext]
400
+ #
401
+ private_class_method def self.create_single_context(data, kind)
402
+ unless data.is_a?(Hash)
403
+ return create_invalid_context(ERR_NOT_HASH)
404
+ end
405
+
406
+ kind_error = LaunchDarkly::Impl::Context.validate_kind(kind)
407
+ return create_invalid_context(kind_error) unless kind_error.nil?
408
+
409
+ key = data[:key]
410
+ key_error = LaunchDarkly::Impl::Context.validate_key(key)
411
+ return create_invalid_context(key_error) unless key_error.nil?
412
+
413
+ name = data[:name]
414
+ name_error = LaunchDarkly::Impl::Context.validate_name(name)
415
+ return create_invalid_context(name_error) unless name_error.nil?
416
+
417
+ anonymous = data.fetch(:anonymous, false)
418
+ anonymous_error = LaunchDarkly::Impl::Context.validate_anonymous(anonymous, false)
419
+ return create_invalid_context(anonymous_error) unless anonymous_error.nil?
420
+
421
+ meta = data.fetch(:_meta, {})
422
+ private_attributes = meta[:privateAttributes]
423
+ if private_attributes && !private_attributes.is_a?(Array)
424
+ return create_invalid_context(ERR_PRIVATE_NON_ARRAY)
425
+ end
426
+
427
+ # We only need to create an attribute hash if there are keys set outside
428
+ # of the ones we store in dedicated instance variables.
429
+ attributes = nil
430
+ data.each do |k, v|
431
+ case k
432
+ when :kind, :key, :name, :anonymous, :_meta
433
+ next
434
+ else
435
+ attributes ||= {}
436
+ attributes[k] = v.clone
437
+ end
438
+ end
439
+
440
+ full_key = kind == LDContext::KIND_DEFAULT ? key.to_s : LaunchDarkly::Impl::Context::canonicalize_key_for_kind(kind, key.to_s)
441
+ new(key.to_s, full_key, kind, name, anonymous, attributes, private_attributes)
442
+ end
443
+ end
444
+ end
@@ -1,4 +1,3 @@
1
-
2
1
  module LaunchDarkly
3
2
  # An object returned by {LDClient#variation_detail}, combining the result of a flag evaluation with
4
3
  # an explanation of how it was calculated.
@@ -12,7 +11,8 @@ module LaunchDarkly
12
11
  # @raise [ArgumentError] if `variation_index` or `reason` is not of the correct type
13
12
  def initialize(value, variation_index, reason)
14
13
  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)
14
+ raise ArgumentError.new("reason must be an EvaluationReason") unless reason.is_a? EvaluationReason
15
+
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,12 @@ 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 there was an inconsistency between the expected type of the flag, and the
104
+ # actual type of the variation evaluated.
105
+ ERROR_WRONG_TYPE = :WRONG_TYPE
106
+
107
+ # Value for {#error_kind} indicating that the caller passed `nil` for the context parameter, or the
108
+ # context was invalid.
105
109
  ERROR_USER_NOT_SPECIFIED = :USER_NOT_SPECIFIED
106
110
 
107
111
  # Value for {#error_kind} indicating that an unexpected exception stopped flag evaluation. An error
@@ -141,7 +145,7 @@ module LaunchDarkly
141
145
  # querying at least one Big Segment. Otherwise it returns `nil`. Possible values are defined by
142
146
  # {BigSegmentsStatus}.
143
147
  #
144
- # Big Segments are a specific kind of user segments. For more information, read the LaunchDarkly
148
+ # Big Segments are a specific kind of context segments. For more information, read the LaunchDarkly
145
149
  # documentation: https://docs.launchdarkly.com/home/users/big-segments
146
150
  # @return [Symbol]
147
151
  attr_reader :big_segments_status
@@ -176,9 +180,9 @@ module LaunchDarkly
176
180
  # @return [EvaluationReason]
177
181
  # @raise [ArgumentError] if `rule_index` is not a number or `rule_id` is not a string
178
182
  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)
183
+ raise ArgumentError.new("rule_index must be a number") unless rule_index.is_a? Numeric
180
184
  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
-
185
+
182
186
  if in_experiment
183
187
  er = new(:RULE_MATCH, rule_index, rule_id, nil, nil, true)
184
188
  else
@@ -193,7 +197,7 @@ module LaunchDarkly
193
197
  # @return [EvaluationReason]
194
198
  # @raise [ArgumentError] if `prerequisite_key` is nil or not a string
195
199
  def self.prerequisite_failed(prerequisite_key)
196
- raise ArgumentError.new("prerequisite_key must be a string") if !(prerequisite_key.is_a? String)
200
+ raise ArgumentError.new("prerequisite_key must be a string") unless prerequisite_key.is_a? String
197
201
  new(:PREREQUISITE_FAILED, nil, nil, prerequisite_key, nil)
198
202
  end
199
203
 
@@ -203,7 +207,7 @@ module LaunchDarkly
203
207
  # @return [EvaluationReason]
204
208
  # @raise [ArgumentError] if `error_kind` is not a symbol
205
209
  def self.error(error_kind)
206
- raise ArgumentError.new("error_kind must be a symbol") if !(error_kind.is_a? Symbol)
210
+ raise ArgumentError.new("error_kind must be a symbol") unless error_kind.is_a? Symbol
207
211
  e = @@error_instances[error_kind]
208
212
  e.nil? ? make_error(error_kind) : e
209
213
  end
@@ -279,7 +283,7 @@ module LaunchDarkly
279
283
  else
280
284
  { kind: @kind }
281
285
  end
282
- if !@big_segments_status.nil?
286
+ unless @big_segments_status.nil?
283
287
  ret[:bigSegmentsStatus] = @big_segments_status
284
288
  end
285
289
  ret
@@ -288,7 +292,7 @@ module LaunchDarkly
288
292
  # Same as {#as_json}, but converts the JSON structure into a string.
289
293
  # @return [String]
290
294
  def to_json(*a)
291
- as_json.to_json(a)
295
+ as_json.to_json(*a)
292
296
  end
293
297
 
294
298
  # Allows this object to be treated as a hash corresponding to its JSON representation. For
@@ -327,9 +331,9 @@ module LaunchDarkly
327
331
  @kind = kind.to_sym
328
332
  @rule_index = rule_index
329
333
  @rule_id = rule_id
330
- @rule_id.freeze if !rule_id.nil?
334
+ @rule_id.freeze unless rule_id.nil?
331
335
  @prerequisite_key = prerequisite_key
332
- @prerequisite_key.freeze if !prerequisite_key.nil?
336
+ @prerequisite_key.freeze unless prerequisite_key.nil?
333
337
  @error_kind = error_kind
334
338
  @in_experiment = in_experiment
335
339
  @big_segments_status = big_segments_status
@@ -348,7 +352,7 @@ module LaunchDarkly
348
352
  ERROR_FLAG_NOT_FOUND => make_error(ERROR_FLAG_NOT_FOUND),
349
353
  ERROR_MALFORMED_FLAG => make_error(ERROR_MALFORMED_FLAG),
350
354
  ERROR_USER_NOT_SPECIFIED => make_error(ERROR_USER_NOT_SPECIFIED),
351
- ERROR_EXCEPTION => make_error(ERROR_EXCEPTION)
355
+ ERROR_EXCEPTION => make_error(ERROR_EXCEPTION),
352
356
  }
353
357
  end
354
358