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

duck-type values responding to #to_hash or #to_ary #139

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
16 changes: 7 additions & 9 deletions lib/jsonpath/dig.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,10 @@ def dig_as_hash(context, keys)

# Dig the value of k on context.
def dig_one(context, k)
case context
when Hash
context[@options[:use_symbols] ? k.to_sym : k]
when Array
context[k.to_i]
if context.respond_to?(:to_hash)
context.to_hash[@options[:use_symbols] ? k.to_sym : k]
elsif context.respond_to?(:to_ary)
context.to_ary[k.to_i]
else
if context.respond_to?(:dig)
context.dig(k)
Expand All @@ -37,12 +36,11 @@ def dig_one(context, k)
# Yields the block if context has a diggable
# value for k
def yield_if_diggable(context, k, &blk)
case context
when Array
if context.respond_to?(:to_ary)
nil
when Hash
elsif context.respond_to?(:to_hash)
k = @options[:use_symbols] ? k.to_sym : k
return yield if context.key?(k) || @options[:default_path_leaf_to_null]
return yield if context.to_hash.key?(k) || @options[:default_path_leaf_to_null]
else
if context.respond_to?(:dig)
digged = dig_one(context, k)
Expand Down
26 changes: 13 additions & 13 deletions lib/jsonpath/enumerable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,21 @@ def each(context = @object, key = nil, pos = 0, &blk)
end

if pos > 0 && @path[pos - 1] == '..' || (@path[pos - 1] == '*' && @path[pos] != '..')
case node
when Hash then node.each { |k, _| each(node, k, pos, &blk) }
when Array then node.each_with_index { |_, i| each(node, i, pos, &blk) }
if node.respond_to?(:to_hash)
node.to_hash.each { |k, _| each(node, k, pos, &blk) }
elsif node.respond_to?(:to_ary)
node.to_ary.each_with_index { |_, i| each(node, i, pos, &blk) }
end
end
end

private

def filter_context(context, keys)
case context
when Hash
if context.respond_to?(:to_hash)
dig_as_hash(context, keys)
when Array
context.each_with_object([]) do |c, memo|
elsif context.respond_to?(:to_ary)
context.to_ary.each_with_object([]) do |c, memo|
memo << dig_as_hash(c, keys)
end
end
Expand All @@ -62,7 +62,7 @@ def handle_wildecard(node, expr, _context, _key, pos, &blk)
when '?'
handle_question_mark(sub_path, node, pos, &blk)
else
next if node.is_a?(Array) && node.empty?
next if node.respond_to?(:to_ary) && node.empty?
next if node.nil? # when default_path_leaf_to_null is true

array_args = sub_path.split(':')
Expand Down Expand Up @@ -103,15 +103,15 @@ def ensure_exclusive_end_index(value)
end

def handle_question_mark(sub_path, node, pos, &blk)
case node
when Array
node.size.times do |index|
@_current_node = node[index]
if node.respond_to?(:to_ary)
node_ary = node.to_ary
node_ary.size.times do |index|
@_current_node = node_ary[index]
if process_function_or_literal(sub_path[1, sub_path.size - 1])
each(@_current_node, nil, pos + 1, &blk)
end
end
when Hash
elsif node.respond_to?(:to_hash)
if process_function_or_literal(sub_path[1, sub_path.size - 1])
each(@_current_node, nil, pos + 1, &blk)
end
Expand Down
4 changes: 2 additions & 2 deletions lib/jsonpath/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def parse_exp(exp)
next if i.empty?

index = Integer(i[0])
raise ArgumentError, 'Node does not appear to be an array.' unless @_current_node.is_a?(Array)
raise ArgumentError, 'Node does not appear to be an array.' unless @_current_node.respond_to?(:to_ary)
raise ArgumentError, "Index out of bounds for nested array. Index: #{index}" if @_current_node.size < index

@_current_node = @_current_node[index]
Expand Down Expand Up @@ -93,7 +93,7 @@ def parse_exp(exp)

el = if elements.empty?
@_current_node
elsif @_current_node.is_a?(Hash)
elsif @_current_node.respond_to?(:to_hash)
dig(@_current_node, *elements)
else
elements.inject(@_current_node, &:__send__)
Expand Down
2 changes: 1 addition & 1 deletion lib/jsonpath/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def _delete(obj, path)

def _remove(obj)
obj.each do |o|
if o.is_a?(Hash) || o.is_a?(Array)
if o.respond_to?(:to_hash) || o.respond_to?(:to_ary)
_remove(o)
o.delete({})
end
Expand Down