Skip to content

Instantly share code, notes, and snippets.

@buren
Last active May 2, 2023 12:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save buren/0cce624ca0466ae4a6d134f905ae75fe to your computer and use it in GitHub Desktop.
Save buren/0cce624ca0466ae4a6d134f905ae75fe to your computer and use it in GitHub Desktop.
Flatten JSON to a two column CSV with defined separator and convert it back from CSV to JSON again. Useful for JSON I18n files amongst other things.
#!/usr/bin/env ruby
USAGE = <<~DOC
USAGE:
ruby json_csv_converter.rb <in_file> <separator(optional)>
EXAMPLES:
Convert JSON to CSV
$ ruby json_csv_converter.rb file.json
Convert CSV to JSON with / as level separator
$ ruby json_csv_converter.rb file.csv /
DOC
module Enumerable
def flatten_with_path(separator, parent_prefix = nil)
res = {}
self.each_with_index do |elem, i|
if elem.is_a?(Array)
k, v = elem
else
k, v = i, elem
end
key = parent_prefix ? "#{parent_prefix}#{separator}#{k}" : k # assign key name for result hash
if v.is_a? Enumerable
res.merge!(v.flatten_with_path(separator, key)) # recursive call to flatten child elements
else
res[key] = v
end
end
res
end
end
# set nested hash values
def dig_set(hash, keys, value)
key = keys.first
if keys.length == 1
hash[key] = value
else
hash[key] = {} unless hash[key]
dig_set(hash[key], keys.slice(1..-1), value)
end
end
def die(*args)
puts USAGE
puts
raise *args
end
def json_to_csv(path, separator)
json = JSON.parse(File.read(path))
csv_string = CSV.generate do |csv|
json.flatten_with_path(separator).each { |k, v| csv << [k, v] }
end
puts csv_string
end
def csv_to_json(path, separator)
csv = CSV.read(path)
hash = {}
csv.each do |key, value|
next if key.nil?
dig_set(hash, key.split(separator), value)
end
JSON.pretty_generate(hash)
end
# main
require 'json'
require 'csv'
path = ARGV[0] or die 'missing file argument'
separator = ARGV[1] || '.'
filetype = path.split('.').last
if filetype == 'csv'
puts csv_to_json(path, separator)
elsif filetype == 'json'
puts json_to_csv(path, separator)
else
die "unknown format #{filetype}, must be .csv or .json!"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment