Module: Tins::HashDFS

Extended by:
ThreadLocal
Defined in:
lib/tins/hash_dfs.rb

Overview

HashDFS for a depth‑first traversal for Ruby hash and array structures.

Provides methods to traverse hash structures in a depth-first manner, visiting all keys and values.

Instance Method Summary collapse

Methods included from ThreadLocal

instance_thread_local, thread_local

Instance Method Details

#dfs(visit_internal: false) {|index, object| ... } ⇒ self

Performs a depth‑first search on the receiver’s structure.

Examples:

Basic usage

{ a: 1, b: [2, 3] }.dfs do |idx, val|
  puts "#{idx.inspect} => #{val.inspect}"
end

Parameters:

  • visit_internal (Boolean) (defaults to: false)

    whether to yield internal hashes/arrays. When false (default) the block is called only for leaf values. When true, the block is called for every node, including the intermediate hashes/arrays that contain other objects.

Yields:

  • (index, object)

    yields the index/key (or array index) and the object being visited.

Yield Parameters:

  • index (Object, Integer, nil)

    the key or array index, or nil for the root object.

  • object (Object)

    the current object (Hash, Array, or leaf).

Returns:

  • (self)

    returns the receiver for chaining.

Raises:

  • (ArgumentError)

    if no block is given.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/tins/hash_dfs.rb', line 32

def dfs(visit_internal: false, &block)
  block or raise ArgumentError, 'require &block argument'
  self.dfs_seen = {}
  stack = []
  stack.push([nil, self])

  while (index, object = stack.pop)
    case
    when dfs_seen[object.__id__]
      next
    when Hash === object
      dfs_seen[object.__id__] = true
      object.each do |k, v|
        stack.push([k, dfs_convert_to_hash_or_ary(v)])
      end
      visit_internal or next
    when Array === object
      dfs_seen[object.__id__] = true
      object.each_with_index do |v, i|
        stack.push([i, dfs_convert_to_hash_or_ary(v)])
      end
      visit_internal or next
    end
    block.(index, object)
  end
  self
ensure
  self.dfs_seen = nil
end

#dfs_convert_to_hash_or_ary(object) ⇒ Hash, ...

Converts the given object into a hash or array if possible.

Examples:

dfs_convert_to_hash_or_ary(Struct.new(:a).new(1)) # => { a: 1 }

Parameters:

  • object (Object)

    the object to convert.

Returns:

  • (Hash, Array, Object)

    the converted object or the original object if no conversion method is available.



70
71
72
73
74
75
76
77
78
79
# File 'lib/tins/hash_dfs.rb', line 70

def dfs_convert_to_hash_or_ary(object)
  case
  when object.respond_to?(:to_hash)
    object.to_hash
  when object.respond_to?(:to_ary)
    object.to_ary
  else
    object
  end
end