lib/view_model/garbage_collection.rb
# frozen_string_literal: true class ViewModel::GarbageCollection class << self def garbage_collect_references!(serialization) return unless serialization.has_key?('references') roots = serialization.except('references') references = serialization['references'] worklist = Set.new(collect_references(roots)) visited = Set.new while (live = worklist.first) worklist.delete(live) visited << live collect_references(references[live]) do |ref| worklist << ref unless visited.include?(ref) end end references.keep_if { |ref, _val| visited.include?(ref) } end private ## yield each reference encountered in tree def collect_references(tree, &block) return enum_for(__method__, tree) unless block_given? case tree when Hash if tree.size == 1 && (ref = tree[ViewModel::REFERENCE_ATTRIBUTE]) block.(ref) else tree.each_value { |t| collect_references(t, &block) } end when Array tree.each { |t| collect_references(t, &block) } end end end end