Class: LaunchDarkly::EvaluationReason

Inherits:
Object
  • Object
show all
Defined in:
lib/ldclient-rb/evaluation_detail.rb

Overview

Describes the reason that a flag evaluation produced a particular value. This is returned by methods such as LDClient#variation_detail as the ‘reason` property of an EvaluationDetail.

The ‘kind` property is always defined, but other properties will have non-nil values only for certain values of `kind`. All properties are immutable.

There is a standard JSON representation of evaluation reasons when they appear in analytics events. Use ‘as_json` or `to_json` to convert to this representation.

Use factory methods such as EvaluationReason.off to obtain instances of this class.

Constant Summary collapse

OFF =

Value for #kind indicating that the flag was off and therefore returned its configured off value.

:OFF
FALLTHROUGH =

Value for #kind indicating that the flag was on but the context did not match any targets or rules.

:FALLTHROUGH
TARGET_MATCH =

Value for #kind indicating that the context key was specifically targeted for this flag.

:TARGET_MATCH
RULE_MATCH =

Value for #kind indicating that the context matched one of the flag’s rules.

:RULE_MATCH
PREREQUISITE_FAILED =

Value for #kind indicating that the flag was considered off because it had at least one prerequisite flag that either was off or did not return the desired variation.

:PREREQUISITE_FAILED
ERROR =

Value for #kind indicating that the flag could not be evaluated, e.g. because it does not exist or due to an unexpected error. In this case the result value will be the application default value that the caller passed to the client. Check #error_kind for more details on the problem.

:ERROR
ERROR_CLIENT_NOT_READY =

Value for #error_kind indicating that the caller tried to evaluate a flag before the client had successfully initialized.

:CLIENT_NOT_READY
ERROR_FLAG_NOT_FOUND =

Value for #error_kind indicating that the caller provided a flag key that did not match any known flag.

:FLAG_NOT_FOUND
ERROR_MALFORMED_FLAG =

Value for #error_kind indicating that there was an internal inconsistency in the flag data, e.g. a rule specified a nonexistent variation. An error message will always be logged in this case.

:MALFORMED_FLAG
ERROR_WRONG_TYPE =

Value for #error_kind indicating that there was an inconsistency between the expected type of the flag, and the actual type of the variation evaluated.

:WRONG_TYPE
ERROR_USER_NOT_SPECIFIED =

Value for #error_kind indicating that the caller passed ‘nil` for the context parameter, or the context was invalid.

:USER_NOT_SPECIFIED
ERROR_EXCEPTION =

Value for #error_kind indicating that an unexpected exception stopped flag evaluation. An error message will always be logged in this case.

:EXCEPTION
@@fallthrough_with_experiment =
new(:FALLTHROUGH, nil, nil, nil, nil, true)
@@fallthrough =
new(:FALLTHROUGH, nil, nil, nil, nil)
@@off =
new(:OFF, nil, nil, nil, nil)
@@target_match =
new(:TARGET_MATCH, nil, nil, nil, nil)
@@error_instances =
{
  ERROR_CLIENT_NOT_READY => make_error(ERROR_CLIENT_NOT_READY),
  ERROR_FLAG_NOT_FOUND => make_error(ERROR_FLAG_NOT_FOUND),
  ERROR_MALFORMED_FLAG => make_error(ERROR_MALFORMED_FLAG),
  ERROR_USER_NOT_SPECIFIED => make_error(ERROR_USER_NOT_SPECIFIED),
  ERROR_EXCEPTION => make_error(ERROR_EXCEPTION),
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(kind, rule_index, rule_id, prerequisite_key, error_kind, in_experiment = nil, big_segments_status = nil) ⇒ EvaluationReason

Constructor that sets all properties. Applications should not normally use this constructor, but should use class methods like #off to avoid creating unnecessary instances.



329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/ldclient-rb/evaluation_detail.rb', line 329

def initialize(kind, rule_index, rule_id, prerequisite_key, error_kind, in_experiment=nil,
    big_segments_status = nil)
  @kind = kind.to_sym
  @rule_index = rule_index
  @rule_id = rule_id
  @rule_id.freeze unless rule_id.nil?
  @prerequisite_key = prerequisite_key
  @prerequisite_key.freeze unless prerequisite_key.nil?
  @error_kind = error_kind
  @in_experiment = in_experiment
  @big_segments_status = big_segments_status
end

Instance Attribute Details

#big_segments_statusSymbol (readonly)

Describes the validity of Big Segment information, if and only if the flag evaluation required querying at least one Big Segment. Otherwise it returns ‘nil`. Possible values are defined by BigSegmentsStatus.

Big Segments are a specific kind of context segments. For more information, read the LaunchDarkly documentation: docs.launchdarkly.com/home/users/big-segments

Returns:

  • (Symbol)


151
152
153
# File 'lib/ldclient-rb/evaluation_detail.rb', line 151

def big_segments_status
  @big_segments_status
end

#error_kindSymbol (readonly)

A value indicating the general category of error. This should be one of the class constants such as #ERROR_FLAG_NOT_FOUND. If #kind is not #ERROR, it will be ‘nil`.

Returns:

  • (Symbol)


142
143
144
# File 'lib/ldclient-rb/evaluation_detail.rb', line 142

def error_kind
  @error_kind
end

#in_experimentBoolean|nil (readonly)

A boolean or nil value representing if the rule or fallthrough has an experiment rollout.

Returns:

  • (Boolean|nil)


132
133
134
# File 'lib/ldclient-rb/evaluation_detail.rb', line 132

def in_experiment
  @in_experiment
end

#kindSymbol (readonly)

Indicates the general category of the reason. Will always be one of the class constants such as #OFF.

Returns:

  • (Symbol)


118
119
120
# File 'lib/ldclient-rb/evaluation_detail.rb', line 118

def kind
  @kind
end

#prerequisite_keyString (readonly)

The key of the prerequisite flag that did not return the desired variation. If #kind is not #PREREQUISITE_FAILED, this will be ‘nil`.

Returns:

  • (String)


137
138
139
# File 'lib/ldclient-rb/evaluation_detail.rb', line 137

def prerequisite_key
  @prerequisite_key
end

#rule_idString (readonly)

A unique string identifier for the matched rule, which will not change if other rules are added or deleted. If #kind is not #RULE_MATCH, this will be ‘nil`.

Returns:

  • (String)


128
129
130
# File 'lib/ldclient-rb/evaluation_detail.rb', line 128

def rule_id
  @rule_id
end

#rule_indexInteger|nil (readonly)

The index of the rule that was matched (0 for the first rule in the feature flag). If #kind is not #RULE_MATCH, this will be ‘nil`.

Returns:

  • (Integer|nil)


123
124
125
# File 'lib/ldclient-rb/evaluation_detail.rb', line 123

def rule_index
  @rule_index
end

Class Method Details

.error(error_kind) ⇒ EvaluationReason

Returns an instance whose #kind is #ERROR.

Parameters:

  • error_kind (Symbol)

    value indicating the general category of error

Returns:

Raises:

  • (ArgumentError)

    if ‘error_kind` is not a symbol



209
210
211
212
213
# File 'lib/ldclient-rb/evaluation_detail.rb', line 209

def self.error(error_kind)
  raise ArgumentError.new("error_kind must be a symbol") unless error_kind.is_a? Symbol
  e = @@error_instances[error_kind]
  e.nil? ? make_error(error_kind) : e
end

.fallthrough(in_experiment = false) ⇒ EvaluationReason

Returns an instance whose #kind is #FALLTHROUGH.

Returns:



161
162
163
164
165
166
167
# File 'lib/ldclient-rb/evaluation_detail.rb', line 161

def self.fallthrough(in_experiment=false)
  if in_experiment
    @@fallthrough_with_experiment
  else
    @@fallthrough
  end
end

.offEvaluationReason

Returns an instance whose #kind is #OFF.

Returns:



155
156
157
# File 'lib/ldclient-rb/evaluation_detail.rb', line 155

def self.off
  @@off
end

.prerequisite_failed(prerequisite_key) ⇒ EvaluationReason

Returns an instance whose #kind is #PREREQUISITE_FAILED.

Parameters:

  • prerequisite_key (String)

    key of the prerequisite flag that did not return the desired variation

Returns:

Raises:

  • (ArgumentError)

    if ‘prerequisite_key` is nil or not a string



199
200
201
202
# File 'lib/ldclient-rb/evaluation_detail.rb', line 199

def self.prerequisite_failed(prerequisite_key)
  raise ArgumentError.new("prerequisite_key must be a string") unless prerequisite_key.is_a? String
  new(:PREREQUISITE_FAILED, nil, nil, prerequisite_key, nil)
end

.rule_match(rule_index, rule_id, in_experiment = false) ⇒ EvaluationReason

Returns an instance whose #kind is #RULE_MATCH.

Parameters:

  • rule_index (Number)

    the index of the rule that was matched (0 for the first rule in the feature flag)

  • rule_id (String)

    unique string identifier for the matched rule

Returns:

Raises:

  • (ArgumentError)

    if ‘rule_index` is not a number or `rule_id` is not a string



182
183
184
185
186
187
188
189
190
191
192
# File 'lib/ldclient-rb/evaluation_detail.rb', line 182

def self.rule_match(rule_index, rule_id, in_experiment=false)
  raise ArgumentError.new("rule_index must be a number") unless rule_index.is_a? Numeric
  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

  if in_experiment
    er = new(:RULE_MATCH, rule_index, rule_id, nil, nil, true)
  else
    er = new(:RULE_MATCH, rule_index, rule_id, nil, nil)
  end
  er
end

.target_matchEvaluationReason

Returns an instance whose #kind is #TARGET_MATCH.

Returns:



171
172
173
# File 'lib/ldclient-rb/evaluation_detail.rb', line 171

def self.target_match
  @@target_match
end

Instance Method Details

#==(other) ⇒ Object



215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/ldclient-rb/evaluation_detail.rb', line 215

def ==(other)
  if other.is_a? EvaluationReason
    @kind == other.kind && @rule_index == other.rule_index && @rule_id == other.rule_id &&
      @prerequisite_key == other.prerequisite_key && @error_kind == other.error_kind &&
      @big_segments_status == other.big_segments_status
  elsif other.is_a? Hash
    @kind.to_s == other[:kind] && @rule_index == other[:ruleIndex] && @rule_id == other[:ruleId] &&
      @prerequisite_key == other[:prerequisiteKey] &&
      (other[:errorKind] == @error_kind.nil? ? nil : @error_kind.to_s) &&
      (other[:bigSegmentsStatus] == @big_segments_status.nil? ? nil : @big_segments_status.to_s)
  end
end

#[](key) ⇒ Object

Allows this object to be treated as a hash corresponding to its JSON representation. For instance, if ‘reason.kind` is #RULE_MATCH, then `reason` will be `“RULE_MATCH”` and `reason` will be equal to `reason.rule_index`.



301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/ldclient-rb/evaluation_detail.rb', line 301

def [](key)
  case key
  when :kind
    @kind.to_s
  when :ruleIndex
    @rule_index
  when :ruleId
    @rule_id
  when :prerequisiteKey
    @prerequisite_key
  when :errorKind
    @error_kind.nil? ? nil : @error_kind.to_s
  when :bigSegmentsStatus
    @big_segments_status.nil? ? nil : @big_segments_status.to_s
  else
    nil
  end
end

#as_jsonHash

Returns a hash that can be used as a JSON representation of the reason, in the format used in LaunchDarkly analytics events.

Returns:

  • (Hash)


260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/ldclient-rb/evaluation_detail.rb', line 260

def as_json(*) # parameter is unused, but may be passed if we're using the json gem
  # Note that this implementation is somewhat inefficient; it allocates a new hash every time.
  # However, in normal usage the SDK only serializes reasons if 1. full event tracking is
  # enabled for a flag and the application called variation_detail, or 2. experimentation is
  # enabled for an evaluation. We can't reuse these hashes because an application could call
  # as_json and then modify the result.
  ret = case @kind
  when :RULE_MATCH
    if @in_experiment
      { kind: @kind, ruleIndex: @rule_index, ruleId: @rule_id, inExperiment: @in_experiment }
    else
      { kind: @kind, ruleIndex: @rule_index, ruleId: @rule_id }
    end
  when :PREREQUISITE_FAILED
    { kind: @kind, prerequisiteKey: @prerequisite_key }
  when :ERROR
    { kind: @kind, errorKind: @error_kind }
  when :FALLTHROUGH
    if @in_experiment
      { kind: @kind, inExperiment: @in_experiment }
    else
      { kind: @kind }
    end
  else
    { kind: @kind }
  end
  unless @big_segments_status.nil?
    ret[:bigSegmentsStatus] = @big_segments_status
  end
  ret
end

#inspectString

Returns a concise string representation of the reason. Examples: ‘“FALLTHROUGH”`, `“ERROR(FLAG_NOT_FOUND)”`. The exact syntax is not guaranteed to remain the same; this is meant for debugging.

Returns:

  • (String)


238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/ldclient-rb/evaluation_detail.rb', line 238

def inspect
  case @kind
  when :RULE_MATCH
    if @in_experiment
      "RULE_MATCH(#{@rule_index},#{@rule_id},#{@in_experiment})"
    else
      "RULE_MATCH(#{@rule_index},#{@rule_id})"
    end
  when :PREREQUISITE_FAILED
    "PREREQUISITE_FAILED(#{@prerequisite_key})"
  when :ERROR
    "ERROR(#{@error_kind})"
  when :FALLTHROUGH
    @in_experiment ? "FALLTHROUGH(#{@in_experiment})" : @kind.to_s
  else
    @kind.to_s
  end
end

#to_json(*a) ⇒ String

Same as #as_json, but converts the JSON structure into a string.

Returns:

  • (String)


294
295
296
# File 'lib/ldclient-rb/evaluation_detail.rb', line 294

def to_json(*a)
  as_json.to_json(*a)
end

#to_sString

Equivalent to #inspect.

Returns:

  • (String)


230
231
232
# File 'lib/ldclient-rb/evaluation_detail.rb', line 230

def to_s
  inspect
end

#with_big_segments_status(big_segments_status) ⇒ Object



320
321
322
323
# File 'lib/ldclient-rb/evaluation_detail.rb', line 320

def with_big_segments_status(big_segments_status)
  return self if @big_segments_status == big_segments_status
  EvaluationReason.new(@kind, @rule_index, @rule_id, @prerequisite_key, @error_kind, @in_experiment, big_segments_status)
end