module Hm::Algo
@private
Constants
- NONDUPABLE
JRuby, I am looking at you
Public Instance Methods
deep_copy(value)
click to toggle source
# File lib/hm/algo.rb, line 13 def deep_copy(value) # FIXME: ignores Struct/OpenStruct (which are diggable too) case value when Hash value.map { |key, val| [key, deep_copy(val)] }.to_h when Array value.map(&method(:deep_copy)) when *NONDUPABLE value else value.dup end end
delete(collection, key)
click to toggle source
# File lib/hm/algo.rb, line 6 def delete(collection, key) collection.is_a?(Array) ? collection.delete_at(key) : collection.delete(key) end
nest_hashes(value, *keys)
click to toggle source
# File lib/hm/algo.rb, line 49 def nest_hashes(value, *keys) return value if keys.empty? key = keys.shift val = keys.empty? ? value : nest_hashes(value, *keys) key.is_a?(Integer) ? [].tap { |arr| arr[key] = val } : {key => val} end
robust_enumerator(collection)
click to toggle source
Enumerates through entire collection with “current key/current value” at each point, even if elements are deleted in a process of enumeration
# File lib/hm/algo.rb, line 29 def robust_enumerator(collection) case collection when Hash, Struct collection.each_pair.to_a when Array Enumerator.new do |y| cur = collection.size until cur.zero? pos = collection.size - cur y << [pos, collection[pos]] cur -= 1 end end when ->(c) { c.respond_to?(:each_pair) } collection.each_pair.to_a else fail TypeError, "Can't dig/* in #{collection.class}" end end
visit(what, rest, path = [], not_found: ->(*) {}
click to toggle source
# File lib/hm/algo.rb, line 57 def visit(what, rest, path = [], not_found: ->(*) {}, &found) Dig.diggable?(what) or fail TypeError, "#{what.class} is not diggable" key, *rst = rest if key == WILDCARD visit_wildcard(what, rst, path, found: found, not_found: not_found) else visit_regular(what, key, rst, path, found: found, not_found: not_found) end end
visit_all(what, path = []) { |what, [*path, key], val| ... }
click to toggle source
# File lib/hm/algo.rb, line 68 def visit_all(what, path = [], &block) robust_enumerator(what).each do |key, val| yield(what, [*path, key], val) visit_all(val, [*path, key], &block) if Dig.diggable?(val) end end
visit_regular(what, key, rest, path, found:, not_found:)
click to toggle source
# File lib/hm/algo.rb, line 84 def visit_regular(what, key, rest, path, found:, not_found:) # rubocop:disable Metrics/ParameterLists internal = Dig.dig(what, key) # NB: NotFound is signified by special value, because `nil` can still be legitimate value in hash return not_found.(what, [*path, key], rest) if internal == Dig::NotFound rest.empty? and return found.(what, [*path, key], internal) visit(internal, rest, [*path, key], not_found: not_found, &found) end
visit_wildcard(what, rest, path, found:, not_found:)
click to toggle source
# File lib/hm/algo.rb, line 75 def visit_wildcard(what, rest, path, found:, not_found:) iterator = robust_enumerator(what) if rest.empty? iterator.map { |key, val| found.(what, [*path, key], val) } else iterator.map { |key, el| visit(el, rest, [*path, key], not_found: not_found, &found) } end end