Top Level Namespace
Defined Under Namespace
Modules: Enumerable Classes: Tb
Class Method Summary collapse
- .decode_a1_addressing_col(str) ⇒ Object
- .exit_if_help(subcommand) ⇒ Object
- .git_each_commit(f) ⇒ Object
- .git_parse_commit(commit_info, files) ⇒ Object
- .git_unescape_filename(filename) ⇒ Object
- .git_with_git_log(dir) ⇒ Object
- .list_summary_of_subcommands ⇒ Object
- .main(argv) ⇒ Object
-
.main_body(argv) ⇒ Object
Copyright © 2011-2012 Tanaka Akira <[email protected]>.
- .main_cat(argv) ⇒ Object
- .main_consecutive(argv) ⇒ Object
- .main_crop(argv) ⇒ Object
- .main_cross(argv) ⇒ Object
- .main_cut(argv) ⇒ Object
- .main_git(argv) ⇒ Object
- .main_grep(argv) ⇒ Object
- .main_group(argv) ⇒ Object
- .main_gsub(argv) ⇒ Object
- .main_help(argv) ⇒ Object
- .main_join(argv) ⇒ Object
- .main_ls(argv) ⇒ Object
- .main_melt(argv) ⇒ Object
- .main_mheader(argv) ⇒ Object
- .main_nest(argv) ⇒ Object
- .main_newfield(argv) ⇒ Object
- .main_rename(argv) ⇒ Object
- .main_shape(argv) ⇒ Object
- .main_sort(argv) ⇒ Object
- .main_svn(argv) ⇒ Object
- .main_to_csv(argv) ⇒ Object
- .main_to_json(argv) ⇒ Object
- .main_to_pnm(argv) ⇒ Object
- .main_to_pp(argv) ⇒ Object
- .main_to_tsv(argv) ⇒ Object
- .main_to_yaml(argv) ⇒ Object
- .main_unmelt(argv) ⇒ Object
- .main_unnest(argv) ⇒ Object
- .op_cat ⇒ Object
- .op_consecutive ⇒ Object
- .op_crop ⇒ Object
- .op_cross ⇒ Object
- .op_cut ⇒ Object
- .op_git ⇒ Object
- .op_grep ⇒ Object
- .op_group ⇒ Object
- .op_gsub ⇒ Object
- .op_help ⇒ Object
- .op_join ⇒ Object
- .op_ls ⇒ Object
- .op_melt ⇒ Object
- .op_mheader ⇒ Object
- .op_nest ⇒ Object
- .op_newfield ⇒ Object
- .op_rename ⇒ Object
- .op_shape ⇒ Object
- .op_sort ⇒ Object
- .op_svn ⇒ Object
- .op_to_csv ⇒ Object
- .op_to_json ⇒ Object
- .op_to_pnm ⇒ Object
- .op_to_pp ⇒ Object
- .op_to_tsv ⇒ Object
- .op_to_yaml ⇒ Object
- .op_unmelt ⇒ Object
- .op_unnest ⇒ Object
- .show_help(subcommand) ⇒ Object
- .svn_with_svn_log(argv) ⇒ Object
- .usage_list_subcommands ⇒ Object
Instance Method Summary collapse
- #err(msg) ⇒ Object
- #output_tbenum(te) ⇒ Object
- #parse_aggregator_spec(spec) ⇒ Object
- #parse_aggregator_spec2(spec) ⇒ Object
- #split_csv_argument(arg) ⇒ Object
- #split_field_list_argument(arg) ⇒ Object
- #tablereader_open(filename, &b) ⇒ Object
- #tbl_generate_tsv(tbl, out) ⇒ Object
- #with_output(filename = Tb::Cmd.opt_output) ⇒ Object
Class Method Details
.decode_a1_addressing_col(str) ⇒ Object
42 43 44 |
# File 'lib/tb/cmd_crop.rb', line 42 def (Tb::Cmd).decode_a1_addressing_col(str) (26**str.length-1)/25+str.tr("A-Z", "0-9A-P").to_i(26) end |
.exit_if_help(subcommand) ⇒ Object
86 87 88 89 90 91 |
# File 'lib/tb/cmd_help.rb', line 86 def (Tb::Cmd).exit_if_help(subcommand) if 0 < Tb::Cmd.opt_help show_help(subcommand) exit end end |
.git_each_commit(f) ⇒ Object
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/tb/cmd_git.rb', line 183 def (Tb::Cmd).git_each_commit(f) while chunk = f.gets("\x01commit-separator\x01\n") chunk.chomp!("\x01commit-separator\x01\n") next if chunk.empty? # beginning of the output if /\nend-commit\n/ !~ chunk warn "unexpected git output (end-commit): #{chunk.inspect}" next end commit_info, files = $`, $' files.sub!(/\A\n/, '') h = git_parse_commit(commit_info, files) yield h end end |
.git_parse_commit(commit_info, files) ⇒ Object
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/tb/cmd_git.rb', line 134 def (Tb::Cmd).git_parse_commit(commit_info, files) commit_info = commit_info.split(/\n(?=[a-z])/) files_raw = {} files_numstat = {} files.split(/\n/).each {|file_line| if /\A:(\d+) (\d+) ([0-9a-f]+) ([0-9a-f]+) (\S+)\t(.+)\z/ =~ file_line mode1, mode2, hash1, hash2, status, filename = $1, $2, $3, $4, $5, $6 filename = git_unescape_filename(filename) files_raw[filename] = [mode1, mode2, hash1, hash2, status] elsif /\A(\d+|-)\t(\d+|-)\t(.+)\z/ =~ file_line add, del, filename = $1, $2, $3 add = add == '-' ? nil : add.to_i del = del == '-' ? nil : del.to_i filename = git_unescape_filename(filename) files_numstat[filename] = [add, del] else warn "unexpected git output (raw/numstat): #{file_line.inspect}" end } Tb.csv_stream_output(files_csv="") {|gen| gen << %w[mode1 mode2 hash1 hash2 add del status filename] files_raw.each {|filename, (mode1, mode2, hash1, hash2, status)| add, del = files_numstat[filename] gen << [mode1, mode2, hash1, hash2, add, del, status, filename] } } h = {} commit_info.each {|s| if /:/ !~ s warn "unexpected git output (header:value): #{s.inspect}" next end k = $` v = $'.gsub(/\n /, "\n") # remove indent generated by %w(0,0,1) case k when /\A(?:author-date|committer-date)/ v = v.sub(/\A(\d+-\d\d-\d\d) (\d\d:\d\d:\d\d) ([-+]\d\d\d\d)\z/, '\1T\2\3') when /\Aparents\z/ v = ['parent', *v.split(/ /)].map {|c| c + "\n" }.join("") when /\Aref-names\z/ v = v.strip.gsub(/\A\(|\)\z/, '') v = ['ref-name', *v.split(/, /)].map {|c| c + "\n" }.join("") end h[k] = v } h['files'] = files_csv h end |
.git_unescape_filename(filename) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/tb/cmd_git.rb', line 107 def (Tb::Cmd).git_unescape_filename(filename) if /\A"/ =~ filename $'.chomp('"').gsub(/\\((\d\d\d)|[abtnvfr"\\])/) { str = $1 if $2 [str.to_i(8)].pack("C") else case str when 'a' then "\a" when 'b' then "\b" when 't' then "\t" when 'n' then "\n" when 'v' then "\v" when 'f' then "\f" when 'r' then "\r" when '"' then '"' when '\\' then "\\" else warn "unexpected escape: #{str.inspect}" end end } else filename end end |
.git_with_git_log(dir) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/tb/cmd_git.rb', line 72 def (Tb::Cmd).git_with_git_log(dir) if Tb::Cmd.opt_git_debug_input File.open(Tb::Cmd.opt_git_debug_input) {|f| yield f } else git = Tb::Cmd.opt_git_command || 'git' # depends Ruby 1.9. command = [ git, 'log', "--pretty=#{Tb::Cmd::GIT_LOG_PRETTY_FORMAT}", '--decorate=full', '--raw', '--numstat', '--abbrev=40', '.', {:chdir=>dir} ] $stderr.puts "git command line: #{command.inspect}" if 1 <= Tb::Cmd.opt_debug if Tb::Cmd.opt_git_debug_output # File.realdirpath is required before Ruby 2.0. command.last[:out] = File.realdirpath(Tb::Cmd.opt_git_debug_output) system(*command) File.open(Tb::Cmd.opt_git_debug_output) {|f| yield f } else IO.popen(command) {|f| yield f } end end end |
.list_summary_of_subcommands ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/tb/cmd_help.rb', line 46 def (Tb::Cmd).list_summary_of_subcommands with_output {|f| f.print "" subcommand_maxlen = Tb::Cmd.subcommands.map {|subcommand| subcommand.length }.max fmt = "%-#{subcommand_maxlen}s : %s" Tb::Cmd.subcommands.each {|subcommand| = self.subcommand_send("op", subcommand). summary = [/^Usage: (.*)\n(.*)/, 2] f.puts(fmt % [subcommand, summary]) } } end |
.main(argv) ⇒ Object
43 44 45 46 47 48 |
# File 'lib/tb/cmdmain.rb', line 43 def (Tb::Cmd).main(argv) main_body(argv) rescue SystemExit $stderr.puts $!. if $!. != 'exit' raise end |
.main_body(argv) ⇒ Object
Copyright © 2011-2012 Tanaka Akira <[email protected]>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
3. The name of the author may not be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/tb/cmdmain.rb', line 29 def (Tb::Cmd).main_body(argv) subcommand = argv.shift if subcommand == '-h' || subcommand == '--help' main_help(argv) elsif Tb::Cmd.subcommands.include?(subcommand) self.subcommand_send("main", subcommand, argv) elsif subcommand == nil usage_list_subcommands true else err "unexpected subcommand: #{subcommand.inspect}" end end |
.main_cat(argv) ⇒ Object
61 62 63 64 65 66 67 |
# File 'lib/tb/cmd_cat.rb', line 61 def (Tb::Cmd).main_cat(argv) op_cat.parse!(argv) exit_if_help('cat') argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N, Tb::Cmd.opt_cat_with_filename) output_tbenum(creader) end |
.main_consecutive(argv) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/tb/cmd_consecutive.rb', line 56 def (Tb::Cmd).main_consecutive(argv) op_consecutive.parse!(argv) exit_if_help('consecutive') argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) er = Tb::Enumerator.new {|y| buf = [] empty = true creader.with_cumulative_header {|header0| if header0 y.set_header header0.map {|f| (1..Tb::Cmd.opt_consecutive_n).map {|i| "#{f}_#{i}" } }.flatten(1) end }.each {|pairs, header| buf << pairs if buf.length == Tb::Cmd.opt_consecutive_n pairs2 = {} header.each {|f| Tb::Cmd.opt_consecutive_n.times {|i| ps = buf[i] next if !ps.has_key?(f) v = ps[f] pairs2["#{f}_#{i+1}"] = v } } empty = false y.yield pairs2 buf.shift end } } output_tbenum(er) end |
.main_crop(argv) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/tb/cmd_crop.rb', line 46 def (Tb::Cmd).main_crop(argv) op_crop.parse!(argv) exit_if_help('crop') argv = ['-'] if argv.empty? stream = false if Tb::Cmd.opt_crop_range case Tb::Cmd.opt_crop_range when /\AR(\d+)C(\d+):R(\d+)C(\d+)\z/ # 1-based (R1C1 reference style) stream = true range_row1 = $1.to_i range_col1 = $2.to_i range_row2 = $3.to_i range_col2 = $4.to_i when /\A([A-Z]+)(\d+):([A-Z]+)(\d+)\z/ # 1-based (A1 reference style) stream = true range_col1 = decode_a1_addressing_col($1) range_row1 = $2.to_i range_col2 = decode_a1_addressing_col($3) range_row2 = $4.to_i else raise ArgumentError, "unexpected range argument: #{Tb::Cmd.opt_crop_range.inspect}" end end if stream creader = Tb::CatReader.open(argv, true) er = Tb::Enumerator.new {|y| rownum = 1 creader.each {|pairs| if range_row2 < rownum break end if range_row1 <= rownum pairs2 = pairs.reject {|f, v| f = f.to_i f < range_col1 || range_col2 < f } y.yield pairs2 end rownum += 1 } } Tb::Cmd.opt_N = true output_tbenum(er) else creader = Tb::CatReader.open(argv, true) last_nonempty_row = nil lmargin_min = nil ter = Enumerator.new {|y| numrows = 0 creader.each {|pairs| ary = [] pairs.each {|f, v| ary[f.to_i-1] = v } while !ary.empty? && (ary.last.nil? || ary.last == '') ary.pop end if numrows == 0 && ary.empty? next end if !ary.empty? lmargin = 0 while lmargin < ary.length if !ary[lmargin].nil? && ary[lmargin] != '' break end lmargin += 1 end if lmargin_min.nil? || lmargin < lmargin_min lmargin_min = lmargin end end last_nonempty_row = numrows if !ary.empty? y.yield ary numrows += 1 } }.to_fileenumerator er = Tb::Enumerator.new {|y| ter.each_with_index {|ary, rownum| if last_nonempty_row < rownum break end ary.slice!(0, lmargin_min) pairs = Hash[ary.map.with_index {|v, i| ["#{i+1}", v]}] y.yield pairs } } Tb::Cmd.opt_N = true output_tbenum(er) end end |
.main_cross(argv) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/tb/cmd_cross.rb', line 45 def (Tb::Cmd).main_cross(argv) op_cross.parse!(argv) exit_if_help('cross') err('no vkey-fields given.') if argv.empty? vkfs = split_field_list_argument(argv.shift) err('no hkey-fields given.') if argv.empty? hkfs = split_field_list_argument(argv.shift) vhkfs = vkfs + hkfs if Tb::Cmd.opt_cross_fields.empty? num_aggregate_fields = 1 opt_cross_fields = (vkfs + hkfs).map {|f| [f, Tb::Func::First, f] } + [['count', Tb::Func::Count, nil]] else num_aggregate_fields = Tb::Cmd.opt_cross_fields.length opt_cross_fields = (vkfs + hkfs).map {|f| [f, Tb::Func::First, f] } + Tb::Cmd.opt_cross_fields.map {|arg| agg_spec, new_field = split_field_list_argument(arg) new_field ||= agg_spec begin func_srcf = parse_aggregator_spec2(agg_spec) rescue ArgumentError err($!.) end [new_field, *func_srcf] } end argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) er = Tb::Enumerator.new {|y| hvs_hash = {} hvs_list = nil aggs_hash = nil op = Tb::Zipper.new(opt_cross_fields.map {|dstf, func, srcf| func }) er = creader.with_header {|header0| vhkfs.each {|f| if !header0.include?(f) err("field not found: #{f}") end } }.extsort_reduce(op) {|pairs| vvs = vkfs.map {|f| pairs[f] } hvs = hkfs.map {|f| pairs[f] } vvsc = vvs.map {|v| Tb::Func.smart_cmp_value(v) } hvsc = hvs.map {|v| Tb::Func.smart_cmp_value(v) } hvs_hash[hvs] = hvsc aggs = opt_cross_fields.map {|dstf, func, srcf| func.start(srcf ? pairs[srcf] : true) } [[vvsc, hvsc], aggs] } all_representative = lambda {|_| 1 } all_before = lambda {|_| hvs_list = hvs_hash.keys.sort_by {|hvs| hvs_hash[hvs] } n = vkfs.length + hvs_list.length * num_aggregate_fields header1 = (1..n).map {|i| i.to_s } y.set_header header1 hkfs.each_with_index {|hkf, i| next if Tb::Cmd.opt_cross_compact && i == hkfs.length - 1 h1 = {} j = vkfs.length h1[j.to_s] = hkf hvs_list.each {|hkvs| num_aggregate_fields.times { j += 1 h1[j.to_s] = hkvs[i] } } y.yield h1 } h2 = {} j = 0 vkfs.each {|vkf| j += 1 h2[j.to_s] = vkf } hvs_list.each {|hkvs| opt_cross_fields.last(num_aggregate_fields).each {|dstf, func, srcf| j += 1 if Tb::Cmd.opt_cross_compact h2[j.to_s] = hkvs[-1] else h2[j.to_s] = dstf end } } y.yield h2 } v_representative = lambda {|((vvsc, _), _)| vvsc } v_before = lambda {|_| aggs_hash = {} } body = lambda {|(_, aggs)| hvs = aggs[vkfs.length, hkfs.length] aggs_hash[hvs] = op.aggregate(aggs) } v_after = lambda {|(_, aggs)| vvs = aggs[0, vkfs.length] ary = vvs hvs_list.each {|hvs| if aggs_hash.has_key? hvs ary.concat(aggs_hash[hvs].last(num_aggregate_fields)) else ary.concat([nil] * num_aggregate_fields) end } pairs = {} ary.each_with_index {|v, i| pairs[(i+1).to_s] = v } y.yield pairs } er.detect_nested_group_by( [[all_representative, all_before], [v_representative, v_before, v_after]]).each(&body) } Tb::Cmd.opt_N = true output_tbenum(er) end |
.main_cut(argv) ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/tb/cmd_cut.rb', line 42 def (Tb::Cmd).main_cut(argv) op_cut.parse!(argv) exit_if_help('cut') err('no fields given.') if argv.empty? fs = split_field_list_argument(argv.shift) argv = ['-'] if argv.empty? Tb::CatReader.open(argv, Tb::Cmd.opt_N) {|tblreader| if Tb::Cmd.opt_cut_v er = Tb::Enumerator.new {|y| tblreader.with_header {|header0| if header0 y.set_header header0 - fs end }.each {|pairs| y.yield pairs.reject {|k, v| fs.include? k } } } output_tbenum(er) else er = Tb::Enumerator.new {|y| tblreader.with_header {|header0| if header0 fieldset = Tb::FieldSet.new(*header0) fs.each {|f| fieldset.index_from_field_ex(f) } end y.set_header fs }.each {|pairs| y.yield pairs.reject {|k, v| !fs.include?(k) } } } output_tbenum(er) end } end |
.main_git(argv) ⇒ Object
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/tb/cmd_git.rb', line 199 def (Tb::Cmd).main_git(argv) op_git.parse!(argv) exit_if_help('git') argv = ['.'] if argv.empty? er = Tb::Enumerator.new {|y| y.set_header Tb::Cmd::GIT_LOG_HEADER argv.each {|dir| git_with_git_log(dir) {|f| f.set_encoding("ASCII-8BIT") if f.respond_to? :set_encoding git_each_commit(f) {|h| y.yield h } } } } output_tbenum(er) end |
.main_grep(argv) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/tb/cmd_grep.rb', line 48 def (Tb::Cmd).main_grep(argv) op_grep.parse!(argv) exit_if_help('grep') if Tb::Cmd.opt_grep_ruby pred = eval("lambda {|_| #{Tb::Cmd.opt_grep_ruby} }") elsif Tb::Cmd.opt_grep_e re = Regexp.new(Tb::Cmd.opt_grep_e) pred = Tb::Cmd.opt_grep_f ? lambda {|_| re =~ _[Tb::Cmd.opt_grep_f] } : lambda {|_| _.any? {|k, v| re =~ v.to_s } } else err("no regexp given.") if argv.empty? re = Regexp.new(argv.shift) pred = Tb::Cmd.opt_grep_f ? lambda {|_| re =~ _[Tb::Cmd.opt_grep_f] } : lambda {|_| _.any? {|k, v| re =~ v.to_s } } end opt_v = Tb::Cmd.opt_grep_v ? true : false argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) er = Tb::Enumerator.new {|y| header = nil creader.with_header {|header0| header = header0 y.set_header header }.each {|pairs| h = {} pairs.each {|f, v| h[f] = v } found = pred.call(h) found = opt_v ^ !!(found) if found y.yield pairs end } } output_tbenum(er) end |
.main_group(argv) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/tb/cmd_group.rb', line 44 def (Tb::Cmd).main_group(argv) op_group.parse!(argv) exit_if_help('group') err("no key fields given.") if argv.empty? kfs = split_field_list_argument(argv.shift) opt_group_fields = kfs.map {|f| [f, Tb::Func::First, f] } + Tb::Cmd.opt_group_fields.map {|arg| aggregation_spec, new_field = split_field_list_argument(arg) new_field ||= aggregation_spec [new_field, *begin parse_aggregator_spec2(aggregation_spec) rescue ArgumentError err($!.) end ] } argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) result = Tb::Enumerator.new {|y| op = Tb::Zipper.new(opt_group_fields.map {|dstf, func, srcf| func }) er = creader.extsort_reduce(op) {|pairs| [kfs.map {|f| Tb::Func.smart_cmp_value(pairs[f]) }, opt_group_fields.map {|dstf, func, srcf| func.start(srcf ? pairs[srcf] : true) } ] } fields = opt_group_fields.map {|dstf, func, srcf| dstf } y.set_header(fields) er.each {|_, vals| pairs = opt_group_fields.zip(vals).map {|(dstf, func, _), val| [dstf, func.aggregate(val)] } y.yield Hash[pairs] } } output_tbenum(result) end |
.main_gsub(argv) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/tb/cmd_gsub.rb', line 44 def (Tb::Cmd).main_gsub(argv) op_gsub.parse!(argv) exit_if_help('gsub') if Tb::Cmd.opt_gsub_e re = Regexp.new(Tb::Cmd.opt_gsub_e) else err('no regexp given.') if argv.empty? re = Regexp.new(argv.shift) end err('no substitution given.') if argv.empty? repl = argv.shift argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) er = Tb::Enumerator.new {|y| creader.with_cumulative_header {|header0| if header0 y.set_header header0 end }.each {|pairs, header| fs = header.dup fs.pop while !fs.empty? && !pairs.has_key?(fs.last) if Tb::Cmd.opt_gsub_f pairs2 = pairs.map {|f, v| if f == Tb::Cmd.opt_gsub_f v ||= '' [f, v.gsub(re, repl)] else [f, v] end } else pairs2 = pairs.map {|f, v| v ||= '' [f, v.gsub(re, repl)] } end y.yield Hash[pairs2] } } output_tbenum(er) end |
.main_help(argv) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/tb/cmd_help.rb', line 108 def (Tb::Cmd).main_help(argv) op_help.parse!(argv) if Tb::Cmd.opt_help_s list_summary_of_subcommands exit elsif argv.empty? if Tb::Cmd.opt_help == 0 usage_list_subcommands return true else argv.unshift 'help' Tb::Cmd.opt_help -= 1 end end Tb::Cmd.opt_help += 1 subcommand = argv.shift exit_if_help(subcommand) end |
.main_join(argv) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/tb/cmd_join.rb', line 62 def (Tb::Cmd).main_join(argv) op_join.parse!(argv) exit_if_help('join') retain_left = Tb::Cmd.opt_join_retain_left retain_right = Tb::Cmd.opt_join_retain_right err('two tables required at least.') if argv.length < 2 result = tablereader_open(argv.shift) argv.each {|filename| tbl = tablereader_open(filename) $stderr.puts "shared keys: #{(result.list_fields & tbl.list_fields).inspect}" if 1 <= Tb::Cmd.opt_debug result = result.natjoin2_outer(tbl, Tb::Cmd.opt_join_outer_missing, retain_left, retain_right) } output_tbenum(result) end |
.main_ls(argv) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/tb/cmd_ls.rb', line 48 def (Tb::Cmd).main_ls(argv) op_ls.parse!(argv) exit_if_help('ls') argv = ['.'] if argv.empty? opts = { :a => Tb::Cmd.opt_ls_a, :A => Tb::Cmd.opt_ls_A, :l => Tb::Cmd.opt_ls_l, :R => Tb::Cmd.opt_ls_R, } ls = nil er = Tb::Enumerator.new {|y| ls = Tb::Cmd::Ls.new(y, opts) ls.set_header argv.each {|arg| ls.ls_run(Pathname(ls.real_pathname_string(arg))) } } output_tbenum(er) if ls.fail exit false end end |
.main_melt(argv) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/tb/cmd_melt.rb', line 64 def (Tb::Cmd).main_melt(argv) op_melt.parse!(argv) exit_if_help('melt') err('no key-fields given.') if argv.empty? key_fields = split_field_list_argument(argv.shift) key_fields_hash = Hash[key_fields.map {|f| [f, true] }] if Tb::Cmd.opt_melt_regexps.empty? && Tb::Cmd.opt_melt_list.empty? melt_fields_pattern = // else list = Tb::Cmd.opt_melt_list + Tb::Cmd.opt_melt_regexps melt_fields_pattern = /\A#{Regexp.union(list)}\z/ end argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) er = Tb::Enumerator.new {|y| header = [] header << Tb::Cmd.opt_melt_recnum if Tb::Cmd.opt_melt_recnum header.concat key_fields header << Tb::Cmd.opt_melt_variable_field header << Tb::Cmd.opt_melt_value_field y.set_header header creader.each_with_index {|pairs, i| recnum = i + 1 h0 = {} h0[Tb::Cmd.opt_melt_recnum] = nil if Tb::Cmd.opt_melt_recnum key_fields.each {|kf| h0[kf] = pairs[kf] } pairs.each {|f, v| next if key_fields_hash[f] next if melt_fields_pattern !~ f h = h0.dup h[Tb::Cmd.opt_melt_recnum] = recnum if Tb::Cmd.opt_melt_recnum h[Tb::Cmd.opt_melt_variable_field] = f h[Tb::Cmd.opt_melt_value_field] = v y.yield h } } } output_tbenum(er) end |
.main_mheader(argv) ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/tb/cmd_mheader.rb', line 42 def (Tb::Cmd).main_mheader(argv) op_mheader.parse!(argv) exit_if_help('mheader') argv = ['-'] if argv.empty? header = [] if Tb::Cmd.opt_mheader_count c = Tb::Cmd.opt_mheader_count header_end_p = lambda { c -= 1 c == 0 ? header.map {|a| a.compact.join(' ').strip } : nil } else header_end_p = lambda { h2 = header.map {|a| a.compact.join(' ').strip }.uniq header.length == h2.length ? h2 : nil } end creader = Tb::CatReader.open(argv, true) er = Tb::Enumerator.new {|y| creader.each {|pairs| if header ary = [] pairs.each {|f, v| ary[f.to_i-1] = v } ary.each_with_index {|v,i| header[i] ||= [] header[i] << v if header[i].empty? || header[i].last != v } h2 = header_end_p.call if h2 pairs2 = Hash[h2.map.with_index {|v, i| ["#{i+1}", v] }] y.yield pairs2 header = nil end else y.yield pairs end } } Tb::Cmd.opt_N = true output_tbenum(er) if header warn "unique header fields not recognized." end end |
.main_nest(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/tb/cmd_nest.rb', line 39 def (Tb::Cmd).main_nest(argv) op_nest.parse!(argv) exit_if_help('nest') err('no fields given.') if argv.empty? fields = split_field_list_argument(argv.shift) newfield, *oldfields = fields oldfields_hash = {} oldfields.each {|f| oldfields_hash[f] = true } argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) er = Tb::Enumerator.new {|y| sorted = creader.with_header {|header0| oldfields.each {|f| if !header0.include?(f) err("field not found: #{f.inspect}") end } y.set_header(header0.reject {|f| oldfields_hash[f] } + [newfield]) }.map {|pairs| cv = pairs.reject {|f, v| oldfields_hash[f] }.map {|f, v| [Tb::Func.smart_cmp_value(f), Tb::Func.smart_cmp_value(v)] }.sort [cv, pairs] } nested = nil before_group = lambda {|(_, _)| nested = [] } body = lambda {|(_, pairs)| nested << pairs.reject {|f, v| !oldfields_hash[f] } } after_group = lambda {|(_, last_pairs)| Tb.csv_stream_output(nested_csv="") {|ngen| ngen << oldfields nested.each {|npairs| ngen << oldfields.map {|of| npairs[of] } } } assoc = last_pairs.reject {|f, v| oldfields_hash[f] }.to_a assoc << [newfield, nested_csv] pairs = Hash[assoc] y.yield pairs } sorted.detect_group_by(before_group, after_group) {|cv,| cv }.each(&body) } output_tbenum(er) end |
.main_newfield(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/tb/cmd_newfield.rb', line 39 def (Tb::Cmd).main_newfield(argv) op_newfield.parse!(argv) exit_if_help('newfield') err('no new field name given.') if argv.empty? field = argv.shift err('no ruby expression given.') if argv.empty? rubyexp = argv.shift pr = eval("lambda {|_| #{rubyexp} }") argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) er = creader.newfield(field) {|pairs| pr.call(pairs) } output_tbenum(er) end |
.main_rename(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/tb/cmd_rename.rb', line 39 def (Tb::Cmd).main_rename(argv) op_rename.parse!(argv) exit_if_help('rename') err('rename fields not given.') if argv.empty? fs = split_field_list_argument(argv.shift) argv = ['-'] if argv.empty? h = {} fs.each_slice(2) {|sf, df| h[sf] = df } creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) er = Tb::Enumerator.new {|y| header = nil creader.with_header {|header0| header = header0 h.each {|sf, df| unless header.include? sf err "field not found: #{sf.inspect}" end } y.set_header header.map {|f| h.fetch(f, f) } }.each {|pairs| y.yield Hash[pairs.map {|f, v| [h.fetch(f, f), v] }] } } output_tbenum(er) end |
.main_shape(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/tb/cmd_shape.rb', line 39 def (Tb::Cmd).main_shape(argv) op_shape.parse!(argv) exit_if_help('shape') filenames = argv.empty? ? ['-'] : argv result = Tb.new(%w[header_fields min_fields max_fields records filename]) filenames.each {|filename| tablereader_open(filename) {|tblreader| min_num_fields = nil max_num_fields = nil num_records = 0 num_header_fields = nil tblreader.with_header {|header| num_header_fields = header.length }.each {|pairs| ary = pairs.values num_records += 1 n = ary.length if min_num_fields.nil? min_num_fields = max_num_fields = n else min_num_fields = n if n < min_num_fields max_num_fields = n if max_num_fields < n end } result.insert({'header_fields'=>num_header_fields, 'min_fields'=>min_num_fields, 'max_fields'=>max_num_fields, 'records'=>num_records, 'filename'=>filename}) } } Tb::Cmd.opt_N = false output_tbenum(result) end |
.main_sort(argv) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/tb/cmd_sort.rb', line 44 def (Tb::Cmd).main_sort(argv) op_sort.parse!(argv) exit_if_help('sort') argv = ['-'] if argv.empty? if Tb::Cmd.opt_sort_f fs = split_field_list_argument(Tb::Cmd.opt_sort_f) else fs = nil end creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) header = [] if fs blk = lambda {|pairs| fs.map {|f| Tb::Func.smart_cmp_value(pairs[f]) } } else blk = lambda {|pairs| header.map {|f| Tb::Func.smart_cmp_value(pairs[f]) } } end if Tb::Cmd.opt_sort_r blk1 = blk blk = lambda {|pairs| Tb::RevCmp.new(blk1.call(pairs)) } end er = Tb::Enumerator.new {|y| creader.with_cumulative_header {|header0| if header0 y.set_header(header0) end }.each {|pairs, header1| header = header1 y.yield pairs } }.extsort_by(&blk) output_tbenum(er) end |
.main_svn(argv) ⇒ Object
173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/tb/cmd_svn.rb', line 173 def (Tb::Cmd).main_svn(argv) op_svn.parse!(argv) exit_if_help('svn') er = Tb::Enumerator.new {|y| svn_with_svn_log(argv) {|f| listener = Tb::Cmd::SVNLOGListener.new(y) REXML::Parsers::StreamParser.new(f, listener).parse } } output_tbenum(er) end |
.main_to_csv(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/tb/cmd_to_csv.rb', line 39 def (Tb::Cmd).main_to_csv(argv) op_to_csv.parse!(argv) exit_if_help('to-csv') argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) header = [] ter = Tb::Enumerator.new {|y| creader.with_cumulative_header.each {|pairs, header1| header = header1 y.yield pairs } }.to_fileenumerator er = Tb::Enumerator.new {|y| y.set_header header ter.each {|pairs| y.yield Hash[header.map {|f| [f, pairs[f]] }] } } with_output {|out| er.write_to_csv(out, !Tb::Cmd.opt_N) } end |
.main_to_json(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/tb/cmd_to_json.rb', line 39 def (Tb::Cmd).main_to_json(argv) require 'json' op_to_json.parse!(argv) exit_if_help('to-json') argv = ['-'] if argv.empty? with_output {|out| out.print "[" sep = nil argv.each {|filename| sep = ",\n\n" if sep tablereader_open(filename) {|tblreader| tblreader.each {|pairs| out.print sep if sep out.print JSON.pretty_generate(Hash[pairs.to_a]) sep = ",\n" } } } out.puts "]" } end |
.main_to_pnm(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 |
# File 'lib/tb/cmd_to_pnm.rb', line 39 def (Tb::Cmd).main_to_pnm(argv) op_to_pnm.parse!(argv) exit_if_help('to-pnm') argv = ['-'] if argv.empty? tbl = Tb::CatReader.open(argv, Tb::Cmd.opt_N).to_tb with_output {|out| tbl.generate_pnm(out) } end |
.main_to_pp(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/tb/cmd_to_pp.rb', line 39 def (Tb::Cmd).main_to_pp(argv) op_to_pp.parse!(argv) exit_if_help('to-pp') argv.unshift '-' if argv.empty? with_output {|out| argv.each {|filename| tablereader_open(filename) {|tblreader| tblreader.each {|pairs| a = pairs.reject {|f, v| v.nil? } q = PP.new(out, 79) q.guard_inspect_key { q.group(1, '{', '}') { q.seplist(a, nil, :each) {|kv| k, v = kv q.group { q.pp k q.text '=>' q.group(1) { q.breakable '' q.pp v } } } } } q.flush out << "\n" } } } } end |
.main_to_tsv(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 |
# File 'lib/tb/cmd_to_tsv.rb', line 39 def (Tb::Cmd).main_to_tsv(argv) op_to_tsv.parse!(argv) exit_if_help('to-tsv') argv = ['-'] if argv.empty? tbl = Tb::CatReader.open(argv, Tb::Cmd.opt_N).to_tb with_output {|out| tbl_generate_tsv(tbl, out) } end |
.main_to_yaml(argv) ⇒ Object
39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/tb/cmd_to_yaml.rb', line 39 def (Tb::Cmd).main_to_yaml(argv) require 'yaml' op_to_yaml.parse!(argv) exit_if_help('to-yaml') argv = ['-'] if argv.empty? tbl = Tb::CatReader.open(argv, Tb::Cmd.opt_N).to_tb ary = tbl.map {|rec| rec.to_h } with_output {|out| YAML.dump(ary, out) out.puts } end |
.main_unmelt(argv) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/tb/cmd_unmelt.rb', line 61 def (Tb::Cmd).main_unmelt(argv) op_unmelt.parse!(argv) exit_if_help('unmelt') argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) if Tb::Cmd.opt_unmelt_keys.empty? key_fields = nil else if Tb::Cmd.opt_unmelt_recnum key_fields = [Tb::Cmd.opt_unmelt_recnum] else key_fields = [] end key_fields += Tb::Cmd.opt_unmelt_keys end melt_fields_hash = {} er = Tb::Enumerator.new {|y| creader.chunk {|pairs| keys = {} if key_fields key_fields.each {|k| keys[k] = pairs[k] } else pairs.each_key {|k| next if k == Tb::Cmd.opt_unmelt_variable_field || k == Tb::Cmd.opt_unmelt_value_field keys[k] = pairs[k] } end keys }.each {|keys, pairs_ary| if Tb::Cmd.opt_unmelt_recnum keys.delete Tb::Cmd.opt_unmelt_recnum end rec = keys.dup pairs_ary.each {|pairs| var = pairs[Tb::Cmd.opt_unmelt_variable_field] val = pairs[Tb::Cmd.opt_unmelt_value_field] melt_fields_hash[var] = true if rec.has_key? var y.yield rec rec = keys.dup end rec[var] = val } y.yield rec } } if !Tb::Cmd.opt_unmelt_missing_value er2 = er else er2 = Tb::Enumerator.new {|y| er.to_fileenumerator.with_header {|header| y.set_header header }.each {|pairs| melt_fields_hash.each_key {|f| pairs[f] ||= Tb::Cmd.opt_unmelt_missing_value } y.yield pairs } } end output_tbenum(er2) end |
.main_unnest(argv) ⇒ Object
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/tb/cmd_unnest.rb', line 44 def (Tb::Cmd).main_unnest(argv) op_unnest.parse!(argv) exit_if_help('unnest') err('no field given.') if argv.empty? target_field = argv.shift argv = ['-'] if argv.empty? creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N) er = Tb::Enumerator.new {|y| nested_fields = {} ter = Tb::Enumerator.new {|y2| creader.with_header {|header0| unless header0.include? target_field err("field not found: #{target_field.inspect}") end y2.set_header header0 }.each {|pairs| pairs2 = {} pairs.each {|f, v| if f != target_field pairs2[f] = v elsif v.nil? pairs2[f] = v else nested_tbl = Tb.parse_csv(v) nested_tbl.list_fields.each {|f2| unless nested_fields.has_key? f2 nested_fields[f2] = nested_fields.size end } pairs2[f] = nested_tbl end } y2.yield pairs2 } }.to_fileenumerator nested_fields_ary = nested_fields.keys if Tb::Cmd.opt_unnest_prefix nested_fields_ary.map! {|f| Tb::Cmd.opt_unnest_prefix + f } end ter.with_header {|header0| header2 = [] header0.each {|f| if f != target_field header2 << f else header2.concat nested_fields_ary end } y.set_header header2 }.each {|pairs| pairs2 = pairs.reject {|f, v| f == target_field } ntbl = pairs[target_field] if ntbl.nil? || ntbl.empty? if Tb::Cmd.opt_unnest_outer y.yield pairs2 end else ntbl.each {|npairs| pairs3 = pairs2.dup npairs.each {|nf, nv| if Tb::Cmd.opt_unnest_prefix nf = Tb::Cmd.opt_unnest_prefix + nf end pairs3[nf] = nv } y.yield pairs3 } end } } output_tbenum(er) end |
.op_cat ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/tb/cmd_cat.rb', line 33 def (Tb::Cmd).op_cat op = OptionParser.new op. = "Usage: tb cat [OPTS] [TABLE ...]\n" + "Concatenate tables vertically." define_common_option(op, "hNo", "--no-pager") op.def_option('-H', '--with-filename', 'add filename column') { Tb::Cmd.opt_cat_with_filename = true } op end |
.op_consecutive ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/tb/cmd_consecutive.rb', line 33 def (Tb::Cmd).op_consecutive op = OptionParser.new op. = "Usage: tb consecutive [OPTS] [TABLE ...]\n" + "Concatenate consecutive rows." define_common_option(op, "hNo", "--no-pager") op.def_option('-n NUM', 'gather NUM records. (default: 2)') {|n| Tb::Cmd.opt_consecutive_n = n.to_i } op end |
.op_crop ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/tb/cmd_crop.rb', line 33 def (Tb::Cmd).op_crop op = OptionParser.new op. = "Usage: tb crop [OPTS] [TABLE ...]\n" + "Extract rectangle in a table." define_common_option(op, "ho", "--no-pager") op.def_option('-r RANGE', 'range. i.e. "2,1-4,3", "B1:D3"') {|arg| Tb::Cmd.opt_crop_range = arg } op end |
.op_cross ⇒ Object
34 35 36 37 38 39 40 41 42 43 |
# File 'lib/tb/cmd_cross.rb', line 34 def (Tb::Cmd).op_cross op = OptionParser.new op. = "Usage: tb cross [OPTS] VKEY-FIELD1,... HKEY-FIELD1,... [TABLE ...]\n" + "Create a cross table. (a.k.a contingency table, pivot table)" define_common_option(op, "ho", "--no-pager") op.def_option('-a AGGREGATION-SPEC[,NEW-FIELD]', '--aggregate AGGREGATION-SPEC[,NEW-FIELD]') {|arg| Tb::Cmd.opt_cross_fields << arg } op.def_option('-c', '--compact', 'compact format') { Tb::Cmd.opt_cross_compact = true } op end |
.op_cut ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/tb/cmd_cut.rb', line 33 def (Tb::Cmd).op_cut op = OptionParser.new op. = "Usage: tb cut [OPTS] FIELD,... [TABLE]\n" + "Select columns." define_common_option(op, "hNo", "--no-pager") op.def_option('-v', 'invert match') { Tb::Cmd.opt_cut_v = true } op end |
.op_git ⇒ Object
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/tb/cmd_git.rb', line 35 def (Tb::Cmd).op_git op = OptionParser.new op. = "Usage: tb git [OPTS] [GIT-DIR ...]\n" + "Show the GIT log as a table." define_common_option(op, "hNod", "--no-pager", '--debug') op.def_option('--git-command COMMAND', 'specify the git command (default: git)') {|command| Tb::Cmd.opt_git_command = command } op.def_option('--debug-git-output FILE', 'store the raw output of git (for debug)') {|filename| Tb::Cmd.opt_git_debug_output = filename } op.def_option('--debug-git-input FILE', 'use the file as output of git (for debug)') {|filename| Tb::Cmd.opt_git_debug_input = filename } op end |
.op_grep ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/tb/cmd_grep.rb', line 36 def (Tb::Cmd).op_grep op = OptionParser.new op. = "Usage: tb grep [OPTS] REGEXP [TABLE ...]\n" + "Search rows using regexp or ruby expression." define_common_option(op, "hNo", "--no-pager") op.def_option('-f FIELD', 'search field') {|field| Tb::Cmd.opt_grep_f = field } op.def_option('-e REGEXP', 'predicate written in ruby. A hash is given as _. no usual regexp argument.') {|pattern| Tb::Cmd.opt_grep_e = pattern } op.def_option('--ruby RUBY-EXP', 'specify a regexp. no usual regexp argument.') {|ruby_exp| Tb::Cmd.opt_grep_ruby = ruby_exp } op.def_option('-v', 'ouput the records which doesn\'t match') { Tb::Cmd.opt_grep_v = true } op end |
.op_group ⇒ Object
33 34 35 36 37 38 39 40 41 42 |
# File 'lib/tb/cmd_group.rb', line 33 def (Tb::Cmd).op_group op = OptionParser.new op. = "Usage: tb group [OPTS] KEY-FIELD1,... [TABLE ...]\n" + "Group and aggregate rows." define_common_option(op, "hNo", "--no-pager") op.def_option('-a AGGREGATION-SPEC[,NEW-FIELD]', '--aggregate AGGREGATION-SPEC[,NEW-FIELD]') {|arg| Tb::Cmd.opt_group_fields << arg } op.def_option('--no-pager', 'don\'t use pager') { Tb::Cmd.opt_no_pager = true } op end |
.op_gsub ⇒ Object
34 35 36 37 38 39 40 41 42 |
# File 'lib/tb/cmd_gsub.rb', line 34 def (Tb::Cmd).op_gsub op = OptionParser.new op. = "Usage: tb gsub [OPTS] REGEXP STRING [TABLE ...]\n" + "Substitute cells." define_common_option(op, "hNo", "--no-pager") op.def_option('-f FIELD', 'target field') {|field| Tb::Cmd.opt_gsub_f = field } op.def_option('-e REGEXP', 'specify regexp, possibly begins with a hyphen') {|pattern| Tb::Cmd.opt_gsub_e = pattern } op end |
.op_help ⇒ Object
60 61 62 63 64 65 66 67 |
# File 'lib/tb/cmd_help.rb', line 60 def (Tb::Cmd).op_help op = OptionParser.new op. = "Usage: tb help [OPTS] [SUBCOMMAND]\n" + "Show help message of tb command." define_common_option(op, "hvo", "--no-pager") op.def_option('-s', 'show summary of subcommands') { Tb::Cmd.opt_help_s = true } op end |
.op_join ⇒ Object
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/tb/cmd_join.rb', line 35 def (Tb::Cmd).op_join op = OptionParser.new op. = "Usage: tb join [OPTS] [TABLE1 TABLE2 ...]\n" + "Concatenate tables horizontally as left/right/full natural join." define_common_option(op, 'hNod', '--no-pager', '--debug') op.def_option('--outer', 'outer join') { Tb::Cmd.opt_join_retain_left = true Tb::Cmd.opt_join_retain_right = true } op.def_option('--left', 'left outer join') { Tb::Cmd.opt_join_retain_left = true Tb::Cmd.opt_join_retain_right = false } op.def_option('--right', 'right outer join') { Tb::Cmd.opt_join_retain_left = false Tb::Cmd.opt_join_retain_right = true } op.def_option('--outer-missing=DEFAULT', 'missing value for outer join') {|missing| if Tb::Cmd.opt_join_retain_left == nil Tb::Cmd.opt_join_retain_left = true Tb::Cmd.opt_join_retain_right = true end Tb::Cmd.opt_join_outer_missing = missing } op end |
.op_ls ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/tb/cmd_ls.rb', line 36 def (Tb::Cmd).op_ls op = OptionParser.new op. = "Usage: tb ls [OPTS] [FILE ...]\n" + "List directory entries as a table." define_common_option(op, "hNo", "--no-pager") op.def_option('-a', 'don\'t ignore filenames beginning with a period.') {|fs| Tb::Cmd.opt_ls_a = true } op.def_option('-A', 'don\'t ignore filenames beginning with a period, except "." and "..".') {|fs| Tb::Cmd.opt_ls_A = true } op.def_option('-l', 'show attributes. -ll for more attributes.') {|fs| Tb::Cmd.opt_ls_l += 1 } op.def_option('-R', 'recursive.') {|fs| Tb::Cmd.opt_ls_R = true } op end |
.op_melt ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/tb/cmd_melt.rb', line 37 def (Tb::Cmd).op_melt op = OptionParser.new op. = "Usage: tb melt KEY-FIELDS-LIST [OPTS] [TABLE ...]\n" + "split value fields into records." define_common_option(op, "hNo", "--no-pager") op.def_option('--recnum[=FIELD]', 'add recnum field (default don\'t add)') {|field| Tb::Cmd.opt_melt_recnum = field || 'recnum' } op.def_option('-R REGEXP', '--melt-regexp REGEXP', 'regexp for melt fields') {|regexp| Tb::Cmd.opt_melt_regexps << Regexp.compile(regexp) } op.def_option('--melt-fields FIELD,...', 'list of melt fields') {|fields| Tb::Cmd.opt_melt_list.concat split_field_list_argument(fields) } op.def_option('--variable-field FIELD', 'variable field. (default: variable)') {|field| Tb::Cmd.opt_melt_variable_field = field } op.def_option('--value-field FIELD', 'value field. (default: value)') {|field| Tb::Cmd.opt_melt_value_field = field } op end |
.op_mheader ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/tb/cmd_mheader.rb', line 33 def (Tb::Cmd).op_mheader op = OptionParser.new op. = "Usage: tb mheader [OPTS] [TABLE]\n" + "Collapse multi rows header." define_common_option(op, "ho", "--no-pager") op.def_option('-c N', 'number of header records') {|arg| Tb::Cmd.opt_mheader_count = arg.to_i } op end |
.op_nest ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_nest.rb', line 31 def (Tb::Cmd).op_nest op = OptionParser.new op. = "Usage: tb nest [OPTS] NEWFIELD,OLDFIELD1,OLDFIELD2,... [TABLE ...]\n" + "Nest fields." define_common_option(op, "hNo", "--no-pager") op end |
.op_newfield ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_newfield.rb', line 31 def (Tb::Cmd).op_newfield op = OptionParser.new op. = "Usage: tb newfield [OPTS] FIELD RUBY-EXP [TABLE]\n" + "Add a field." define_common_option(op, "ho", "--no-pager") op end |
.op_rename ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_rename.rb', line 31 def (Tb::Cmd).op_rename op = OptionParser.new op. = "Usage: tb rename [OPTS] SRC,DST,... [TABLE]\n" + "Rename field names." define_common_option(op, "ho", "--no-pager") op end |
.op_shape ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_shape.rb', line 31 def (Tb::Cmd).op_shape op = OptionParser.new op. = "Usage: tb shape [OPTS] [TABLE ...]\n" + "Show table size." define_common_option(op, "hNo", "--no-pager") op end |
.op_sort ⇒ Object
34 35 36 37 38 39 40 41 42 |
# File 'lib/tb/cmd_sort.rb', line 34 def (Tb::Cmd).op_sort op = OptionParser.new op. = "Usage: tb sort [OPTS] [TABLE]\n" + "Sort rows." define_common_option(op, "hNo", "--no-pager") op.def_option('-f FIELD,...', 'specify sort keys') {|fs| Tb::Cmd.opt_sort_f = fs } op.def_option('-r', '--reverse', 'reverse order') { Tb::Cmd.opt_sort_r = true } op end |
.op_svn ⇒ Object
36 37 38 39 40 41 42 43 44 |
# File 'lib/tb/cmd_svn.rb', line 36 def (Tb::Cmd).op_svn op = OptionParser.new op. = "Usage: tb svn [OPTS] -- [SVN-LOG-ARGS]\n" + "Show the SVN log as a table." define_common_option(op, "hNo", "--no-pager") op.def_option('--svn-command COMMAND', 'specify the svn command (default: svn)') {|command| Tb::Cmd.opt_svn_command = command } op.def_option('--svn-log-xml FILE', 'specify the result svn log --xml') {|filename| Tb::Cmd.opt_svn_log_xml = filename } op end |
.op_to_csv ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_to_csv.rb', line 31 def (Tb::Cmd).op_to_csv op = OptionParser.new op. = "Usage: tb to-csv [OPTS] [TABLE ...]\n" + "Convert a table to CSV (Comma Separated Value)." define_common_option(op, "hNo", "--no-pager") op end |
.op_to_json ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_to_json.rb', line 31 def (Tb::Cmd).op_to_json op = OptionParser.new op. = "Usage: tb to-json [OPTS] [TABLE]\n" + "Convert a table to JSON (JavaScript Object Notation)." define_common_option(op, "hNo", "--no-pager") op end |
.op_to_pnm ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_to_pnm.rb', line 31 def (Tb::Cmd).op_to_pnm op = OptionParser.new op. = "Usage: tb to-pnm [OPTS] [TABLE]\n" + "Convert a table to PNM (Portable Anymap: PPM, PGM, PBM)." define_common_option(op, "hNo", "--no-pager") op end |
.op_to_pp ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_to_pp.rb', line 31 def (Tb::Cmd).op_to_pp op = OptionParser.new op. = "Usage: tb to-pp [OPTS] [TABLE]\n" + "Convert a table to pretty printed format." define_common_option(op, "hNo", "--no-pager") op end |
.op_to_tsv ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_to_tsv.rb', line 31 def (Tb::Cmd).op_to_tsv op = OptionParser.new op. = "Usage: tb to-tsv [OPTS] [TABLE]\n" + "Convert a table to TSV (Tab Separated Value)." define_common_option(op, "hNo", "--no-pager") op end |
.op_to_yaml ⇒ Object
31 32 33 34 35 36 37 |
# File 'lib/tb/cmd_to_yaml.rb', line 31 def (Tb::Cmd).op_to_yaml op = OptionParser.new op. = "Usage: tb to-yaml [OPTS] [TABLE]\n" + "Convert a table to YAML (YAML Ain't a Markup Language)." define_common_option(op, "hNo", "--no-pager") op end |
.op_unmelt ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/tb/cmd_unmelt.rb', line 37 def (Tb::Cmd).op_unmelt op = OptionParser.new op. = "Usage: tb unmelt [OPTS] [TABLE ...]\n" + "merge melted records into a record." define_common_option(op, "hNo", "--no-pager") op.def_option('--recnum[=FIELD]', 'use FIELD as an additional key and remove it from the result. (default: not specified)') {|field| Tb::Cmd.opt_unmelt_recnum = field || 'recnum' } op.def_option('--keys FIELD,...', 'key fields. (default: all fields except variable and value)') {|fields| Tb::Cmd.opt_unmelt_keys.concat split_field_list_argument(fields) } op.def_option('--variable-field FIELD', 'variable field. (default: variable)') {|field| Tb::Cmd.opt_unmelt_variable_field = field } op.def_option('--value-field FIELD', 'value field. (default: value)') {|field| Tb::Cmd.opt_unmelt_value_field = field } op.def_option('--missing-value FIELD', 'used for missing values. (default: not specified)') {|value| Tb::Cmd.opt_unmelt_missing_value = value } op end |
.op_unnest ⇒ Object
34 35 36 37 38 39 40 41 42 |
# File 'lib/tb/cmd_unnest.rb', line 34 def (Tb::Cmd).op_unnest op = OptionParser.new op. = "Usage: tb unnest [OPTS] FIELD [TABLE ...]\n" + "Unnest a field." define_common_option(op, "hNo", "--no-pager") op.def_option('--prefix PREFIX', 'field prefix') {|prefix| Tb::Cmd.opt_unnest_prefix = prefix } op.def_option('--outer', 'retain rows for empty nested table') { Tb::Cmd.opt_unnest_outer = true } op end |
.show_help(subcommand) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/tb/cmd_help.rb', line 93 def (Tb::Cmd).show_help(subcommand) if Tb::Cmd.subcommands.include?(subcommand) with_output {|f| f.puts self.subcommand_send("op", subcommand) if 2 <= Tb::Cmd.opt_help && Tb::Cmd.verbose_help[subcommand] f.puts f.puts Tb::Cmd.verbose_help[subcommand] end } true else err "unexpected subcommand: #{subcommand.inspect}" end end |
.svn_with_svn_log(argv) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/tb/cmd_svn.rb', line 160 def (Tb::Cmd).svn_with_svn_log(argv) if Tb::Cmd.opt_svn_log_xml File.open(Tb::Cmd.opt_svn_log_xml) {|f| yield f } else svn = Tb::Cmd.opt_svn_command || 'svn' IO.popen([svn, 'log', '--xml', *argv]) {|f| yield f } end end |
.usage_list_subcommands ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/tb/cmd_help.rb', line 33 def (Tb::Cmd).usage_list_subcommands with_output {|f| f.print "Usage:\n" Tb::Cmd.subcommands.each {|subcommand| = self.subcommand_send("op", subcommand). usage = [/^Usage: (.*)/, 1] f.puts " " + usage } } end |
Instance Method Details
#err(msg) ⇒ Object
95 96 97 |
# File 'lib/tb/cmdutil.rb', line 95 def err(msg) raise SystemExit.new(1, msg) end |
#output_tbenum(te) ⇒ Object
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/tb/cmdutil.rb', line 179 def output_tbenum(te) filename = Tb::Cmd.opt_output if /\A([a-z0-9]{2,}):/ =~ filename fmt = $1 filename = $' else fmt = nil end if !fmt case filename when /\.csv\z/ fmt = 'csv' when /\.json\z/ fmt = 'json' end end if fmt case fmt when 'csv' write_proc = lambda {|out| te.write_to_csv(out, !Tb::Cmd.opt_N) } when 'json' write_proc = lambda {|out| te.write_to_json(out) } else err("unexpected format: #{fmt.inspect}") end end write_proc ||= lambda {|out| te.write_to_csv(out, !Tb::Cmd.opt_N) } with_output(filename) {|out| write_proc.call(out) } end |
#parse_aggregator_spec(spec) ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/tb/cmdutil.rb', line 99 def parse_aggregator_spec(spec) case spec when 'count' ['count', nil] when /\Asum\((.*)\)\z/ ['sum', $1] when /\Aavg\((.*)\)\z/ ['avg', $1] when /\Amax\((.*)\)\z/ ['max', $1] when /\Amin\((.*)\)\z/ ['min', $1] when /\Avalues\((.*)\)\z/ ['values', $1] when /\Auniquevalues\((.*)\)\z/ ['uniquevalues', $1] else raise ArgumentError, "unexpected aggregation spec: #{spec.inspect}" end end |
#parse_aggregator_spec2(spec) ⇒ Object
120 121 122 123 124 125 126 127 |
# File 'lib/tb/cmdutil.rb', line 120 def parse_aggregator_spec2(spec) name, field = parse_aggregator_spec(spec) func = Tb::Func::AggregationFunctions[name] if !func raise ArgumentError, "unexpected aggregation spec: #{spec.inspect}" end [func, field] end |
#split_csv_argument(arg) ⇒ Object
133 134 135 136 |
# File 'lib/tb/cmdutil.rb', line 133 def split_csv_argument(arg) Tb.csv_stream_input(arg) {|ary| return ary } return [] end |
#split_field_list_argument(arg) ⇒ Object
129 130 131 |
# File 'lib/tb/cmdutil.rb', line 129 def split_field_list_argument(arg) split_csv_argument(arg).map {|f| f || '' } end |
#tablereader_open(filename, &b) ⇒ Object
138 139 140 |
# File 'lib/tb/cmdutil.rb', line 138 def tablereader_open(filename, &b) Tb.open_reader(filename, {:numeric=>Tb::Cmd.opt_N}, &b) end |
#tbl_generate_tsv(tbl, out) ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/tb/cmdutil.rb', line 142 def tbl_generate_tsv(tbl, out) if Tb::Cmd.opt_N header = tbl.list_fields Tb.tsv_stream_output(out) {|gen| tbl.each {|rec| gen << rec.values_at(*header) } } else tbl.generate_tsv(out) end end |
#with_output(filename = Tb::Cmd.opt_output) ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/tb/cmdutil.rb', line 155 def with_output(filename=Tb::Cmd.opt_output) if filename && filename != '-' tmp = filename + ".part" begin File.open(tmp, 'w') {|f| yield f } if File.exist?(filename) && FileUtils.compare_file(filename, tmp) File.unlink tmp else File.rename tmp, filename end ensure File.unlink tmp if File.exist? tmp end elsif $stdout.tty? && !Tb::Cmd.opt_no_pager Tb::Pager.open {|pager| yield pager } else yield $stdout end end |