tb 0.2 → 0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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