Skip to content

Instantly share code, notes, and snippets.

@snipsnipsnip
Last active September 4, 2019 11:20
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 snipsnipsnip/b5059d9a4abd06e135bf49e3b17c43a2 to your computer and use it in GitHub Desktop.
Save snipsnipsnip/b5059d9a4abd06e135bf49e3b17c43a2 to your computer and use it in GitHub Desktop.
perm.rb: explodes ARGV as a TSV (permutate 'foo bar baz' 'quu qux' yields 6 lines)
# frozen_string_literal: true
# permutate.rb: MIT license. @snipsnipsnip
require 'csv'
require 'optparse'
require 'shellwords'
def main(argv=ARGV)
filter = nil
rest = nil
need_header = false
unique_marker = nil
utate = false
OptionParser.new do |o|
o.banner += " ['a b c' 'd e %1$s'...]"
o.separator "Options:"
o.on('-c', '--column-header', "Treat first value ('a' and 'd' in the usage) as a title row", TrueClass) {|a| need_header = a }
o.on('-u [OMITTED-MARKER]', '--only-unique-value', "Replaces duplicate output with OMITTED-MARKER", String) {|a| unique_marker = a || "" }
o.on('--utate', "Permutates columns", TrueClass) {|a| utate = true }
o.on('-e CODE', '--eval', "Applies filter. CODE must return a callable (String[] -> String[] | nil)", String) {|a| filter = TOPLEVEL_BINDING.eval(a) }
o.on('-h', '--help') { abort o.to_s }
rest = o.parse(argv)
abort o.to_s if rest.empty?
abort "CODE must return a callable (String[] -> String[] | nil)" unless !filter || filter.respond_to?(:call)
true
end or return
CSV(col_sep: "\t") do |csv|
orig_cols = rest.map {|x| Shellwords.shellsplit x.strip }
permutated_cols = utate ? orig_cols.permutation : [orig_cols]
no = 1
prev_line = nil
permutated_cols.each do |cols|
if need_header
csv << ['No', *cols.map(&:first)]
cols = cols.map {|c| c.drop 1 }
end
:product.to_proc.(*cols) do |line|
line.map! {|c| c.include?(?%) ? c % line : c }
line = filter.call(line) || next if filter
curr_line = [no, *line]
if prev_line && unique_marker
line.each_index do |col|
curr_line[col + 1] = unique_marker if line[col] == prev_line[col]
end
end
csv << curr_line
no += 1
prev_line = line
end
end
end
end
main if $0 == __FILE__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment