Sha256: 8bf381ea5b3c339b409d77aedda9cb3a6c2412c536ebf1bd2d2504ca2a61fe7d

Contents?: true

Size: 1.9 KB

Versions: 4

Compression:

Stored size: 1.9 KB

Contents

require 'tins/thread_local'

module Tins
  module HashBFS
    extend Tins::ThreadLocal

    thread_local :seen

    # The bfs method performs a breadth-first search on the object's structure,
    # visiting all elements and yielding their indices and values to the block.
    #
    # @param visit_internal [ true, false ] whether to visit internal hashes or arrays
    # @yield [ index, value ] yields each element's index and value to the block
    #
    # @raise [ ArgumentError ] if no &block argument was provided
    #
    # @example bfs { |index, value| … } # performs a breadth-first search on the object's structure
    #
    # @return [ self ] returns the receiver
    def bfs(visit_internal: false, &block)
      block or raise ArgumentError, 'require &block argument'
      self.seen = {}
      queue     = []
      queue.push([ nil, self ])
      while (index, object = queue.shift)
        case
        when seen[object.__id__]
          next
        when Hash === object
          seen[object.__id__] = true
          object.each do |k, v|
            queue.push([ k, convert_to_hash_or_ary(v) ])
          end
          visit_internal or next
        when Array === object
          seen[object.__id__] = true
          object.each_with_index do |v, i|
            queue.push([ i, convert_to_hash_or_ary(v) ])
          end
          visit_internal or next
        end
        block.(index, object)
      end
      self
    ensure
      self.seen = nil
    end

    # Converts the given object into a hash or array if possible
    #
    # @param object [Object] The object to convert
    #
    # @return [Hash, Array, Object] The converted object or itself if not convertible
    def 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
  end
end

require 'tins/alias'

Version data entries

4 entries across 4 versions & 1 rubygems

Version Path
tins-1.38.0 lib/tins/hash_bfs.rb
tins-1.37.1 lib/tins/hash_bfs.rb
tins-1.37.0 lib/tins/hash_bfs.rb
tins-1.36.1 lib/tins/hash_bfs.rb