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/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