Skip to content

Commit

Permalink
Add JSON/YAML::Any#dig/dig?
Browse files Browse the repository at this point in the history
  • Loading branch information
Sija committed Sep 14, 2018
1 parent 553c352 commit 0143933
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 0 deletions.
40 changes: 40 additions & 0 deletions spec/std/json/any_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,46 @@ describe JSON::Any do
end
end

describe "#dig?" do
it "gets the value at given path given splat" do
obj = JSON.parse(%({"foo": [1, {"bar": [2, 3]}]}))

obj.dig?("foo", 0).should eq(1)
obj.dig?("foo", 1, "bar", 1).should eq(3)
end

it "returns nil if not found" do
obj = JSON.parse(%({"foo": [1, {"bar": [2, 3]}]}))

obj.dig?("foo", 10).should be_nil
obj.dig?("bar", "baz").should be_nil
obj.dig?("").should be_nil
end
end

describe "dig" do
it "gets the value at given path given splat" do
obj = JSON.parse(%({"foo": [1, {"bar": [2, 3]}]}))

obj.dig("foo", 0).should eq(1)
obj.dig("foo", 1, "bar", 1).should eq(3)
end

it "raises if not found" do
obj = JSON.parse(%({"foo": [1, {"bar": [2, 3]}]}))

expect_raises Exception, %(Expected Hash for #[](key : String), not Array(JSON::Any)) do
obj.dig("foo", 1, "bar", "baz")
end
expect_raises KeyError, %(Missing hash key: "z") do
obj.dig("z")
end
expect_raises KeyError, %(Missing hash key: "") do
obj.dig("")
end
end
end

it "traverses big structure" do
obj = JSON.parse(%({"foo": [1, {"bar": [2, 3]}]}))
obj["foo"][1]["bar"][1].as_i.should eq(3)
Expand Down
40 changes: 40 additions & 0 deletions spec/std/yaml/any_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,46 @@ describe YAML::Any do
end
end

describe "#dig?" do
it "gets the value at given path given splat" do
obj = YAML.parse("--- \nfoo: \n bar: \n baz: \n - qux\n - fox")

obj.dig?("foo", "bar", "baz").should eq(%w(qux fox))
obj.dig?("foo", "bar", "baz", 1).should eq("fox")
end

it "returns nil if not found" do
obj = YAML.parse("--- \nfoo: \n bar: \n baz: \n - qux\n - fox")

obj.dig?("foo", 10).should be_nil
obj.dig?("bar", "baz").should be_nil
obj.dig?("").should be_nil
end
end

describe "dig" do
it "gets the value at given path given splat" do
obj = YAML.parse("--- \nfoo: \n bar: \n baz: \n - qux\n - fox")

obj.dig("foo", "bar", "baz").should eq(%w(qux fox))
obj.dig("foo", "bar", "baz", 1).should eq("fox")
end

it "raises if not found" do
obj = YAML.parse("--- \nfoo: \n bar: \n baz: \n - qux\n - fox")

expect_raises KeyError, %(Missing hash key: 1) do
obj.dig("foo", 1, "bar", "baz")
end
expect_raises KeyError, %(Missing hash key: "bar") do
obj.dig("bar", "baz")
end
expect_raises KeyError, %(Missing hash key: "") do
obj.dig("")
end
end
end

it "traverses big structure" do
obj = YAML.parse("--- \nfoo: \n bar: \n baz: \n - qux\n - fox")
obj["foo"]["bar"]["baz"][1].as_s.should eq("fox")
Expand Down
26 changes: 26 additions & 0 deletions src/json/any.cr
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,32 @@ struct JSON::Any
end
end

# Traverses the depth of a structure and returns the value.
# Returns `nil` if not found.
def dig?(key : String | Int, *subkeys)
if (value = self[key]?) && value.responds_to?(:dig?)
value.dig?(*subkeys)
end
end

# :nodoc:
def dig?(key : String | Int)
self[key]?
end

# Traverses the depth of a structure and returns the value, otherwise raises.
def dig(key : String | Int, *subkeys)
if (value = self[key]) && value.responds_to?(:dig)
return value.dig(*subkeys)
end
raise "JSON::Any value not diggable for key: #{key.inspect}"
end

# :nodoc:
def dig(key : String | Int)
self[key]
end

# Checks that the underlying value is `Nil`, and returns `nil`.
# Raises otherwise.
def as_nil : Nil
Expand Down
26 changes: 26 additions & 0 deletions src/yaml/any.cr
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,32 @@ struct YAML::Any
end
end

# Traverses the depth of a structure and returns the value.
# Returns `nil` if not found.
def dig?(index_or_key, *subkeys)
if (value = self[index_or_key]?) && value.responds_to?(:dig?)
value.dig?(*subkeys)
end
end

# :nodoc:
def dig?(index_or_key)
self[index_or_key]?
end

# Traverses the depth of a structure and returns the value, otherwise raises.
def dig(index_or_key, *subkeys)
if (value = self[index_or_key]) && value.responds_to?(:dig)
return value.dig(*subkeys)
end
raise "YAML::Any value not diggable for key: #{index_or_key.inspect}"
end

# :nodoc:
def dig(index_or_key)
self[index_or_key]
end

# Checks that the underlying value is `Nil`, and returns `nil`.
# Raises otherwise.
def as_nil : Nil
Expand Down

0 comments on commit 0143933

Please sign in to comment.