Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add hash access and equality support to LDContext #241

Merged
merged 1 commit into from
Jan 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lib/ldclient-rb/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,18 @@ def individual_context(kind)
nil
end

#
# 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.
#
# @param other [LDContext, Hash]
# @return [Boolean]
#
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
Expand All @@ -308,6 +319,21 @@ def ==(other)
end
alias eql? ==

#
# 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`.
#
# @param key [Symbol, String]
#
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

#
# Retrieve the value of any top level, addressable attribute.
#
Expand Down
70 changes: 70 additions & 0 deletions spec/context_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,44 @@ module LaunchDarkly
end
end

describe "hash-like behavior" do
it "multi-kind contexts return nested contexts" do
user_context = subject.create({ key: "user-key", kind: "user" })
org_context = subject.create({ key: "org-key", kind: "org" })
multi_context = subject.create_multi([user_context, org_context])

expect(multi_context.valid?).to be true
expect(multi_context["user"]).to eq(user_context)
expect(multi_context["org"]).to eq(org_context)
expect(multi_context["no-such-type"]).to be_nil
end

describe "single-kind contexts" do
it "can retrieve the correct simple attribute value" do
context = subject.create({ key: "my-key", kind: "org", name: "x", :"my-attr" => "y", :"/starts-with-slash" => "z" })

expect(context["kind"]).to eq("org")
expect(context["key"]).to eq("my-key")
expect(context["name"]).to eq("x")
expect(context["my-attr"]).to eq("y")
expect(context["/starts-with-slash"]).to eq("z")
expect(context["a-value-that-is-not-set"]).to be_nil
end

it "cannot query subpath/elements" do
object_value = { a: 1 }
array_value = [1]

context = subject.create({ key: "my-key", kind: "org", :"obj-attr" => object_value, :"array-attr" => array_value })
expect(context["obj-attr"]).to eq(object_value)
expect(context[:"array-attr"]).to eq(array_value)

expect(context[:"/obj-attr/a"]).to be_nil
expect(context[:"/array-attr/0"]).to be_nil
end
end
end

describe "value retrieval" do
describe "supports simple attribute retrieval" do
it "can retrieve the correct simple attribute value" do
Expand Down Expand Up @@ -298,6 +336,38 @@ module LaunchDarkly
end

describe "equality comparisons" do
it "wrong types are not equal" do
context = subject.create({ key: 'context-key', kind: 'user' })
expect(context).to_not eq(true)
expect(context).to_not eq(3)
end

it "single-kind context can compare with hash" do
hash = { key: 'context-key', kind: 'user', name: 'Example name', groups: ['test', 'it', 'here'], address: {street: '123 Easy St', city: 'Every Town'},
_meta: { privateAttributes: ['name', 'out of order attribute'] }
}
context = subject.create(hash)
expect(context).to eq(hash)
end

it "multi-kind context can compare with hash" do
hash = {
kind: "multi",
org: { key: 'org-key', kind: 'org' },
user: { key: 'user-key', kind: 'user' },
device: { key: 'device-key', kind: 'device' },
}
org_context = subject.create(hash[:org])
user_context = subject.create(hash[:user])
device_context = subject.create(hash[:device])
context = subject.create(hash)

expect(context).to eq(hash)
expect(context["org"]).to eq(hash[:org])
expect(context["user"]).to eq(hash[:user])
expect(context["device"]).to eq(hash[:device])
end

it "single kind contexts are equal" do
original_context = subject.create(
{ key: 'context-key', kind: 'user', name: 'Example name', groups: ['test', 'it', 'here'], address: {street: '123 Easy St', city: 'Every Town'},
Expand Down