Skip to content

Instantly share code, notes, and snippets.

@floriandejonckheere
Created May 16, 2022 07:35
Show Gist options
  • Save floriandejonckheere/698636ed1c526f2700ea41578edb40a9 to your computer and use it in GitHub Desktop.
Save floriandejonckheere/698636ed1c526f2700ea41578edb40a9 to your computer and use it in GitHub Desktop.
Sort YAML files while keeping the comments intact
#!/usr/bin/env ruby
#
# yaml-keysort.rb - Sort YAML files by key while keeping comments intact
#
# Note: script does not parse YAML and copies lines entirely, only keeping track of top-level keys.
# Ensure there is a blank line between each block.
# frozen_string_literal: true
file = ARGV.pop
abort("Usage: #{$0} FILE") unless file
file = File.expand_path(File.join(__dir__, file))
output = File.join(File.dirname(file), "#{File.basename(file, ".yml")}.sorted.yml")
abort("File not found: #{file}") unless File.exist?(file)
lines = File.readlines(file)
configuration = { key: "", comments: [], lines: [] }
configurations = lines.each_with_object([]) do |e, a|
case e
when /^\n$/
# Finalize configuration block
a << configuration
configuration = { key: "", comments: [], lines: [] }
when /^#/
# Save comments preceding key definition
configuration[:comments] << e
when /^ /
# Save lines following key definition
configuration[:lines] << e
else
# Save key definition
configuration[:lines] << e
configuration[:key] = e.chomp.delete_suffix(":")
end
end
lines = configurations
.reject { |c| c.fetch(:key) == "" }
.sort_by { |c| c.fetch(:key) }
.map { |c| c.fetch(:comments).concat(c.fetch(:lines)).join }
.join("\n")
File.write(output, lines)
puts "Written sorted keys to #{output}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment