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/catreader.rb CHANGED
@@ -1,131 +1,48 @@
1
1
  # lib/tb/catreader.rb - Tb::CatReader class
2
2
  #
3
- # Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
3
+ # Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
4
4
  #
5
5
  # Redistribution and use in source and binary forms, with or without
6
- # modification, are permitted provided that the following conditions are met:
6
+ # modification, are permitted provided that the following conditions
7
+ # are met:
7
8
  #
8
- # 1. Redistributions of source code must retain the above copyright notice, this
9
- # list of conditions and the following disclaimer.
10
- # 2. Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- # 3. The name of the author may not be used to endorse or promote products
14
- # derived from this software without specific prior written permission.
9
+ # 1. Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ # 2. Redistributions in binary form must reproduce the above
12
+ # copyright notice, this list of conditions and the following
13
+ # disclaimer in the documentation and/or other materials provided
14
+ # with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote
16
+ # products derived from this software without specific prior
17
+ # written permission.
15
18
  #
16
- # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17
- # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
- # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21
- # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24
- # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25
- # OF SUCH DAMAGE.
26
-
27
- class Tb::CatReader
28
- def self.open(filenames, numeric=false)
19
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20
+ # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21
+ # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25
+ # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29
+ # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ module Tb::CatReader
32
+ def self.open(filenames, numeric=false, with_filename=false)
29
33
  readers = []
30
34
  filenames.each {|f|
31
- readers << Tb::Reader.open(f, numeric ? {:numeric=>true} : {})
35
+ r = Tb.open_reader(f, numeric ? {:numeric=>true} : {})
36
+ if with_filename
37
+ r = r.newfield("filename") { f }
38
+ end
39
+ readers << r
32
40
  }
33
- r = Tb::CatReader.new(readers, readers, numeric)
41
+ r = readers.first.cat(*readers[1..-1])
34
42
  if block_given?
35
- begin
36
- yield r
37
- ensure
38
- r.close
39
- end
43
+ yield r
40
44
  else
41
45
  r
42
46
  end
43
47
  end
44
-
45
- def initialize(readers, also_close, numeric)
46
- @readers = readers.dup
47
- @also_close = also_close
48
- @numeric = numeric
49
- @fieldset = nil
50
- end
51
-
52
- def header
53
- return @fieldset.header if @fieldset
54
- if @numeric
55
- @fieldset = Tb::FieldSet.new
56
- else
57
- h = {}
58
- @readers.each {|r|
59
- r.header.each {|f|
60
- if !h[f]
61
- h[f] = h.size
62
- end
63
- }
64
- }
65
- @fieldset = Tb::FieldSet.new(*h.keys.sort_by {|f| h[f] })
66
- end
67
- return @fieldset.header
68
- end
69
-
70
- def index_from_field_ex(f)
71
- self.header
72
- @fieldset.index_from_field_ex(f)
73
- end
74
-
75
- def index_from_field(f)
76
- self.header
77
- @fieldset.index_from_field(f)
78
- end
79
-
80
- def field_from_index_ex(i)
81
- self.header
82
- @fieldset.field_from_index_ex(i)
83
- end
84
-
85
- def field_from_index(i)
86
- self.header
87
- @fieldset.field_from_index(i)
88
- end
89
-
90
- def shift
91
- self.header
92
- while !@readers.empty?
93
- r = @readers.first
94
- ary = r.shift
95
- if ary
96
- h = r.header
97
- ary2 = []
98
- ary.each_with_index {|v,i|
99
- f = h[i]
100
- i2 = @fieldset.index_from_field_ex(f)
101
- ary2[i2] = v
102
- }
103
- return ary2
104
- else
105
- @readers.shift
106
- end
107
- end
108
- nil
109
- end
110
-
111
- def each
112
- while ary = self.shift
113
- yield ary
114
- end
115
- nil
116
- end
117
-
118
- def read_all
119
- result = []
120
- while ary = self.shift
121
- result << ary
122
- end
123
- result
124
- end
125
-
126
- def close
127
- if @also_close
128
- @also_close.each {|x| x.close }
129
- end
130
- end
131
48
  end
data/lib/tb/cmd_cat.rb CHANGED
@@ -1,33 +1,41 @@
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 << 'cat'
26
30
 
31
+ Tb::Cmd.default_option[:opt_cat_with_filename] = nil
32
+
27
33
  def (Tb::Cmd).op_cat
28
34
  op = OptionParser.new
29
- op.banner = 'Usage: tb cat [OPTS] [TABLE ...]'
35
+ op.banner = "Usage: tb cat [OPTS] [TABLE ...]\n" +
36
+ "Concatenate tables vertically."
30
37
  define_common_option(op, "hNo", "--no-pager")
38
+ op.def_option('-H', '--with-filename', 'add filename column') { Tb::Cmd.opt_cat_with_filename = true }
31
39
  op
32
40
  end
33
41
 
@@ -54,12 +62,8 @@ def (Tb::Cmd).main_cat(argv)
54
62
  op_cat.parse!(argv)
55
63
  exit_if_help('cat')
56
64
  argv = ['-'] if argv.empty?
57
- creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N)
58
- header = creader.header
59
- with_table_stream_output {|gen|
60
- gen << header if !Tb::Cmd.opt_N
61
- creader.each {|ary|
62
- gen << ary
63
- }
65
+ creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N, Tb::Cmd.opt_cat_with_filename)
66
+ with_output {|out|
67
+ creader.write_to_csv(out, !Tb::Cmd.opt_N)
64
68
  }
65
69
  end
@@ -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 << 'consecutive'
26
30
 
@@ -28,7 +32,8 @@ Tb::Cmd.default_option[:opt_consecutive_n] = 2
28
32
 
29
33
  def (Tb::Cmd).op_consecutive
30
34
  op = OptionParser.new
31
- op.banner = 'Usage: tb consecutive [OPTS] [TABLE ...]'
35
+ op.banner = "Usage: tb consecutive [OPTS] [TABLE ...]\n" +
36
+ "Concatenate consecutive rows."
32
37
  define_common_option(op, "hNo", "--no-pager")
33
38
  op.def_option('-n NUM', 'gather NUM records. (default: 2)') {|n| Tb::Cmd.opt_consecutive_n = n.to_i }
34
39
  op
@@ -53,27 +58,32 @@ def (Tb::Cmd).main_consecutive(argv)
53
58
  exit_if_help('consecutive')
54
59
  argv = ['-'] if argv.empty?
55
60
  creader = Tb::CatReader.open(argv, Tb::Cmd.opt_N)
56
- consecutive_header = []
57
- creader.header.each {|f|
58
- Tb::Cmd.opt_consecutive_n.times {|i|
59
- consecutive_header << "#{f}_#{i+1}"
60
- }
61
- }
62
- with_table_stream_output {|gen|
63
- gen.output_header consecutive_header
61
+ er = Tb::Enumerator.new {|y|
64
62
  buf = []
65
- creader.each {|ary|
66
- buf << ary
63
+ empty = true
64
+ creader.with_cumulative_header {|header0|
65
+ if header0
66
+ y.set_header header0.map {|f| (1..Tb::Cmd.opt_consecutive_n).map {|i| "#{f}_#{i}" } }.flatten(1)
67
+ end
68
+ }.each {|pairs, header|
69
+ buf << pairs
67
70
  if buf.length == Tb::Cmd.opt_consecutive_n
68
- ary2 = []
69
- buf.each_with_index {|a, i|
70
- a.each_with_index {|e, j|
71
- ary2[j*Tb::Cmd.opt_consecutive_n + i] = e
71
+ pairs2 = []
72
+ header.each {|f|
73
+ Tb::Cmd.opt_consecutive_n.times {|i|
74
+ ps = buf[i]
75
+ next if !ps.has_key?(f)
76
+ v = ps[f]
77
+ pairs2 << ["#{f}_#{i+1}", v]
72
78
  }
73
79
  }
74
- gen << ary2
80
+ empty = false
81
+ y.yield Tb::Pairs.new(pairs2)
75
82
  buf.shift
76
83
  end
77
84
  }
78
85
  }
86
+ with_output {|out|
87
+ er.write_to_csv(out, !Tb::Cmd.opt_N)
88
+ }
79
89
  end
data/lib/tb/cmd_crop.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 << 'crop'
26
30
 
@@ -28,7 +32,8 @@ Tb::Cmd.default_option[:opt_crop_range] = nil
28
32
 
29
33
  def (Tb::Cmd).op_crop
30
34
  op = OptionParser.new
31
- op.banner = 'Usage: tb crop [OPTS] [TABLE ...]'
35
+ op.banner = "Usage: tb crop [OPTS] [TABLE ...]\n" +
36
+ "Extract rectangle in a table."
32
37
  define_common_option(op, "ho", "--no-pager")
33
38
  op.def_option('-r RANGE', 'range. i.e. "2,1-4,3", "B1:D3"') {|arg| Tb::Cmd.opt_crop_range = arg }
34
39
  op
@@ -62,43 +67,72 @@ def (Tb::Cmd).main_crop(argv)
62
67
  end
63
68
  end
64
69
  if stream
65
- with_table_stream_output {|gen|
66
- Tb::CatReader.open(argv, true) {|tblreader|
67
- rownum = 1
68
- tblreader.each {|ary|
69
- if range_row2 < rownum
70
- break
71
- end
72
- if range_row1 <= rownum
73
- if range_col2 < ary.length
74
- ary[range_col2..-1] = []
75
- end
76
- if 1 < range_col1
77
- ary[0...(range_col1-1)] = []
78
- end
79
- gen << ary
80
- end
81
- rownum += 1
82
- }
70
+ creader = Tb::CatReader.open(argv, true)
71
+ er = Tb::Enumerator.new {|y|
72
+ rownum = 1
73
+ creader.each {|pairs|
74
+ if range_row2 < rownum
75
+ break
76
+ end
77
+ if range_row1 <= rownum
78
+ pairs2 = pairs.reject {|f, v|
79
+ f = f.to_i
80
+ f < range_col1 || range_col2 < f
81
+ }
82
+ y.yield pairs2
83
+ end
84
+ rownum += 1
83
85
  }
84
86
  }
87
+ with_output {|out|
88
+ er.write_to_csv(out, false)
89
+ }
85
90
  else
86
- arys = []
87
- Tb::CatReader.open(argv, true) {|tblreader|
88
- tblreader.each {|a|
89
- a.pop while !a.empty? && (a.last.nil? || a.last == '')
90
- arys << a
91
+ creader = Tb::CatReader.open(argv, true)
92
+ last_nonempty_row = nil
93
+ lmargin_min = nil
94
+ ter = Enumerator.new {|y|
95
+ numrows = 0
96
+ creader.each {|pairs|
97
+ ary = []
98
+ pairs.each {|f, v|
99
+ ary[f.to_i-1] = v
100
+ }
101
+ while !ary.empty? && (ary.last.nil? || ary.last == '')
102
+ ary.pop
103
+ end
104
+ if numrows == 0 && ary.empty?
105
+ next
106
+ end
107
+ if !ary.empty?
108
+ lmargin = 0
109
+ while lmargin < ary.length
110
+ if !ary[lmargin].nil? && ary[lmargin] != ''
111
+ break
112
+ end
113
+ lmargin += 1
114
+ end
115
+ if lmargin_min.nil? || lmargin < lmargin_min
116
+ lmargin_min = lmargin
117
+ end
118
+ end
119
+ last_nonempty_row = numrows if !ary.empty?
120
+ y.yield ary
121
+ numrows += 1
122
+ }
123
+ }.to_fileenumerator
124
+ er = Tb::Enumerator.new {|y|
125
+ ter.each_with_index {|ary, rownum|
126
+ if last_nonempty_row < rownum
127
+ break
128
+ end
129
+ ary.slice!(0, lmargin_min)
130
+ pairs = Tb::Pairs.new(ary.map.with_index {|v, i| ["#{i+1}", v]})
131
+ y.yield pairs
91
132
  }
92
133
  }
93
- arys.pop while !arys.empty? && arys.last.all? {|v| v.nil? || v == '' }
94
- arys.shift while !arys.empty? && arys.first.all? {|v| v.nil? || v == '' }
95
- if !arys.empty?
96
- while arys.all? {|a| a.empty? || (a.first.nil? || a.first == '') }
97
- arys.each {|a| a.shift }
98
- end
99
- end
100
- with_table_stream_output {|gen|
101
- arys.each {|a| gen << a }
134
+ with_output {|out|
135
+ er.write_to_csv(out, false)
102
136
  }
103
137
  end
104
138
  end