Skip to content

Instantly share code, notes, and snippets.

@dbreunig
Last active May 19, 2021 04:56
Show Gist options
  • Save dbreunig/b9fdb0b5bf092373b0dbcf95b94c4703 to your computer and use it in GitHub Desktop.
Save dbreunig/b9fdb0b5bf092373b0dbcf95b94c4703 to your computer and use it in GitHub Desktop.
Extracting an array of similar hash objects from a JSON file into a csv, following some very basic assumptions.
#!/usr/bin/env ruby
# frozen_string_literal: true
require "json"
require "csv"
require "optionparser"
#
# Option Handling
#
@options = {}
options = ARGV.options do |opts|
opts.banner = "Usage: jsoncsv -i /path/to/input.json -o /path/to/output.csv"
opts.accept(JSON) do |json|
JSON.parse(File.read(json))
rescue JSON::ParserError => e
raise OptionParser::InvalidArgument, e.message
end
opts.on '-i', '--input [JSONFILE]', JSON, 'Input JSON filepath'
opts.on '-o', '--output [CSVFILE]', String, 'Output CSV filepath'
end.freeze
options.permute! into: @options
raise ArgumentError, "provide an input json file: \n#{options.banner}" unless @options[:input]
#
# Processing & Checking
#
def csvable_array?(candidate_array)
return false unless candidate_array.is_a?(Array)
return candidate_array.map { |a| a.keys rescue nil }.tally.values.max > 2
end
# Output to CSV
def output_csv(json_array, dest = @options[:output])
# Get all potential keys
keys = json_array.flat_map(&:keys).uniq
# Write the csv
out = dest ? File.open(dest, "w+") : $stdout.dup
CSV(out) do |csv|
csv << keys
json_array.each do |json_hash|
csv << keys.map { |k| json_hash[k] }
end
end
out.close
exit
end
# Check root
output_csv(@options[:input]) if csvable_array?(@options[:input])
# Check first children
# FEATURE: Make this step through all children to handle more json files.
@options[:input].each_value do |v|
next unless v.is_a?(Array)
output_csv(v) if csvable_array?(v)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment