lib/honey_format/cli/cli.rb
# frozen_string_literal: true
require 'optparse'
module HoneyFormat
# Main CLI
# @attr_reader [Hash] options from command line arguments
class CLI
attr_reader :options
# Instantiate the CLI
# @return [CLI] the CLI
def initialize(argv: ARGV, io: STDOUT)
@io = io
@parser = nil
@options = parse_options(argv: argv.dup)
end
def usage
@parser.to_s
end
private
# Puts to configured IO
# @param [#to_s] object to print
# @return [nil] nil
def puts(arg)
@io.puts(arg)
end
# Parse command line arguments and return options
# @param [Array<String>] argv the command lines arguments
# @return [Hash] the command line options
def parse_options(argv:)
input_path = nil
columns = nil
output_path = nil
delimiter = ','
header_only = false
rows_only = false
skip_lines = nil
type_map = {}
OptionParser.new do |parser|
@parser = parser
parser.banner = 'Usage: honey_format [options] <file.csv>'
parser.default_argv = argv
parser.on('--csv=input.csv', String, 'CSV file') do |value|
input_path = value
end
parser.on('--columns=id,name', Array, 'Select columns') do |value|
columns = value&.map(&:to_sym)
end
parser.on('--output=output.csv', String, 'CSV output (STDOUT otherwise)') do |value|
output_path = value
end
parser.on('--delimiter=,', String, 'CSV delimiter (default: ,)') do |value|
delimiter = value
end
parser.on('--skip-lines=,', String, 'Skip lines that match this pattern') do |value|
skip_lines = value
end
parser.on('--type-map=[key1=val1,key2=val2]', Array, 'Type map') do |value|
type_map = option_to_h(value || [])
end
parser.on('--[no-]header-only', 'Print only the header') do |value|
header_only = value
end
parser.on('--[no-]rows-only', 'Print only the rows') do |value|
rows_only = value
end
parser.on('-h', '--help', 'How to use') do
puts parser
exit
end
parser.on_tail('--version', 'Show version') do
puts "HoneyFormat version #{HoneyFormat::VERSION}"
exit
end
end.parse!
if header_only && rows_only
raise(ArgumentError, "you can't provide both --header-only and --rows-only")
end
if input_path && argv.last
raise(ArgumentError, "you can't provide both --csv and <path>")
end
input_path ||= argv.last
{
input_path: input_path,
columns: columns,
output_path: output_path,
delimiter: delimiter,
header_only: header_only,
rows_only: rows_only,
skip_lines: skip_lines,
type_map: type_map,
}
end
def option_to_h(option)
option.map { |v| v.split('=').map(&:to_sym) }.to_h
end
end
end