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/json.rb ADDED
@@ -0,0 +1,50 @@
1
+ # Copyright (C) 2012 Tanaka Akira <akr@fsij.org>
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions
5
+ # are met:
6
+ #
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.
16
+ #
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.
28
+
29
+ require 'json'
30
+
31
+ class Tb
32
+ class JSONReader
33
+ include Tb::Enum
34
+
35
+ def initialize(string)
36
+ @ary = JSON.parse(string)
37
+ end
38
+
39
+ def header_and_each(header_proc)
40
+ header_proc.call(nil) if header_proc
41
+ @ary.each {|obj|
42
+ yield obj
43
+ }
44
+ end
45
+
46
+ def each(&block)
47
+ header_and_each(nil, &block)
48
+ end
49
+ end
50
+ end
data/lib/tb/pager.rb CHANGED
@@ -14,11 +14,11 @@ class Tb::Pager
14
14
  end
15
15
 
16
16
  def initialize
17
- if STDOUT.tty?
17
+ if $stdout.tty?
18
18
  @io = nil
19
19
  @buf = ''
20
20
  else
21
- @io = STDOUT
21
+ @io = $stdout
22
22
  @buf = nil
23
23
  end
24
24
  end
@@ -81,8 +81,8 @@ class Tb::Pager
81
81
  DEFAULT_COLUMNS = 80
82
82
 
83
83
  def winsize
84
- if STDOUT.respond_to? :winsize
85
- lines, columns = STDOUT.winsize
84
+ if $stdout.respond_to? :winsize
85
+ lines, columns = $stdout.winsize
86
86
  return [lines, columns] if lines != 0 && columns != 0
87
87
  end
88
88
  [DEFAULT_LINES, DEFAULT_COLUMNS]
@@ -122,10 +122,10 @@ class Tb::Pager
122
122
 
123
123
  def close
124
124
  if !@io
125
- STDOUT.print @buf
125
+ $stdout.print @buf
126
126
  else
127
127
  # don't need to ouput @buf because @buf is nil.
128
- @io.close if @io != STDOUT
128
+ @io.close if @io != $stdout
129
129
  end
130
130
  nil
131
131
  end
data/lib/tb/pairs.rb ADDED
@@ -0,0 +1,227 @@
1
+ # Copyright (C) 2012 Tanaka Akira <akr@fsij.org>
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions
5
+ # are met:
6
+ #
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.
16
+ #
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.
28
+
29
+ require 'weakref'
30
+
31
+ class Tb::Pairs
32
+ def self.get_key2index(keys)
33
+ wm = (Thread.current[:tb_pairs_frozen_info] ||= {})
34
+ w = wm[keys]
35
+ if w
36
+ begin
37
+ return w.__getobj__
38
+ rescue WeakRef::RefError
39
+ end
40
+ end
41
+ keys = keys.dup.freeze
42
+ k2i = {}
43
+ keys.each_with_index {|k, i|
44
+ k2i[k] = i
45
+ }
46
+ k2i.freeze
47
+ info = [keys, k2i]
48
+ w = WeakRef.new(info)
49
+ wm[keys.dup] = w
50
+ info
51
+ end
52
+
53
+ include Enumerable
54
+
55
+ def initialize(pairs)
56
+ keys = []
57
+ vals = []
58
+ pairs.each {|k, v|
59
+ keys << k
60
+ vals << v
61
+ }
62
+ keys, k2i = Tb::Pairs.get_key2index(keys)
63
+ @keys = keys
64
+ @k2i = k2i
65
+ @vals = vals
66
+ end
67
+
68
+ def pretty_print(q) # :nodoc:
69
+ q.object_group(self) {
70
+ fs = @keys
71
+ unless fs.empty?
72
+ q.text ':'
73
+ q.breakable
74
+ end
75
+ q.seplist(fs, nil, :each) {|f|
76
+ v = self[f]
77
+ q.group {
78
+ q.pp f
79
+ q.text '=>'
80
+ q.group(1) {
81
+ q.breakable ''
82
+ q.pp v
83
+ }
84
+ }
85
+ }
86
+ }
87
+ end
88
+ alias inspect pretty_print_inspect # :nodoc:
89
+
90
+ def [](key)
91
+ i = @k2i.fetch(key) {
92
+ return nil
93
+ }
94
+ @vals[i]
95
+ end
96
+
97
+ def each
98
+ @keys.each_index {|i|
99
+ yield [@keys[i], @vals[i]]
100
+ }
101
+ end
102
+
103
+ def each_key(&b)
104
+ @keys.each(&b)
105
+ end
106
+
107
+ def each_value(&b)
108
+ @vals.each(&b)
109
+ end
110
+
111
+ def to_h
112
+ h = {}
113
+ @keys.each_with_index {|k, i|
114
+ v = @vals[i]
115
+ h[k] = v
116
+ }
117
+ h
118
+ end
119
+
120
+ def empty?
121
+ @keys.empty?
122
+ end
123
+
124
+ if defined?(::KeyError)
125
+ KeyError = ::KeyError
126
+ else
127
+ KeyError = IndexError
128
+ end
129
+
130
+ def fetch(key, *rest)
131
+ if 1 < rest.length
132
+ raise ArgumentError, "wrong number of arguments (#{1+rest.length} for 1..2)"
133
+ elsif block_given?
134
+ i = @k2i.fetch(key) {
135
+ return yield(key)
136
+ }
137
+ @vals[i]
138
+ elsif !rest.empty?
139
+ i = @k2i.fetch(key) {
140
+ return rest[0]
141
+ }
142
+ @vals[i]
143
+ else
144
+ i = @k2i.fetch(key)
145
+ @vals[i]
146
+ end
147
+ end
148
+
149
+ def has_key?(key)
150
+ @k2i.has_key?(key)
151
+ end
152
+ alias include? has_key?
153
+ alias key? has_key?
154
+ alias member? has_key?
155
+
156
+ def has_value?(value)
157
+ i = index(value)
158
+ if i
159
+ true
160
+ else
161
+ false
162
+ end
163
+ end
164
+ alias value? has_value?
165
+
166
+ def index(value)
167
+ @vals.each_with_index {|v, i|
168
+ if v == value
169
+ return @keys[i]
170
+ end
171
+ }
172
+ nil
173
+ end
174
+ alias key index
175
+
176
+ def invert
177
+ Tb::Pairs.new(self.map {|k, v| [v, k] })
178
+ end
179
+
180
+ def keys
181
+ @keys.dup
182
+ end
183
+
184
+ def length
185
+ @keys.length
186
+ end
187
+ alias size length
188
+
189
+ def merge(other)
190
+ pairs = []
191
+ self.each {|k, v|
192
+ if other.has_key? k
193
+ if block_given?
194
+ v = yield(k, v, other[k])
195
+ else
196
+ v = other[k]
197
+ end
198
+ end
199
+ pairs << [k, v]
200
+ }
201
+ other.each {|k, v|
202
+ next if self.has_key? k
203
+ pairs << [k, v]
204
+ }
205
+ Tb::Pairs.new(pairs)
206
+ end
207
+
208
+ def reject
209
+ pairs = []
210
+ self.each {|kv|
211
+ unless yield kv
212
+ pairs << kv
213
+ end
214
+ }
215
+ Tb::Pairs.new(pairs)
216
+ end
217
+
218
+ def values
219
+ @vals.dup
220
+ end
221
+
222
+ def values_at(*keys)
223
+ keys.map {|k|
224
+ self[k]
225
+ }
226
+ end
227
+ end
data/lib/tb/pnm.rb CHANGED
@@ -1,28 +1,32 @@
1
1
  # lib/tb/pnm.rb - tools for (very small) PNM images.
2
2
  #
3
- # Copyright (C) 2010-2011 Tanaka Akira <akr@fsij.org>
3
+ # Copyright (C) 2010-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.
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.
26
30
 
27
31
  class Tb
28
32
  # :call-seq:
@@ -175,9 +179,6 @@ class Tb
175
179
  each {|ary| result << ary }
176
180
  result
177
181
  end
178
-
179
- def close
180
- end
181
182
  end
182
183
 
183
184
  # :call-seq:
data/lib/tb/reader.rb CHANGED
@@ -1,43 +1,48 @@
1
1
  # lib/tb/reader.rb - Tb::Reader 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.
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.
26
30
 
27
31
  class Tb::Reader
28
- def initialize(rawreader, opts={})
32
+ include Tb::Enum
33
+
34
+ def initialize(opts={}, &rawreader_open)
29
35
  @opt_n = opts[:numeric]
30
- @opt_close = opts[:close]
31
- @reader = rawreader
36
+ @reader_open = rawreader_open
32
37
  @fieldset = nil
33
38
  end
34
39
 
35
- def header
40
+ def internal_header(rawreader)
36
41
  return @fieldset.header if @fieldset
37
42
  if @opt_n
38
43
  @fieldset = Tb::FieldSet.new
39
44
  else
40
- while ary = @reader.shift
45
+ while ary = rawreader.shift
41
46
  if ary.all? {|elt| elt.nil? || elt == '' }
42
47
  next
43
48
  else
@@ -51,53 +56,51 @@ class Tb::Reader
51
56
  end
52
57
 
53
58
  def index_from_field_ex(f)
54
- self.header
59
+ raise TypeError if !@fieldset
55
60
  @fieldset.index_from_field_ex(f)
56
61
  end
57
62
 
58
63
  def index_from_field(f)
59
- self.header
64
+ raise TypeError if !@fieldset
60
65
  @fieldset.index_from_field(f)
61
66
  end
62
67
 
63
68
  def field_from_index_ex(i)
69
+ raise TypeError if !@fieldset
64
70
  raise ArgumentError, "negative index: #{i}" if i < 0
65
- self.header
66
71
  @fieldset.field_from_index_ex(i)
67
72
  end
68
73
 
69
74
  def field_from_index(i)
75
+ raise TypeError if !@fieldset
70
76
  raise ArgumentError, "negative index: #{i}" if i < 0
71
- self.header
72
77
  @fieldset.field_from_index(i)
73
78
  end
74
79
 
75
- def shift
76
- header
77
- ary = @reader.shift
80
+ def internal_shift(rawreader)
81
+ raise TypeError if !@fieldset
82
+ ary = rawreader.shift
78
83
  field_from_index_ex(ary.length-1) if ary && !ary.empty?
79
84
  ary
80
85
  end
81
86
 
82
- def each
83
- while ary = self.shift
84
- yield ary
85
- end
86
- nil
87
- end
88
-
89
- def read_all
90
- result = []
91
- while ary = self.shift
92
- result << ary
93
- end
94
- result
87
+ def header_and_each(header_proc)
88
+ body = lambda {|rawreader|
89
+ h = self.internal_header(rawreader)
90
+ header_proc.call(h) if header_proc
91
+ while ary = self.internal_shift(rawreader)
92
+ pairs = []
93
+ ary.each_with_index {|v, i|
94
+ f = field_from_index_ex(i)
95
+ pairs << [f, v]
96
+ }
97
+ yield Tb::Pairs.new(pairs)
98
+ end
99
+ }
100
+ @reader_open.call(body)
95
101
  end
96
102
 
97
- def close
98
- @reader.close
99
- if @opt_close
100
- @opt_close.close
101
- end
103
+ def each(&block)
104
+ header_and_each(nil, &block)
102
105
  end
103
106
  end