Last active
September 4, 2019 11:20
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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