class ViewModel::Migrator
def migrate!(serialization)
def migrate!(serialization) references = (serialization['references'] ||= {}) # First visit everything except references; there's no issue with adding # new references during this. migrate_tree!(serialization.except('references'), references: references) # While visiting references itself, we need to take care that we can # concurrently modify them (e.g. by adding new referenced views). # Moreover, such added references must themselves be visited, as they'll # be synthesized at the current version and so may need to be migrated # down to the client's requested version. visited_refs = [] loop do unvisited_refs = references.keys - visited_refs break if unvisited_refs.empty? unvisited_refs.each do |ref| migrate_tree!(references[ref], references: references) end visited_refs.concat(unvisited_refs) end GarbageCollection.garbage_collect_references!(serialization) if references.empty? serialization.delete('references') end end