class RbPath::Query
Public Class Methods
new(*query)
click to toggle source
takes a string query or a pre-parsed query list
# File lib/rbpath/query.rb, line 6 def initialize(*query) @query = parse_query_list(query) end
Public Instance Methods
parse_query_list(query)
click to toggle source
# File lib/rbpath/query.rb, line 25 def parse_query_list(query) query.flat_map do |part| case part when String, Symbol parse_string_query(part.to_s) when Regexp {multi: false, neg: false, keys: [], regexp: part} else {multi: false, neg: false, keys: [part]} end end end
parse_string_query(query)
click to toggle source
Parsing rules:
-
query keys are seperated by spaces, keys with spaces must be single quoted
-
brackets group keys into an NOR group
-
parens group keys into a OR group
-
valid keys names consist of [chars|nums|spaces|-|_|.], anything else can be used as a seperator inside the parens/brackets
# File lib/rbpath/query.rb, line 17 def parse_string_query(query) query.scan(/(\([^\)]+\)|\[[^\]]+\]|'[^']+'|[^\s]+)/) .flatten .map { |keys| { multi: /\*\*/ === keys[0..1], neg: /[\[\*]/ === keys[0], keys: keys.scan(/[\w\d\s\-\_\.]+/) }} end
pquery(data)
click to toggle source
# File lib/rbpath/query.rb, line 43 def pquery(data) do_query(deep_stringify_all(data), @query, [[]]).map(&:flatten) end
query(data)
click to toggle source
# File lib/rbpath/query.rb, line 37 def query(data) data = deep_stringify_all(data) do_query(data, @query, [[]]).map(&:flatten) .map { |path| get_value(data, path) } end
values_at(data, paths)
click to toggle source
# File lib/rbpath/query.rb, line 47 def values_at(data, paths) paths.map {|path| get_value(deep_stringify_all(data), path) } end
Private Instance Methods
all_keys(data, path)
click to toggle source
# File lib/rbpath/query.rb, line 78 def all_keys(data, path) value = get_value(data, path) case value when Hash then value.keys when Array then (0...value.size).map(&:to_s) when RbPath value.rbpath_fields else [value] end end
do_query(data, query, valid_paths)
click to toggle source
# File lib/rbpath/query.rb, line 53 def do_query(data, query, valid_paths) matcher, *rest = *query if query.empty? || valid_paths.empty? valid_paths elsif matcher[:multi] do_query(data, rest, valid_paths) + do_query(data, query, match(data, matcher, valid_paths)) else do_query(data, rest, match(data, matcher, valid_paths)) end end
get_value(data, path)
click to toggle source
# File lib/rbpath/query.rb, line 90 def get_value(data, path) return data if path.empty? key, *rest = *path case data when Hash get_value(data[key], rest) when Array get_value(data[Integer(key)], rest) rescue nil when RbPath get_value(data.send(key), rest) if data.respond_to?(key) when key rest.empty? ? data : nil end end
match(data, matcher, valid_paths)
click to toggle source
# File lib/rbpath/query.rb, line 66 def match(data, matcher, valid_paths) neg, keys, rgx = matcher.values_at(:neg, :keys, :regexp) valid_paths.flat_map { |path| children = if rgx all_keys(data, path).grep(rgx) elsif neg (all_keys(data, path) - keys) else keys; end [path].product(children).map(&:flatten) } \ .select { |path| get_value(data, path) } end