Skip to content

Commit 1ba6bde

Browse files
authored
feat: Add hash access and equality support to LDContext (#241)
1 parent 3eee921 commit 1ba6bde

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

lib/ldclient-rb/context.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,18 @@ def individual_context(kind)
281281
nil
282282
end
283283

284+
#
285+
# An LDContext can be compared to other LDContexts or to a hash object. If
286+
# a hash is provided, it is first converted to an LDContext using the
287+
# `LDContext.create` method.
288+
#
289+
# @param other [LDContext, Hash]
290+
# @return [Boolean]
291+
#
284292
def ==(other)
293+
other = LDContext.create(other) if other.is_a? Hash
294+
return false unless other.is_a? LDContext
295+
285296
return false unless self.kind == other.kind
286297
return false unless self.valid? == other.valid?
287298
return false unless self.error == other.error
@@ -308,6 +319,21 @@ def ==(other)
308319
end
309320
alias eql? ==
310321

322+
#
323+
# For a single-kind context, the provided key will return the attribute value specified. This is the same as calling
324+
# `LDCotnext.get_value`.
325+
#
326+
# For multi-kind contexts, the key will be interpreted as a context kind. If the multi-kind context has an
327+
# individual context of that kind, it will be returned. Otherwise, this method will return nil. This behaves the
328+
# same as calling `LDContext.individual_context`.
329+
#
330+
# @param key [Symbol, String]
331+
#
332+
def [](key)
333+
return nil unless key.is_a? Symbol or key.is_a? String
334+
multi_kind? ? individual_context(key.to_s) : get_value(key)
335+
end
336+
311337
#
312338
# Retrieve the value of any top level, addressable attribute.
313339
#

spec/context_spec.rb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,44 @@ module LaunchDarkly
211211
end
212212
end
213213

214+
describe "hash-like behavior" do
215+
it "multi-kind contexts return nested contexts" do
216+
user_context = subject.create({ key: "user-key", kind: "user" })
217+
org_context = subject.create({ key: "org-key", kind: "org" })
218+
multi_context = subject.create_multi([user_context, org_context])
219+
220+
expect(multi_context.valid?).to be true
221+
expect(multi_context["user"]).to eq(user_context)
222+
expect(multi_context["org"]).to eq(org_context)
223+
expect(multi_context["no-such-type"]).to be_nil
224+
end
225+
226+
describe "single-kind contexts" do
227+
it "can retrieve the correct simple attribute value" do
228+
context = subject.create({ key: "my-key", kind: "org", name: "x", :"my-attr" => "y", :"/starts-with-slash" => "z" })
229+
230+
expect(context["kind"]).to eq("org")
231+
expect(context["key"]).to eq("my-key")
232+
expect(context["name"]).to eq("x")
233+
expect(context["my-attr"]).to eq("y")
234+
expect(context["/starts-with-slash"]).to eq("z")
235+
expect(context["a-value-that-is-not-set"]).to be_nil
236+
end
237+
238+
it "cannot query subpath/elements" do
239+
object_value = { a: 1 }
240+
array_value = [1]
241+
242+
context = subject.create({ key: "my-key", kind: "org", :"obj-attr" => object_value, :"array-attr" => array_value })
243+
expect(context["obj-attr"]).to eq(object_value)
244+
expect(context[:"array-attr"]).to eq(array_value)
245+
246+
expect(context[:"/obj-attr/a"]).to be_nil
247+
expect(context[:"/array-attr/0"]).to be_nil
248+
end
249+
end
250+
end
251+
214252
describe "value retrieval" do
215253
describe "supports simple attribute retrieval" do
216254
it "can retrieve the correct simple attribute value" do
@@ -298,6 +336,38 @@ module LaunchDarkly
298336
end
299337

300338
describe "equality comparisons" do
339+
it "wrong types are not equal" do
340+
context = subject.create({ key: 'context-key', kind: 'user' })
341+
expect(context).to_not eq(true)
342+
expect(context).to_not eq(3)
343+
end
344+
345+
it "single-kind context can compare with hash" do
346+
hash = { key: 'context-key', kind: 'user', name: 'Example name', groups: ['test', 'it', 'here'], address: {street: '123 Easy St', city: 'Every Town'},
347+
_meta: { privateAttributes: ['name', 'out of order attribute'] }
348+
}
349+
context = subject.create(hash)
350+
expect(context).to eq(hash)
351+
end
352+
353+
it "multi-kind context can compare with hash" do
354+
hash = {
355+
kind: "multi",
356+
org: { key: 'org-key', kind: 'org' },
357+
user: { key: 'user-key', kind: 'user' },
358+
device: { key: 'device-key', kind: 'device' },
359+
}
360+
org_context = subject.create(hash[:org])
361+
user_context = subject.create(hash[:user])
362+
device_context = subject.create(hash[:device])
363+
context = subject.create(hash)
364+
365+
expect(context).to eq(hash)
366+
expect(context["org"]).to eq(hash[:org])
367+
expect(context["user"]).to eq(hash[:user])
368+
expect(context["device"]).to eq(hash[:device])
369+
end
370+
301371
it "single kind contexts are equal" do
302372
original_context = subject.create(
303373
{ key: 'context-key', kind: 'user', name: 'Example name', groups: ['test', 'it', 'here'], address: {street: '123 Easy St', city: 'Every Town'},

0 commit comments

Comments
 (0)