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_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.



325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/ldclient-rb/evaluation_detail.rb', line 325

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)


147
148
149
# File 'lib/ldclient-rb/evaluation_detail.rb', line 147

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)


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

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)


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

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)


114
115
116
# File 'lib/ldclient-rb/evaluation_detail.rb', line 114

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)


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

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)


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

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)


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

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



205
206
207
208
209
# File 'lib/ldclient-rb/evaluation_detail.rb', line 205

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:



157
158
159
160
161
162
163
# File 'lib/ldclient-rb/evaluation_detail.rb', line 157

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:



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

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



195
196
197
198
# File 'lib/ldclient-rb/evaluation_detail.rb', line 195

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



178
179
180
181
182
183
184
185
186
187
188
# File 'lib/ldclient-rb/evaluation_detail.rb', line 178

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:



167
168
169
# File 'lib/ldclient-rb/evaluation_detail.rb', line 167

def self.target_match
  @@target_match
end

Instance Method Details

#==(other) ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/ldclient-rb/evaluation_detail.rb', line 211

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`.



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/ldclient-rb/evaluation_detail.rb', line 297

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)


256
257
258
259
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
# File 'lib/ldclient-rb/evaluation_detail.rb', line 256

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)


234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/ldclient-rb/evaluation_detail.rb', line 234

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)


290
291
292
# File 'lib/ldclient-rb/evaluation_detail.rb', line 290

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

#to_sString

Equivalent to #inspect.

Returns:

  • (String)


226
227
228
# File 'lib/ldclient-rb/evaluation_detail.rb', line 226

def to_s
  inspect
end

#with_big_segments_status(big_segments_status) ⇒ Object



316
317
318
319
# File 'lib/ldclient-rb/evaluation_detail.rb', line 316

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