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