tb 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/README +62 -50
  2. data/bin/tb +22 -18
  3. data/lib/tb.rb +35 -19
  4. data/lib/tb/basic.rb +85 -86
  5. data/lib/tb/catreader.rb +33 -116
  6. data/lib/tb/cmd_cat.rb +31 -27
  7. data/lib/tb/cmd_consecutive.rb +45 -35
  8. data/lib/tb/cmd_crop.rb +86 -52
  9. data/lib/tb/cmd_cross.rb +113 -71
  10. data/lib/tb/cmd_cut.rb +49 -44
  11. data/lib/tb/cmd_git_log.rb +193 -0
  12. data/lib/tb/cmd_grep.rb +43 -32
  13. data/lib/tb/cmd_group.rb +63 -39
  14. data/lib/tb/cmd_gsub.rb +53 -43
  15. data/lib/tb/cmd_help.rb +51 -24
  16. data/lib/tb/cmd_join.rb +32 -35
  17. data/lib/tb/cmd_ls.rb +233 -205
  18. data/lib/tb/cmd_mheader.rb +47 -37
  19. data/lib/tb/cmd_nest.rb +94 -0
  20. data/lib/tb/cmd_newfield.rb +29 -33
  21. data/lib/tb/cmd_rename.rb +40 -32
  22. data/lib/tb/cmd_shape.rb +31 -24
  23. data/lib/tb/cmd_sort.rb +46 -25
  24. data/lib/tb/cmd_svn_log.rb +47 -28
  25. data/lib/tb/cmd_tar_tvf.rb +447 -0
  26. data/lib/tb/cmd_to_csv.rb +60 -0
  27. data/lib/tb/cmd_to_json.rb +60 -0
  28. data/lib/tb/cmd_to_pnm.rb +48 -0
  29. data/lib/tb/cmd_to_pp.rb +71 -0
  30. data/lib/tb/cmd_to_tsv.rb +48 -0
  31. data/lib/tb/cmd_to_yaml.rb +52 -0
  32. data/lib/tb/cmd_unnest.rb +118 -0
  33. data/lib/tb/cmdmain.rb +24 -20
  34. data/lib/tb/cmdtop.rb +33 -25
  35. data/lib/tb/cmdutil.rb +26 -66
  36. data/lib/tb/csv.rb +46 -34
  37. data/lib/tb/enum.rb +294 -0
  38. data/lib/tb/enumerable.rb +198 -7
  39. data/lib/tb/enumerator.rb +73 -0
  40. data/lib/tb/fieldset.rb +27 -19
  41. data/lib/tb/fileenumerator.rb +365 -0
  42. data/lib/tb/json.rb +50 -0
  43. data/lib/tb/pager.rb +6 -6
  44. data/lib/tb/pairs.rb +227 -0
  45. data/lib/tb/pnm.rb +23 -22
  46. data/lib/tb/reader.rb +52 -49
  47. data/lib/tb/record.rb +48 -19
  48. data/lib/tb/revcmp.rb +38 -0
  49. data/lib/tb/ropen.rb +74 -57
  50. data/lib/tb/search.rb +25 -21
  51. data/lib/tb/tsv.rb +31 -34
  52. data/sample/excel2csv +24 -20
  53. data/sample/poi-xls2csv.rb +24 -20
  54. data/sample/poi-xls2csv.sh +22 -18
  55. data/sample/tbplot +185 -127
  56. data/test-all-cov.rb +3 -3
  57. data/test-all.rb +1 -1
  58. data/test/test_basic.rb +26 -10
  59. data/test/test_catreader.rb +7 -6
  60. data/test/test_cmd_cat.rb +32 -0
  61. data/test/test_cmd_consecutive.rb +10 -0
  62. data/test/test_cmd_crop.rb +4 -4
  63. data/test/test_cmd_cross.rb +16 -4
  64. data/test/test_cmd_git_log.rb +46 -0
  65. data/test/test_cmd_help.rb +17 -12
  66. data/test/test_cmd_join.rb +21 -1
  67. data/test/test_cmd_ls.rb +3 -4
  68. data/test/test_cmd_mheader.rb +17 -11
  69. data/test/test_cmd_nest.rb +49 -0
  70. data/test/test_cmd_sort.rb +15 -0
  71. data/test/test_cmd_tar_tvf.rb +281 -0
  72. data/test/{test_cmd_csv.rb → test_cmd_to_csv.rb} +35 -21
  73. data/test/{test_cmd_json.rb → test_cmd_to_json.rb} +31 -3
  74. data/test/{test_cmd_pnm.rb → test_cmd_to_pnm.rb} +2 -2
  75. data/test/{test_cmd_pp.rb → test_cmd_to_pp.rb} +4 -4
  76. data/test/{test_cmd_tsv.rb → test_cmd_to_tsv.rb} +4 -4
  77. data/test/{test_cmd_yaml.rb → test_cmd_to_yaml.rb} +3 -3
  78. data/test/test_cmd_unnest.rb +89 -0
  79. data/test/test_cmdtty.rb +19 -13
  80. data/test/test_enumerable.rb +83 -1
  81. data/test/test_fileenumerator.rb +265 -0
  82. data/test/test_json.rb +15 -0
  83. data/test/test_pager.rb +3 -4
  84. data/test/test_pairs.rb +122 -0
  85. data/test/test_pnm.rb +24 -24
  86. data/test/test_reader.rb +35 -13
  87. data/test/test_revcmp.rb +10 -0
  88. data/test/test_tbenum.rb +173 -0
  89. metadata +51 -23
  90. data/lib/tb/cmd_csv.rb +0 -42
  91. data/lib/tb/cmd_json.rb +0 -60
  92. data/lib/tb/cmd_pnm.rb +0 -43
  93. data/lib/tb/cmd_pp.rb +0 -70
  94. data/lib/tb/cmd_tsv.rb +0 -43
  95. data/lib/tb/cmd_yaml.rb +0 -47
data/lib/tb/cmd_grep.rb CHANGED
@@ -1,26 +1,30 @@
1
- # Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
1
+ # Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
2
2
  #
3
3
  # Redistribution and use in source and binary forms, with or without
4
- # modification, are permitted provided that the following conditions are met:
4
+ # modification, are permitted provided that the following conditions
5
+ # are met:
5
6
  #
6
- # 1. Redistributions of source code must retain the above copyright notice, this
7
- # list of conditions and the following disclaimer.
8
- # 2. Redistributions in binary form must reproduce the above copyright notice,
9
- # this list of conditions and the following disclaimer in the documentation
10
- # and/or other materials provided with the distribution.
11
- # 3. The name of the author may not be used to endorse or promote products
12
- # derived from this software without specific prior written permission.
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above
10
+ # copyright notice, this list of conditions and the following
11
+ # disclaimer in the documentation and/or other materials provided
12
+ # with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote
14
+ # products derived from this software without specific prior
15
+ # written permission.
13
16
  #
14
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
- # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
- # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
- # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
- # OF SUCH DAMAGE.
17
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18
+ # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23
+ # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
28
 
25
29
  Tb::Cmd.subcommands << 'grep'
26
30
 
@@ -31,7 +35,8 @@ Tb::Cmd.default_option[:opt_grep_v] = nil
31
35
 
32
36
  def (Tb::Cmd).op_grep
33
37
  op = OptionParser.new
34
- op.banner = 'Usage: tb grep [OPTS] REGEXP [TABLE ...]'
38
+ op.banner = "Usage: tb grep [OPTS] REGEXP [TABLE ...]\n" +
39
+ "Search rows using regexp or ruby expression."
35
40
  define_common_option(op, "hNo", "--no-pager")
36
41
  op.def_option('-f FIELD', 'search field') {|field| Tb::Cmd.opt_grep_f = field }
37
42
  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 }
@@ -57,20 +62,26 @@ def (Tb::Cmd).main_grep(argv)
57
62
  end
58
63
  opt_v = Tb::Cmd.opt_grep_v ? true : false
59
64
  argv = ['-'] if argv.empty?
60
- Tb::CatReader.open(argv, Tb::Cmd.opt_N) {|tblreader|
61
- with_table_stream_output {|gen|
62
- gen.output_header tblreader.header
63
- tblreader.each {|ary|
64
- h = {}
65
- ary.each_with_index {|str, i|
66
- f = tblreader.field_from_index_ex(i)
67
- h[f] = str
68
- }
69
- found = pred.call(h)
70
- found = opt_v ^ !!(found)
71
- gen << ary if found
65
+ creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N)
66
+ er = Tb::Enumerator.new {|y|
67
+ header = nil
68
+ creader.with_header {|header0|
69
+ header = header0
70
+ y.set_header header
71
+ }.each {|pairs|
72
+ h = {}
73
+ pairs.each {|f, v|
74
+ h[f] = v
72
75
  }
76
+ found = pred.call(h)
77
+ found = opt_v ^ !!(found)
78
+ if found
79
+ y.yield pairs
80
+ end
73
81
  }
74
82
  }
83
+ with_output {|out|
84
+ er.write_to_csv(out, !Tb::Cmd.opt_N)
85
+ }
75
86
  end
76
87
 
data/lib/tb/cmd_group.rb CHANGED
@@ -1,26 +1,30 @@
1
- # Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
1
+ # Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
2
2
  #
3
3
  # Redistribution and use in source and binary forms, with or without
4
- # modification, are permitted provided that the following conditions are met:
4
+ # modification, are permitted provided that the following conditions
5
+ # are met:
5
6
  #
6
- # 1. Redistributions of source code must retain the above copyright notice, this
7
- # list of conditions and the following disclaimer.
8
- # 2. Redistributions in binary form must reproduce the above copyright notice,
9
- # this list of conditions and the following disclaimer in the documentation
10
- # and/or other materials provided with the distribution.
11
- # 3. The name of the author may not be used to endorse or promote products
12
- # derived from this software without specific prior written permission.
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above
10
+ # copyright notice, this list of conditions and the following
11
+ # disclaimer in the documentation and/or other materials provided
12
+ # with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote
14
+ # products derived from this software without specific prior
15
+ # written permission.
13
16
  #
14
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
- # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
- # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
- # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
- # OF SUCH DAMAGE.
17
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18
+ # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23
+ # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
28
 
25
29
  Tb::Cmd.subcommands << 'group'
26
30
 
@@ -28,7 +32,8 @@ Tb::Cmd.default_option[:opt_group_fields] = []
28
32
 
29
33
  def (Tb::Cmd).op_group
30
34
  op = OptionParser.new
31
- op.banner = 'Usage: tb group [OPTS] KEY-FIELD1,... [TABLE ...]'
35
+ op.banner = "Usage: tb group [OPTS] KEY-FIELD1,... [TABLE ...]\n" +
36
+ "Group and aggregate rows."
32
37
  define_common_option(op, "hNo", "--no-pager")
33
38
  op.def_option('-a AGGREGATION-SPEC[,NEW-FIELD]',
34
39
  '--aggregate AGGREGATION-SPEC[,NEW-FIELD]') {|arg| Tb::Cmd.opt_group_fields << arg }
@@ -55,28 +60,47 @@ def (Tb::Cmd).main_group(argv)
55
60
  ]
56
61
  }
57
62
  argv = ['-'] if argv.empty?
58
- h = {}
59
- Tb::CatReader.open(argv, Tb::Cmd.opt_N) {|tblreader|
60
- kis = kfs.map {|f| tblreader.index_from_field(f) }
61
- result_fields = kfs + opt_group_fields.map {|nf, maker| nf }
62
- tblreader.each {|ary|
63
- kvs = ary.values_at(*kis)
64
- if !h.include?(kvs)
65
- h[kvs] = opt_group_fields.map {|nf, maker| ag = maker.call(tblreader.header); ag.update(ary); ag }
66
- else
67
- h[kvs].each {|ag|
68
- ag.update(ary)
69
- }
70
- end
63
+ creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N)
64
+ result = Tb::Enumerator.new {|y|
65
+ er = creader.extsort_by {|pairs|
66
+ kfs.map {|f| smart_cmp_value(pairs[f]) }
71
67
  }
72
- result = Tb.new(result_fields)
73
- h.keys.sort_by {|k| k.map {|v| smart_cmp_value(v) } }.each {|k|
74
- a = h[k]
75
- result.insert_values result_fields, k + a.map {|ag| ag.finish }
68
+ header = nil
69
+ row = nil
70
+ agg = nil
71
+ er2 = er.with_header {|header0|
72
+ header = header0
73
+ y.set_header(kfs + opt_group_fields.map {|f, maker| f })
76
74
  }
77
- with_output {|out|
78
- tbl_generate_csv(result, out)
75
+ boudary_p = lambda {|pairs1, pairs2|
76
+ kfs.any? {|f| pairs1[f] != pairs2[f] }
79
77
  }
78
+ before = lambda {|first_pairs|
79
+ row = {}
80
+ kfs.each {|f|
81
+ row[f] = first_pairs[f]
82
+ }
83
+ agg = {}
84
+ opt_group_fields.each {|f, maker|
85
+ agg[f] = maker.call(header)
86
+ }
87
+ }
88
+ body = lambda {|pairs|
89
+ ary = header.map {|f| pairs[f] }
90
+ opt_group_fields.each {|f, maker|
91
+ agg[f].update(ary)
92
+ }
93
+ }
94
+ after = lambda {|last_pairs|
95
+ opt_group_fields.each {|f, maker|
96
+ row[f] = agg[f].finish
97
+ }
98
+ y.yield row
99
+ }
100
+ er2.each_group_element(boudary_p, before, body, after)
101
+ }
102
+ with_output {|out|
103
+ result.write_to_csv(out, !Tb::Cmd.opt_N)
80
104
  }
81
105
  end
82
106
 
data/lib/tb/cmd_gsub.rb CHANGED
@@ -1,26 +1,30 @@
1
- # Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
1
+ # Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
2
2
  #
3
3
  # Redistribution and use in source and binary forms, with or without
4
- # modification, are permitted provided that the following conditions are met:
4
+ # modification, are permitted provided that the following conditions
5
+ # are met:
5
6
  #
6
- # 1. Redistributions of source code must retain the above copyright notice, this
7
- # list of conditions and the following disclaimer.
8
- # 2. Redistributions in binary form must reproduce the above copyright notice,
9
- # this list of conditions and the following disclaimer in the documentation
10
- # and/or other materials provided with the distribution.
11
- # 3. The name of the author may not be used to endorse or promote products
12
- # derived from this software without specific prior written permission.
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above
10
+ # copyright notice, this list of conditions and the following
11
+ # disclaimer in the documentation and/or other materials provided
12
+ # with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote
14
+ # products derived from this software without specific prior
15
+ # written permission.
13
16
  #
14
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
- # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
- # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
- # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
- # OF SUCH DAMAGE.
17
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18
+ # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23
+ # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
28
 
25
29
  Tb::Cmd.subcommands << 'gsub'
26
30
 
@@ -29,7 +33,8 @@ Tb::Cmd.default_option[:opt_gsub_f] = nil
29
33
 
30
34
  def (Tb::Cmd).op_gsub
31
35
  op = OptionParser.new
32
- op.banner = 'Usage: tb gsub [OPTS] REGEXP STRING [TABLE ...]'
36
+ op.banner = "Usage: tb gsub [OPTS] REGEXP STRING [TABLE ...]\n" +
37
+ "Substitute cells."
33
38
  define_common_option(op, "hNo", "--no-pager")
34
39
  op.def_option('-f FIELD', 'target field') {|field| Tb::Cmd.opt_gsub_f = field }
35
40
  op.def_option('-e REGEXP', 'specify regexp, possibly begins with a hyphen') {|pattern| Tb::Cmd.opt_gsub_e = pattern }
@@ -48,30 +53,35 @@ def (Tb::Cmd).main_gsub(argv)
48
53
  err('no substitution given.') if argv.empty?
49
54
  repl = argv.shift
50
55
  argv = ['-'] if argv.empty?
51
- Tb::CatReader.open(argv, Tb::Cmd.opt_N) {|tblreader|
52
- with_table_stream_output {|gen|
53
- gen.output_header tblreader.header
54
- tblreader.each {|ary|
55
- if Tb::Cmd.opt_gsub_f
56
- ary2 = []
57
- ary.each_with_index {|str, i|
58
- f = tblreader.field_from_index_ex(i)
59
- if f == Tb::Cmd.opt_gsub_f
60
- str ||= ''
61
- ary2 << str.gsub(re, repl)
62
- else
63
- ary2 << str
64
- end
65
- }
66
- else
67
- ary2 = ary.map {|s|
68
- s ||= ''
69
- s.gsub(re, repl)
70
- }
71
- end
72
- gen << ary2
73
- }
56
+ creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N)
57
+ er = Tb::Enumerator.new {|y|
58
+ creader.with_cumulative_header {|header0|
59
+ if header0
60
+ y.set_header header0
61
+ end
62
+ }.each {|pairs, header|
63
+ fs = header.dup
64
+ fs.pop while !fs.empty? && !pairs.has_key?(fs.last)
65
+ if Tb::Cmd.opt_gsub_f
66
+ pairs2 = pairs.map {|f, v|
67
+ if f == Tb::Cmd.opt_gsub_f
68
+ v ||= ''
69
+ [f, v.gsub(re, repl)]
70
+ else
71
+ [f, v]
72
+ end
73
+ }
74
+ else
75
+ pairs2 = pairs.map {|f, v|
76
+ v ||= ''
77
+ [f, v.gsub(re, repl)]
78
+ }
79
+ end
80
+ y.yield Tb::Pairs.new(pairs2)
74
81
  }
75
82
  }
83
+ with_output {|out|
84
+ er.write_to_csv(out, !Tb::Cmd.opt_N)
85
+ }
76
86
  end
77
87
 
data/lib/tb/cmd_help.rb CHANGED
@@ -1,44 +1,68 @@
1
- # Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
1
+ # Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
2
2
  #
3
3
  # Redistribution and use in source and binary forms, with or without
4
- # modification, are permitted provided that the following conditions are met:
4
+ # modification, are permitted provided that the following conditions
5
+ # are met:
5
6
  #
6
- # 1. Redistributions of source code must retain the above copyright notice, this
7
- # list of conditions and the following disclaimer.
8
- # 2. Redistributions in binary form must reproduce the above copyright notice,
9
- # this list of conditions and the following disclaimer in the documentation
10
- # and/or other materials provided with the distribution.
11
- # 3. The name of the author may not be used to endorse or promote products
12
- # derived from this software without specific prior written permission.
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ # 2. Redistributions in binary form must reproduce the above
10
+ # copyright notice, this list of conditions and the following
11
+ # disclaimer in the documentation and/or other materials provided
12
+ # with the distribution.
13
+ # 3. The name of the author may not be used to endorse or promote
14
+ # products derived from this software without specific prior
15
+ # written permission.
13
16
  #
14
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
- # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
- # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
- # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
- # OF SUCH DAMAGE.
17
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18
+ # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23
+ # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
28
 
25
29
  Tb::Cmd.subcommands << 'help'
26
30
 
31
+ Tb::Cmd.default_option[:opt_help_s] = nil
32
+
27
33
  def (Tb::Cmd).usage_list_subcommands
28
34
  with_output {|f|
29
35
  f.print <<'End'
30
36
  Usage:
31
37
  End
32
38
  Tb::Cmd.subcommands.each {|subcommand|
33
- f.puts " " + self.subcommand_send("op", subcommand).banner.sub(/\AUsage: /, '')
39
+ banner = self.subcommand_send("op", subcommand).banner
40
+ usage = banner[/^Usage: (.*)/, 1]
41
+ f.puts " " + usage
42
+ }
43
+ }
44
+ end
45
+
46
+ def (Tb::Cmd).list_summary_of_subcommands
47
+ with_output {|f|
48
+ f.print <<'End'
49
+ End
50
+ subcommand_maxlen = Tb::Cmd.subcommands.map {|subcommand| subcommand.length }.max
51
+ fmt = "%-#{subcommand_maxlen}s : %s"
52
+ Tb::Cmd.subcommands.each {|subcommand|
53
+ banner = self.subcommand_send("op", subcommand).banner
54
+ summary = banner[/^Usage: (.*)\n(.*)/, 2]
55
+ f.puts(fmt % [subcommand, summary])
34
56
  }
35
57
  }
36
58
  end
37
59
 
38
60
  def (Tb::Cmd).op_help
39
61
  op = OptionParser.new
40
- op.banner = 'Usage: tb help [OPTS] [SUBCOMMAND]'
62
+ op.banner = "Usage: tb help [OPTS] [SUBCOMMAND]\n" +
63
+ "Show help message of tb command."
41
64
  define_common_option(op, "hvo", "--no-pager")
65
+ op.def_option('-s', 'show summary of subcommands') { Tb::Cmd.opt_help_s = true }
42
66
  op
43
67
  end
44
68
 
@@ -49,13 +73,13 @@ Example:
49
73
  tb help : list subcommands
50
74
 
51
75
  tb cat -h : succinct help of "cat" subcommand
52
- tb cat -hh : verbose help of "cat" subcommand
53
76
  tb help cat : succinct help of "cat" subcommand
77
+ tb cat -hh : verbose help of "cat" subcommand
54
78
  tb help -h cat : verbose help of "cat" subcommand
55
79
 
56
80
  tb help -h : succinct help of "help" subcommand
57
- tb help -hh : verbose help of "help" subcommand
58
81
  tb help help : succinct help of "help" subcommand
82
+ tb help -hh : verbose help of "help" subcommand
59
83
  tb help -h help : verbose help of "help" subcommand
60
84
  End
61
85
 
@@ -83,7 +107,10 @@ end
83
107
 
84
108
  def (Tb::Cmd).main_help(argv)
85
109
  op_help.parse!(argv)
86
- if argv.empty?
110
+ if Tb::Cmd.opt_help_s
111
+ list_summary_of_subcommands
112
+ exit
113
+ elsif argv.empty?
87
114
  if Tb::Cmd.opt_help == 0
88
115
  usage_list_subcommands
89
116
  return true