Class: LaunchDarkly::LDContext
- Inherits:
-
Object
- Object
- LaunchDarkly::LDContext
- Defined in:
- lib/ldclient-rb/context.rb
Overview
LDContext is a collection of attributes that can be referenced in flag evaluations and analytics events.
To create an LDContext of a single kind, such as a user, you may use LDContext.create or LDContext.with_key.
To create an LDContext with multiple kinds, use LDContext.create_multi.
Each factory method will always return an LDContext. However, that LDContext may be invalid. You can check the validity of the resulting context, and the associated errors by calling #valid? and #error
Constant Summary collapse
- KIND_DEFAULT =
"user"
- KIND_MULTI =
"multi"
- ERR_PRIVATE_NON_ARRAY =
'context private attributes must be an array'
Instance Attribute Summary collapse
-
#error ⇒ String?
readonly
Returns the error associated with this LDContext if invalid.
-
#fully_qualified_key ⇒ String?
readonly
Returns the fully qualified key for this context.
-
#key ⇒ String?
readonly
Returns the key for this context.
-
#kind ⇒ String?
readonly
Returns the kind for this context.
Class Method Summary collapse
-
.create(data) ⇒ LDContext
Create a single kind context from the provided hash.
-
.create_multi(contexts) ⇒ LDContext
Create a multi-kind context from the array of LDContexts provided.
-
.with_key(key, kind = KIND_DEFAULT) ⇒ Object
Convenience method to create a simple single kind context providing only a key and kind type.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
(also: #eql?)
An LDContext can be compared to other LDContexts or to a hash object.
-
#[](key) ⇒ Object
For a single-kind context, the provided key will return the attribute value specified.
-
#get_custom_attribute_names ⇒ Array<Symbol>
Return an array of top level attribute keys (excluding built-in attributes).
-
#get_value(attribute) ⇒ any
get_value looks up the value of any attribute of the Context by name.
-
#get_value_for_reference(reference) ⇒ any
get_value_for_reference looks up the value of any attribute of the Context, or a value contained within an attribute, based on a Reference instance.
-
#individual_context(kind) ⇒ LDContext?
Returns the single-kind LDContext corresponding to one of the kinds in this context.
-
#individual_context_count ⇒ Integer
Returns the number of context kinds in this context.
-
#initialize(key, fully_qualified_key, kind, name = nil, anonymous = nil, attributes = nil, private_attributes = nil, error = nil, contexts = nil) ⇒ LDContext
constructor
A new instance of LDContext.
-
#keys ⇒ Hash<Symbol, String>
Returns a hash mapping each context’s kind to its key.
-
#kinds ⇒ Array<String>
Returns an array of context kinds.
-
#multi_kind? ⇒ Boolean
Is this LDContext a multi-kind context?.
-
#private_attributes ⇒ Array<Reference>
Returns the private attributes associated with this LDContext.
-
#to_h ⇒ Hash
Convert the LDContext to a hash.
-
#to_json(*args) ⇒ String
Convert the LDContext to a JSON string.
-
#valid? ⇒ Boolean
Determine if this LDContext is considered valid.
-
#without_anonymous_contexts ⇒ Object
For a multi-kind context:.
Constructor Details
#initialize(key, fully_qualified_key, kind, name = nil, anonymous = nil, attributes = nil, private_attributes = nil, error = nil, contexts = nil) ⇒ LDContext
Returns a new instance of LDContext.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/ldclient-rb/context.rb', line 62 def initialize(key, fully_qualified_key, kind, name = nil, anonymous = nil, attributes = nil, private_attributes = nil, error = nil, contexts = nil) @key = key @fully_qualified_key = fully_qualified_key @kind = kind @name = name @anonymous = anonymous || false @attributes = attributes @private_attributes = Set.new (private_attributes || []).each do |attribute| reference = Reference.create(attribute) @private_attributes.add(reference) if reference.error.nil? end @error = error @contexts = contexts @is_multi = !contexts.nil? end |
Instance Attribute Details
#error ⇒ String? (readonly)
Returns the error associated with this LDContext if invalid
48 49 50 |
# File 'lib/ldclient-rb/context.rb', line 48 def error @error end |
#fully_qualified_key ⇒ String? (readonly)
Returns the fully qualified key for this context
42 43 44 |
# File 'lib/ldclient-rb/context.rb', line 42 def fully_qualified_key @fully_qualified_key end |
#key ⇒ String? (readonly)
Returns the key for this context
39 40 41 |
# File 'lib/ldclient-rb/context.rb', line 39 def key @key end |
#kind ⇒ String? (readonly)
Returns the kind for this context
45 46 47 |
# File 'lib/ldclient-rb/context.rb', line 45 def kind @kind end |
Class Method Details
.create(data) ⇒ LDContext
Create a single kind context from the provided hash.
The provided hash must match the format as outlined in the SDK documentation.
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 |
# File 'lib/ldclient-rb/context.rb', line 446 def self.create(data) return create_invalid_context(ERR_NOT_HASH) unless data.is_a?(Hash) kind = data[:kind] if kind == KIND_MULTI contexts = [] data.each do |key, value| next if key == :kind contexts << create_single_context(value, key.to_s) end return create_multi(contexts) end create_single_context(data, kind) end |
.create_multi(contexts) ⇒ LDContext
Create a multi-kind context from the array of LDContexts provided.
A multi-kind context is comprised of two or more single kind contexts. You cannot include a multi-kind context instead another multi-kind context.
Additionally, the kind of each single-kind context must be unique. For instance, you cannot create a multi-kind context that includes two user kind contexts.
If you attempt to create a multi-kind context from one single-kind context, this method will return the single-kind context instead of a new multi-kind context wrapping that one single-kind.
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
# File 'lib/ldclient-rb/context.rb', line 481 def self.create_multi(contexts) return create_invalid_context(ERR_KIND_MULTI_NON_CONTEXT_ARRAY) unless contexts.is_a?(Array) return create_invalid_context(ERR_KIND_MULTI_WITH_NO_KINDS) if contexts.empty? kinds = Set.new contexts.each do |context| if !context.is_a?(LDContext) return create_invalid_context(ERR_KIND_MULTI_NON_CONTEXT_ARRAY) elsif !context.valid? return create_invalid_context(ERR_KIND_MULTI_NON_CONTEXT_ARRAY) elsif context.multi_kind? return create_invalid_context(ERR_KIND_MULTI_CANNOT_CONTAIN_MULTI) elsif kinds.include? context.kind return create_invalid_context(ERR_KIND_MULTI_DUPLICATES) end kinds.add(context.kind) end return contexts[0] if contexts.length == 1 full_key = contexts.sort_by(&:kind) .map { |c| LaunchDarkly::Impl::Context::canonicalize_key_for_kind(c.kind, c.key) } .join(":") new(nil, full_key, "multi", nil, false, nil, nil, nil, contexts) end |
.with_key(key, kind = KIND_DEFAULT) ⇒ Object
Convenience method to create a simple single kind context providing only a key and kind type.
432 433 434 |
# File 'lib/ldclient-rb/context.rb', line 432 def self.with_key(key, kind = KIND_DEFAULT) create({key: key, kind: kind}) end |
Instance Method Details
#==(other) ⇒ Boolean Also known as: eql?
An LDContext can be compared to other LDContexts or to a hash object. If a hash is provided, it is first converted to an LDContext using the ‘LDContext.create` method.
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/ldclient-rb/context.rb', line 312 def ==(other) other = LDContext.create(other) if other.is_a? Hash return false unless other.is_a? LDContext return false unless self.kind == other.kind return false unless self.valid? == other.valid? return false unless self.error == other.error return false unless self.individual_context_count == other.individual_context_count if self.multi_kind? self.kinds.each do |kind| return false unless self.individual_context(kind) == other.individual_context(kind) end return true end return false unless self.key == other.key return false unless self.name == other.name return false unless self.anonymous == other.anonymous return false unless self.attributes == other.attributes # TODO(sc-227265): Calling .to_set is unnecessary once private_attributes are sets. return false unless self.private_attributes.to_set == other.private_attributes.to_set true end |
#[](key) ⇒ Object
For a single-kind context, the provided key will return the attribute value specified. This is the same as calling ‘LDCotnext.get_value`.
For multi-kind contexts, the key will be interpreted as a context kind. If the multi-kind context has an individual context of that kind, it will be returned. Otherwise, this method will return nil. This behaves the same as calling ‘LDContext.individual_context`.
352 353 354 355 |
# File 'lib/ldclient-rb/context.rb', line 352 def [](key) return nil unless key.is_a? Symbol or key.is_a? String multi_kind? ? individual_context(key.to_s) : get_value(key) end |
#get_custom_attribute_names ⇒ Array<Symbol>
Return an array of top level attribute keys (excluding built-in attributes)
153 154 155 156 157 |
# File 'lib/ldclient-rb/context.rb', line 153 def get_custom_attribute_names return [] if @attributes.nil? @attributes.keys end |
#get_value(attribute) ⇒ any
get_value looks up the value of any attribute of the Context by name. This includes only attributes that are addressable in evaluations– not metadata such as private attributes.
For a single-kind context, the attribute name can be any custom attribute. It can also be one of the built-in ones like “kind”, “key”, or “name”.
For a multi-kind context, the only supported attribute name is “kind”. Use #individual_context to inspect a Context for a particular kind and then get its attributes.
This method does not support complex expressions for getting individual values out of JSON objects or arrays, such as “/address/street”. Use #get_value_for_reference for that purpose.
If the value is found, the return value is the attribute value; otherwise, it is nil.
181 182 183 184 |
# File 'lib/ldclient-rb/context.rb', line 181 def get_value(attribute) reference = Reference.create_literal(attribute) get_value_for_reference(reference) end |
#get_value_for_reference(reference) ⇒ any
get_value_for_reference looks up the value of any attribute of the Context, or a value contained within an attribute, based on a Reference instance. This includes only attributes that are addressable in evaluations– not metadata such as private attributes.
This implements the same behavior that the SDK uses to resolve attribute references during a flag evaluation. In a single-kind context, the Reference can represent a simple attribute name– either a built-in one like “name” or “key”, or a custom attribute – or, it can be a slash-delimited path using a JSON-Pointer-like syntax. See Reference for more details.
For a multi-kind context, the only supported attribute name is “kind”. Use #individual_context to inspect a Context for a particular kind and then get its attributes.
If the value is found, the return value is the attribute value; otherwise, it is nil.
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/ldclient-rb/context.rb', line 209 def get_value_for_reference(reference) return nil unless valid? return nil unless reference.is_a?(Reference) return nil unless reference.error.nil? first_component = reference.component(0) return nil if first_component.nil? if multi_kind? if reference.depth == 1 && first_component == :kind return kind end # Multi-kind contexts have no other addressable attributes return nil end value = get_top_level_addressable_attribute_single_kind(first_component) return nil if value.nil? (1...reference.depth).each do |i| name = reference.component(i) return nil unless value.is_a?(Hash) return nil unless value.has_key?(name) value = value[name] end value end |
#individual_context(kind) ⇒ LDContext?
Returns the single-kind LDContext corresponding to one of the kinds in this context.
The ‘kind` parameter can be either a number representing a zero-based index, or a string representing a context kind.
If this method is called on a single-kind LDContext, then the only allowable value for ‘kind` is either zero or the same value as #kind, and the return value on success is the same LDContext.
If the method is called on a multi-context, and ‘kind` is a number, it must be a non-negative index that is less than the number of kinds (that is, less than the return value of #individual_context_count, and the return value on success is one of the individual LDContexts within. Or, if `kind` is a string, it must match the context kind of one of the individual contexts.
If there is no context corresponding to ‘kind`, the method returns nil.
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/ldclient-rb/context.rb', line 280 def individual_context(kind) return nil unless valid? if kind.is_a?(Integer) unless multi_kind? return kind == 0 ? self : nil end return kind >= 0 && kind < @contexts.count ? @contexts[kind] : nil end return nil unless kind.is_a?(String) unless multi_kind? return self.kind == kind ? self : nil end @contexts.each do |context| return context if context.kind == kind end nil end |
#individual_context_count ⇒ Integer
Returns the number of context kinds in this context.
For a valid individual context, this returns 1. For a multi-context, it returns the number of context kinds. For an invalid context, it returns zero.
250 251 252 253 254 |
# File 'lib/ldclient-rb/context.rb', line 250 def individual_context_count return 0 unless valid? return 1 if @contexts.nil? @contexts.count end |
#keys ⇒ Hash<Symbol, String>
Returns a hash mapping each context’s kind to its key.
129 130 131 132 133 134 |
# File 'lib/ldclient-rb/context.rb', line 129 def keys return {} unless valid? return Hash[kind, key] unless multi_kind? @contexts.map { |c| [c.kind, c.key] }.to_h end |
#kinds ⇒ Array<String>
Returns an array of context kinds.
141 142 143 144 145 146 |
# File 'lib/ldclient-rb/context.rb', line 141 def kinds return [] unless valid? return [kind] unless multi_kind? @contexts.map { |c| c.kind } end |
#multi_kind? ⇒ Boolean
Returns Is this LDContext a multi-kind context?.
93 94 95 |
# File 'lib/ldclient-rb/context.rb', line 93 def multi_kind? @is_multi end |
#private_attributes ⇒ Array<Reference>
Returns the private attributes associated with this LDContext
85 86 87 88 |
# File 'lib/ldclient-rb/context.rb', line 85 def private_attributes # TODO(sc-227265): Return a set instead of an array. @private_attributes.to_a end |
#to_h ⇒ Hash
Convert the LDContext to a hash. If the LDContext is invalid, the hash will contain an error key with the error message.
373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/ldclient-rb/context.rb', line 373 def to_h return {error: error} unless valid? return hash_single_kind unless multi_kind? hash = {kind: 'multi'} @contexts.each do |context| single_kind_hash = context.to_h kind = single_kind_hash.delete(:kind) hash[kind] = single_kind_hash end hash end |
#to_json(*args) ⇒ String
Convert the LDContext to a JSON string.
363 364 365 |
# File 'lib/ldclient-rb/context.rb', line 363 def to_json(*args) JSON.generate(to_h, *args) end |
#valid? ⇒ Boolean
Returns Determine if this LDContext is considered valid.
100 101 102 |
# File 'lib/ldclient-rb/context.rb', line 100 def valid? @error.nil? end |
#without_anonymous_contexts ⇒ Object
For a multi-kind context:
A multi-kind context is made up of two or more single-kind contexts. This method will first discard any single-kind contexts which are anonymous. It will then create a new multi-kind context from the remaining single-kind contexts. This may result in an invalid context (e.g. all single-kind contexts are anonymous).
For a single-kind context:
If the context is not anonymous, this method will return the current context as is and unmodified.
If the context is anonymous, this method will return an invalid context.
117 118 119 120 121 122 |
# File 'lib/ldclient-rb/context.rb', line 117 def without_anonymous_contexts contexts = multi_kind? ? @contexts : [self] contexts = contexts.reject { |c| c.anonymous } LDContext.create_multi(contexts) end |