class Xcodeproj::Project::UUIDGenerator

def fixup_uuid_references

def fixup_uuid_references
  fixup = ->(object, attr) do
    if object.respond_to?(attr) && link = @project.objects_by_uuid[object.send(attr)]
      object.send(:"#{attr}=", link.uuid)
    end
  end
  @project.objects.each do |object|
    UUID_ATTRIBUTES.each do |attr|
      fixup[object, attr]
    end
  end
end

def generate!

def generate!
  all_objects = @project.objects
  generate_paths(@project.root_object)
  switch_uuids(all_objects)
  verify_no_duplicates!(all_objects)
  fixup_uuid_references
  @project.instance_variable_set(:@generated_uuids, @project.instance_variable_get(:@available_uuids))
  @project.instance_variable_set(:@objects_by_uuid, @new_objects_by_uuid)
end

def generate_paths(object, path = '')

def generate_paths(object, path = '')
  existing = @paths_by_object[object] || path
  return existing if @paths_by_object.key?(object)
  @paths_by_object[object] = path.size > existing.size ? path : existing
  object.to_one_attributes.each do |attrb|
    obj = attrb.get_value(object)
    generate_paths(obj, path + '/' << attrb.plist_name) if obj
  end
  object.to_many_attributes.each do |attrb|
    attrb.get_value(object).each do |o|
      generate_paths(o, path + '/' << attrb.plist_name << "/#{path_component_for_object(o)}")
    end
  end
  object.references_by_keys_attributes.each do |attrb|
    attrb.get_value(object).each do |dictionary|
      dictionary.each do |key, value|
        generate_paths(value, path + '/' << attrb.plist_name << "/k:#{key}/#{path_component_for_object(value)}")
      end
    end
  end
end

def initialize(project)

def initialize(project)
  @project = project
  @new_objects_by_uuid = {}
  @paths_by_object = {}
end

def path_component_for_object(object)

def path_component_for_object(object)
  @path_component_for_object ||= Hash.new do |cache, key|
    component = tree_hash_to_path(key.to_tree_hash)
    component << key.hierarchy_path.to_s if key.respond_to?(:hierarchy_path)
    cache[key] = component
  end
  @path_component_for_object[object]
end

def switch_uuids(objects)

def switch_uuids(objects)
  @project.mark_dirty!
  objects.each do |object|
    next unless path = @paths_by_object[object]
    uuid = uuid_for_path(path)
    object.instance_variable_set(:@uuid, uuid)
    @new_objects_by_uuid[uuid] = object
  end
end

def tree_hash_to_path(object, depth = 4)

def tree_hash_to_path(object, depth = 4)
  return '|' if depth.zero?
  case object
  when Hash
    object.sort.each_with_object('') do |(key, value), string|
      string << key << ':' << tree_hash_to_path(value, depth - 1) << ','
    end
  when Array
    object.map do |value|
      tree_hash_to_path(value, depth - 1)
    end.join(',')
  else
    object.to_s
  end
end

def uuid_for_path(path)

def uuid_for_path(path)
  Digest::MD5.hexdigest(path).upcase
end

def verify_no_duplicates!(all_objects)

def verify_no_duplicates!(all_objects)
  duplicates = all_objects - @new_objects_by_uuid.values
  UserInterface.warn "[Xcodeproj] Generated duplicate UUIDs:\n\n" <<
    duplicates.map { |d| "#{d.isa} -- #{@paths_by_object[d]}" }.join("\n") unless duplicates.empty?
end