tb 0.9 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README +13 -11
  3. data/lib/tb.rb +14 -6
  4. data/lib/tb/catreader.rb +2 -2
  5. data/lib/tb/cmd_consecutive.rb +6 -2
  6. data/lib/tb/cmd_crop.rb +22 -3
  7. data/lib/tb/cmd_cross.rb +24 -0
  8. data/lib/tb/cmd_cut.rb +20 -10
  9. data/lib/tb/cmd_git.rb +20 -7
  10. data/lib/tb/cmd_group.rb +32 -0
  11. data/lib/tb/cmd_gsub.rb +21 -0
  12. data/lib/tb/cmd_join.rb +28 -0
  13. data/lib/tb/cmd_ls.rb +9 -0
  14. data/lib/tb/cmd_melt.rb +15 -0
  15. data/lib/tb/cmd_mheader.rb +15 -0
  16. data/lib/tb/cmd_nest.rb +27 -6
  17. data/lib/tb/cmd_newfield.rb +19 -2
  18. data/lib/tb/cmd_rename.rb +20 -0
  19. data/lib/tb/{cmd_grep.rb → cmd_search.rb} +37 -23
  20. data/lib/tb/cmd_shape.rb +69 -25
  21. data/lib/tb/cmd_sort.rb +20 -0
  22. data/lib/tb/cmd_tar.rb +38 -0
  23. data/lib/tb/cmd_to_json.rb +2 -2
  24. data/lib/tb/cmd_to_ltsv.rb +3 -3
  25. data/lib/tb/cmd_to_pnm.rb +3 -3
  26. data/lib/tb/cmd_to_tsv.rb +3 -3
  27. data/lib/tb/cmd_to_yaml.rb +3 -3
  28. data/lib/tb/cmd_unmelt.rb +15 -0
  29. data/lib/tb/cmd_unnest.rb +31 -7
  30. data/lib/tb/cmdmain.rb +2 -0
  31. data/lib/tb/cmdtop.rb +1 -1
  32. data/lib/tb/cmdutil.rb +9 -62
  33. data/lib/tb/csv.rb +21 -79
  34. data/lib/tb/enumerable.rb +42 -68
  35. data/lib/tb/enumerator.rb +15 -7
  36. data/lib/tb/{fieldset.rb → hashreader.rb} +37 -56
  37. data/lib/tb/hashwriter.rb +54 -0
  38. data/lib/tb/headerreader.rb +108 -0
  39. data/lib/tb/headerwriter.rb +116 -0
  40. data/lib/tb/json.rb +17 -15
  41. data/lib/tb/ltsv.rb +35 -96
  42. data/lib/tb/ndjson.rb +63 -0
  43. data/lib/tb/numericreader.rb +66 -0
  44. data/lib/tb/numericwriter.rb +61 -0
  45. data/lib/tb/pnm.rb +206 -200
  46. data/lib/tb/ropen.rb +54 -59
  47. data/lib/tb/tsv.rb +39 -71
  48. data/sample/excel2csv +24 -25
  49. data/sample/poi-xls2csv.rb +13 -14
  50. data/tb.gemspec +154 -0
  51. data/test/test_cmd_cat.rb +28 -6
  52. data/test/test_cmd_consecutive.rb +8 -3
  53. data/test/test_cmd_cut.rb +14 -4
  54. data/test/test_cmd_git_log.rb +50 -50
  55. data/test/test_cmd_grep.rb +6 -6
  56. data/test/test_cmd_gsub.rb +7 -2
  57. data/test/test_cmd_ls.rb +70 -62
  58. data/test/test_cmd_shape.rb +43 -6
  59. data/test/test_cmd_svn_log.rb +26 -27
  60. data/test/test_cmd_to_csv.rb +10 -5
  61. data/test/test_cmd_to_json.rb +16 -0
  62. data/test/test_cmd_to_ltsv.rb +2 -2
  63. data/test/test_cmd_to_pp.rb +7 -2
  64. data/test/test_csv.rb +74 -62
  65. data/test/test_ex_enumerable.rb +0 -1
  66. data/test/test_fileenumerator.rb +3 -3
  67. data/test/test_headercsv.rb +43 -0
  68. data/test/test_json.rb +2 -2
  69. data/test/test_ltsv.rb +22 -17
  70. data/test/test_ndjson.rb +62 -0
  71. data/test/test_numericcsv.rb +36 -0
  72. data/test/test_pnm.rb +69 -70
  73. data/test/test_reader.rb +27 -124
  74. data/test/test_tbenum.rb +18 -18
  75. data/test/test_tsv.rb +21 -32
  76. data/test/util_tbtest.rb +12 -0
  77. metadata +41 -19
  78. data/lib/tb/basic.rb +0 -1070
  79. data/lib/tb/reader.rb +0 -106
  80. data/lib/tb/record.rb +0 -158
  81. data/test/test_basic.rb +0 -403
  82. data/test/test_fieldset.rb +0 -42
  83. data/test/test_record.rb +0 -61
@@ -1,106 +0,0 @@
1
- # lib/tb/reader.rb - Tb::Reader class
2
- #
3
- # Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
4
- #
5
- # Redistribution and use in source and binary forms, with or without
6
- # modification, are permitted provided that the following conditions
7
- # are met:
8
- #
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.
18
- #
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
- class Tb::Reader
32
- include Tb::Enumerable
33
-
34
- def initialize(opts={}, &rawreader_open)
35
- @opt_n = opts[:numeric]
36
- @reader_open = rawreader_open
37
- @fieldset = nil
38
- end
39
-
40
- def internal_header(rawreader)
41
- return @fieldset.header if @fieldset
42
- if @opt_n
43
- @fieldset = Tb::FieldSet.new
44
- else
45
- while ary = rawreader.shift
46
- if ary.all? {|elt| elt.nil? || elt == '' }
47
- next
48
- else
49
- @fieldset = Tb::FieldSet.new(*ary)
50
- return @fieldset.header
51
- end
52
- end
53
- @fieldset = Tb::FieldSet.new
54
- end
55
- return @fieldset.header
56
- end
57
-
58
- def index_from_field_ex(f)
59
- raise TypeError if !@fieldset
60
- @fieldset.index_from_field_ex(f)
61
- end
62
-
63
- def index_from_field(f)
64
- raise TypeError if !@fieldset
65
- @fieldset.index_from_field(f)
66
- end
67
-
68
- def field_from_index_ex(i)
69
- raise TypeError if !@fieldset
70
- raise ArgumentError, "negative index: #{i}" if i < 0
71
- @fieldset.field_from_index_ex(i)
72
- end
73
-
74
- def field_from_index(i)
75
- raise TypeError if !@fieldset
76
- raise ArgumentError, "negative index: #{i}" if i < 0
77
- @fieldset.field_from_index(i)
78
- end
79
-
80
- def internal_shift(rawreader)
81
- raise TypeError if !@fieldset
82
- ary = rawreader.shift
83
- field_from_index_ex(ary.length-1) if ary && !ary.empty?
84
- ary
85
- end
86
-
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 pairs
98
- end
99
- }
100
- @reader_open.call(body)
101
- end
102
-
103
- def each(&block)
104
- header_and_each(nil, &block)
105
- end
106
- end
@@ -1,158 +0,0 @@
1
- # lib/tb/record.rb - record class for table library
2
- #
3
- # Copyright (C) 2010-2012 Tanaka Akira <akr@fsij.org>
4
- #
5
- # Redistribution and use in source and binary forms, with or without
6
- # modification, are permitted provided that the following conditions
7
- # are met:
8
- #
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.
18
- #
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
- class Tb::Record
32
- include Enumerable
33
-
34
- def initialize(table, recordid)
35
- @table = table
36
- @recordid = recordid
37
- end
38
- attr_reader :table
39
-
40
- def record_id
41
- @recordid
42
- end
43
-
44
- def pretty_print(q) # :nodoc:
45
- q.object_group(self) {
46
- fs = @table.list_fields.reject {|f| self[f].nil? }
47
- unless fs.empty?
48
- q.text ':'
49
- q.breakable
50
- end
51
- q.seplist(fs, nil, :each) {|f|
52
- v = self[f]
53
- q.group {
54
- q.pp f
55
- q.text '=>'
56
- q.group(1) {
57
- q.breakable ''
58
- q.pp v
59
- }
60
- }
61
- }
62
- }
63
- end
64
- alias inspect pretty_print_inspect # :nodoc:
65
-
66
- def has_field?(field)
67
- @table.has_field?(field)
68
- end
69
- alias has_key? has_field?
70
- alias include? has_field?
71
- alias key? has_field?
72
- alias member? has_field?
73
-
74
- def [](field)
75
- @table.get_cell(@recordid, field)
76
- end
77
-
78
- def []=(field, value)
79
- @table.set_cell(@recordid, field, value)
80
- end
81
-
82
- def to_h
83
- h = {}
84
- @table.each_field {|f|
85
- v = @table.get_cell(@recordid, f)
86
- h[f] = v if !v.nil?
87
- }
88
- h
89
- end
90
-
91
- def to_h_with_reserved
92
- h = {}
93
- @table.each_field_with_reserved {|f|
94
- v = @table.get_cell(@recordid, f)
95
- h[f] = v if !v.nil?
96
- }
97
- h
98
- end
99
-
100
- def to_a
101
- a = []
102
- @table.each_field {|f|
103
- v = @table.get_cell(@recordid, f)
104
- a << [f, v] if !v.nil?
105
- }
106
- a
107
- end
108
-
109
- def to_a_with_reserved
110
- a = []
111
- @table.each_field_with_reserved {|f|
112
- v = @table.get_cell(@recordid, f)
113
- a << [f, v] if !v.nil?
114
- }
115
- a
116
- end
117
-
118
- def each
119
- @table.each_field {|f|
120
- v = @table.get_cell(@recordid, f)
121
- yield [f, v] if !v.nil?
122
- }
123
- nil
124
- end
125
-
126
- def each_with_reserved
127
- @table.each_field_with_reserved {|f|
128
- v = @table.get_cell(@recordid, f)
129
- yield [f, v] if !v.nil?
130
- }
131
- nil
132
- end
133
-
134
- def values_at(*fields)
135
- fields.map {|f| self[f] }
136
- end
137
-
138
- def keys
139
- a = []
140
- @table.each_field {|f|
141
- v = @table.get_cell(@recordid, f)
142
- next if v.nil?
143
- a << f
144
- }
145
- a
146
- end
147
-
148
- def values
149
- a = []
150
- @table.each_field {|f|
151
- v = @table.get_cell(@recordid, f)
152
- next if v.nil?
153
- a << v
154
- }
155
- a
156
- end
157
-
158
- end
@@ -1,403 +0,0 @@
1
- require 'tb'
2
- require 'test/unit'
3
-
4
- class TestTbBasic < Test::Unit::TestCase
5
- def test_initialize
6
- t = Tb.new
7
- assert_equal([], t.list_fields)
8
- t = Tb.new %w[fruit color],
9
- %w[apple red],
10
- %w[banana yellow],
11
- %w[orange orange]
12
- assert_equal(%w[fruit color].sort, t.list_fields.sort)
13
- a = t.to_a.map {|r| r.to_h_with_reserved }
14
- assert_operator(a, :include?, {"_recordid"=>0, "fruit"=>"apple", "color"=>"red"})
15
- assert_operator(a, :include?, {"_recordid"=>1, "fruit"=>"banana", "color"=>"yellow"})
16
- assert_operator(a, :include?, {"_recordid"=>2, "fruit"=>"orange", "color"=>"orange"})
17
- assert_equal(3, a.length)
18
- end
19
-
20
- def test_replace
21
- t1 = Tb.new %w[fruit color],
22
- %w[apple red],
23
- %w[banana yellow],
24
- %w[orange orange]
25
- t2 = Tb.new %w[grain color],
26
- %w[rice white],
27
- %w[wheat light-brown]
28
- t1.replace t2
29
- assert_equal([{"grain"=>"rice", "color"=>"white"},
30
- {"grain"=>"wheat", "color"=>"light-brown"}],
31
- t2.to_a.map {|rec| rec.to_h })
32
- end
33
-
34
- def test_pretty_print
35
- t = Tb.new %w[fruit color],
36
- %w[apple red],
37
- %w[banana yellow],
38
- %w[orange orange]
39
- s = t.pretty_inspect
40
- assert_match(/fruit/, s)
41
- assert_match(/color/, s)
42
- assert_match(/apple/, s)
43
- assert_match(/red/, s)
44
- assert_match(/banana/, s)
45
- assert_match(/yellow/, s)
46
- assert_match(/orange/, s)
47
- end
48
-
49
- def test_enumerable
50
- t = Tb.new
51
- assert_kind_of(Enumerable, t)
52
- end
53
-
54
- def test_define_field
55
- t = Tb.new %w[fruit color],
56
- %w[apple red],
57
- %w[banana yellow],
58
- %w[orange orange]
59
- t.define_field("namelen") {|record| record["fruit"].length }
60
- t.each {|rec|
61
- case rec['fruit']
62
- when 'apple' then assert_equal(5, rec['namelen'])
63
- when 'banana' then assert_equal(6, rec['namelen'])
64
- when 'orange' then assert_equal(6, rec['namelen'])
65
- else raise
66
- end
67
- }
68
- end
69
-
70
- def test_define_field_error
71
- t = Tb.new %w[fruit color],
72
- %w[apple red],
73
- %w[banana yellow],
74
- %w[orange orange]
75
- assert_raise(ArgumentError) { t.define_field("_foo") }
76
- assert_raise(ArgumentError) { t.define_field("fruit") }
77
- end
78
-
79
- def test_list_fields
80
- t = Tb.new
81
- assert_equal([], t.list_fields)
82
- assert_equal([], t.list_fields)
83
- assert_equal(["_recordid"], t.list_fields_all)
84
- t = Tb.new %w[fruit color],
85
- %w[apple red],
86
- %w[banana yellow],
87
- %w[orange orange]
88
- assert_equal(%w[fruit color], t.list_fields)
89
- assert_equal(%w[fruit color], t.list_fields)
90
- assert_equal(%w[_recordid fruit color], t.list_fields_all)
91
- end
92
-
93
- def test_list_recordids
94
- t = Tb.new
95
- assert_equal([], t.list_recordids)
96
- recordid1 = t.allocate_recordid
97
- assert_equal([recordid1], t.list_recordids)
98
- recordid2 = t.allocate_recordid
99
- assert_equal([recordid1, recordid2], t.list_recordids)
100
- assert_equal(nil, t.delete_recordid(recordid1))
101
- assert_equal([recordid2], t.list_recordids)
102
- end
103
-
104
- def test_cell
105
- t = Tb.new %w[f g]
106
- recordid = t.allocate_recordid
107
- assert_equal(nil, t.get_cell(recordid, :f))
108
- t.set_cell(recordid, :f, 1)
109
- assert_equal(1, t.get_cell(recordid, :f))
110
- assert_equal(1, t.delete_cell(recordid, :f))
111
- assert_equal(nil, t.get_cell(recordid, :f))
112
- t.set_cell(recordid, :f, nil)
113
- assert_equal(nil, t.get_cell(recordid, :f))
114
- t.set_cell(recordid, :g, 2)
115
- assert_equal(2, t.get_cell(recordid, :g))
116
- t.set_cell(recordid, :g, nil)
117
- assert_equal(nil, t.get_cell(recordid, :g))
118
- t.delete_cell(recordid, :g)
119
- assert_equal(nil, t.get_cell(recordid, :g))
120
- t.delete_recordid(recordid)
121
- assert_raise(IndexError) { t.get_cell(recordid, :g) }
122
- assert_raise(IndexError) { t.get_cell(100, :g) }
123
- assert_raise(IndexError) { t.get_cell(-1, :g) }
124
- assert_raise(TypeError) { t.get_cell(:invalid_recordid, :g) }
125
- end
126
-
127
- def test_each_field
128
- t = Tb.new %w[a b z]
129
- a = []
130
- t.each_field_with_reserved {|f| a << f }
131
- assert_equal(%w[_recordid a b z], a)
132
- a = []
133
- t.each_field {|f| a << f }
134
- assert_equal(%w[a b z], a)
135
- end
136
-
137
- def test_each_record
138
- t = Tb.new %w[a], [1], [2]
139
- records = []
140
- t.each {|record| records << record.to_h_with_reserved }
141
- assert_equal([{"_recordid"=>0, "a"=>1}, {"_recordid"=>1, "a"=>2}], records)
142
- end
143
-
144
- def test_categorize
145
- t = Tb.new %w[a b c], [1,2,3], [2,4,3]
146
- assert_raise(ArgumentError) { t.tb_categorize('a') }
147
- assert_equal({1=>[2], 2=>[4]}, t.tb_categorize('a', 'b'))
148
- assert_equal({1=>{2=>[3]}, 2=>{4=>[3]}}, t.tb_categorize('a', 'b', 'c'))
149
- assert_equal({1=>[[2,3]], 2=>[[4,3]]}, t.tb_categorize('a', ['b', 'c']))
150
- assert_equal({[1,2]=>[3], [2,4]=>[3]}, t.tb_categorize(['a', 'b'], 'c'))
151
- assert_equal({3=>[2,4]}, t.tb_categorize('c', 'b'))
152
- assert_equal({3=>[true,true]}, t.tb_categorize('c', lambda {|e| true }))
153
- assert_equal({3=>2}, t.tb_categorize('c', 'b') {|ks, vs| vs.length } )
154
- assert_equal({3=>2}, t.tb_categorize('c', 'b',
155
- :seed=>0,
156
- :update=> lambda {|ks, s, v| s + 1 }))
157
- assert_equal({true => [1,2]}, t.tb_categorize(lambda {|e| true }, 'a'))
158
- h = t.tb_categorize('a', lambda {|e| e })
159
- assert_equal(2, h.size)
160
- assert_equal([1, 2], h.keys.sort)
161
- assert_instance_of(Array, h[1])
162
- assert_instance_of(Array, h[2])
163
- assert_equal(1, h[1].length)
164
- assert_equal(1, h[2].length)
165
- assert_instance_of(Tb::Record, h[1][0])
166
- assert_instance_of(Tb::Record, h[2][0])
167
- assert_same(t, h[1][0].table)
168
- assert_same(t, h[2][0].table)
169
- assert_equal(0, h[1][0].record_id)
170
- assert_equal(1, h[2][0].record_id)
171
- assert_same(t, h[2][0].table)
172
-
173
- assert_raise(ArgumentError) { t.tb_categorize(:_foo, lambda {|e| true }) }
174
- assert_equal({3=>[2], 6=>[4]}, t.tb_categorize(lambda {|rec| rec['a'] * 3 }, 'b'))
175
- assert_equal({[1,2]=>[[2,3]], [2,4]=>[[4,3]]}, t.tb_categorize(['a', 'b'], ['b', 'c']))
176
- assert_equal({1=>2, 2=>4}, t.tb_categorize('a', 'b', :seed=>0, :op=>:+))
177
- assert_raise(ArgumentError) { t.tb_categorize('a', 'b', :op=>:+, :update=>lambda {|ks, s, v| v }) }
178
- i = -1
179
- assert_equal({3=>[0, 1]}, t.tb_categorize('c', lambda {|e| i += 1 }))
180
- end
181
-
182
- def test_unique_categorize
183
- t = Tb.new %w[a b c], [1,2,3], [2,4,4]
184
- assert_equal({1=>3, 2=>4}, t.tb_unique_categorize("a", "c"))
185
- assert_equal({1=>[3], 2=>[4]}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? [v] : (seed << v) })
186
- assert_equal({1=>1, 2=>1}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? 1 : seed + 1 })
187
- assert_equal({1=>{2=>3}, 2=>{4=>4}}, t.tb_unique_categorize("a", "b", "c"))
188
- t.insert({"a"=>2, "b"=>7, "c"=>8})
189
- assert_equal({1=>{2=>3}, 2=>{4=>4, 7=>8}}, t.tb_unique_categorize("a", "b", "c"))
190
- end
191
-
192
- def test_unique_categorize_ambiguous
193
- t = Tb.new %w[a b c], [1,2,3], [1,4,4]
194
- assert_raise(ArgumentError) { t.tb_unique_categorize("a", "c") }
195
- assert_equal({1=>[3,4]}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? [v] : (seed << v) })
196
- assert_equal({1=>2}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? 1 : seed + 1 })
197
- end
198
-
199
- def test_category_count
200
- t = Tb.new %w[a b c], [1,2,3], [2,4,3]
201
- assert_equal({1=>1, 2=>1}, t.tb_category_count("a"))
202
- assert_equal({2=>1, 4=>1}, t.tb_category_count("b"))
203
- assert_equal({3=>2}, t.tb_category_count("c"))
204
- assert_equal({3=>{1=>1, 2=>1}}, t.tb_category_count("c", "a"))
205
- end
206
-
207
- def test_natjoin2
208
- t1 = Tb.new %w[a b], %w[1 2], %w[3 4], %w[0 4]
209
- t2 = Tb.new %w[b c], %w[2 3], %w[4 5], %w[5 8]
210
- t3 = t1.natjoin2(t2)
211
- assert_equal([{"a"=>"1", "b"=>"2", "c"=>"3"},
212
- {"a"=>"3", "b"=>"4", "c"=>"5"},
213
- {"a"=>"0", "b"=>"4", "c"=>"5"}],
214
- t3.to_a.map {|r| r.to_h })
215
- end
216
-
217
- def test_natjoin2_nocommon
218
- t1 = Tb.new %w[a b], %w[1 2], %w[3 4]
219
- t2 = Tb.new %w[c d], %w[5 6], %w[7 8]
220
- t3 = t1.natjoin2(t2)
221
- assert_equal([{"a"=>"1", "b"=>"2", "c"=>"5", "d"=>"6"},
222
- {"a"=>"1", "b"=>"2", "c"=>"7", "d"=>"8"},
223
- {"a"=>"3", "b"=>"4", "c"=>"5", "d"=>"6"},
224
- {"a"=>"3", "b"=>"4", "c"=>"7", "d"=>"8"}],
225
- t3.to_a.map {|r| r.to_h })
226
- end
227
-
228
- def test_natjoin2_outer
229
- t1 = Tb.new %w[a b], %w[1 2], %w[3 4], %w[0 4], %w[0 1]
230
- t2 = Tb.new %w[b c], %w[2 3], %w[4 5], %w[5 8]
231
- t3 = t1.natjoin2_outer(t2)
232
- assert_equal([{"a"=>"0", "b"=>"1"},
233
- {"a"=>"1", "b"=>"2", "c"=>"3"},
234
- {"a"=>"3", "b"=>"4", "c"=>"5"},
235
- {"a"=>"0", "b"=>"4", "c"=>"5"},
236
- {"b"=>"5", "c"=>"8"}],
237
- t3.to_a.map {|r| r.to_h })
238
- end
239
-
240
- def test_fmap!
241
- t = Tb.new %w[a b], %w[1 2], %w[3 4]
242
- t.fmap!("a") {|record, v| "foo" + v }
243
- assert_equal([{"_recordid"=>0, "a"=>"foo1", "b"=>"2"},
244
- {"_recordid"=>1, "a"=>"foo3", "b"=>"4"}], t.to_a.map {|r| r.to_h_with_reserved })
245
- end
246
-
247
- def test_delete_field
248
- t = Tb.new(%w[a b], %w[1 2], %w[3 4])
249
- t.delete_field("a")
250
- assert_equal([{"_recordid"=>0, "b"=>"2"},
251
- {"_recordid"=>1, "b"=>"4"}], t.to_a.map {|r| r.to_h_with_reserved })
252
- end
253
-
254
- def test_delete_recordid
255
- t = Tb.new %w[a]
256
- recordid = t.insert({"a"=>"foo"})
257
- t.insert({"a"=>"bar"})
258
- t.delete_recordid(recordid)
259
- t.insert({"a"=>"foo"})
260
- records = []
261
- t.each {|record|
262
- record = record.to_h
263
- record.delete('_recordid')
264
- records << record
265
- }
266
- records = records.sort_by {|record| record['a'] }
267
- assert_equal([{"a"=>"bar"}, {"a"=>"foo"}], records)
268
- end
269
-
270
- def test_rename_field
271
- t1 = Tb.new %w[a b], [1, 2]
272
- assert_equal([{"_recordid"=>0, "a"=>1, "b"=>2}], t1.to_a.map {|r| r.to_h_with_reserved })
273
- t2 = t1.rename_field("a" => "c", "b" => "d")
274
- assert_equal([{"_recordid"=>0, "a"=>1, "b"=>2}], t1.to_a.map {|r| r.to_h_with_reserved })
275
- assert_equal([{"_recordid"=>0, "c"=>1, "d"=>2}], t2.to_a.map {|r| r.to_h_with_reserved })
276
- end
277
-
278
- def test_allocate_recordid
279
- t = Tb.new
280
- recordid1 = t.allocate_recordid(100)
281
- assert_equal(100, recordid1)
282
- recordid2 = t.allocate_recordid(200)
283
- assert_equal(200, recordid2)
284
- recordid3 = t.allocate_recordid
285
- assert(recordid3 != recordid1)
286
- assert(recordid3 != recordid2)
287
- end
288
-
289
- def test_allocate_recordid_error
290
- t = Tb.new
291
- recordid1 = t.allocate_recordid
292
- assert_raise(ArgumentError) { t.allocate_recordid(recordid1) }
293
- end
294
-
295
- def test_allocate_record
296
- t = Tb.new
297
- rec1 = t.allocate_record
298
- assert_kind_of(Tb::Record, rec1)
299
- rec2 = t.allocate_record(200)
300
- assert_kind_of(Tb::Record, rec2)
301
- assert_equal(200, rec2.record_id)
302
- end
303
-
304
- def test_reorder_fields!
305
- t = Tb.new %w[fruit color],
306
- %w[apple red],
307
- %w[banana yellow],
308
- %w[orange orange]
309
- assert_equal(%w[fruit color], t.list_fields)
310
- t.reorder_fields! %w[color fruit]
311
- assert_equal(%w[_recordid color fruit], t.list_fields_all)
312
- t.reorder_fields! %w[fruit _recordid color]
313
- assert_equal(%w[fruit _recordid color], t.list_fields_all)
314
- end
315
-
316
- def test_has_field?
317
- t = Tb.new %w[fruit color],
318
- %w[apple red],
319
- %w[banana yellow],
320
- %w[orange orange]
321
- assert_equal(true, t.has_field?("fruit"))
322
- assert_equal(false, t.has_field?("foo"))
323
- end
324
-
325
- def test_filter
326
- t = Tb.new %w[fruit color],
327
- %w[apple red],
328
- %w[banana yellow],
329
- %w[orange orange]
330
- t2 = t.filter {|rec| rec["fruit"] == "banana" }
331
- assert_equal(1, t2.size)
332
- end
333
-
334
- def test_reorder_records_by
335
- t = Tb.new %w[fruit color],
336
- %w[apple red],
337
- %w[banana yellow],
338
- %w[orange orange]
339
- t2 = t.reorder_records_by {|rec| rec["color"] }
340
- assert_equal(t.map {|rec| rec["color"] }.sort, t2.map {|rec| rec["color"] })
341
- end
342
-
343
- def test_insert_values
344
- t = Tb.new %w[fruit color],
345
- %w[apple red],
346
- %w[banana yellow],
347
- %w[orange orange]
348
- res = t.insert_values(["fruit", "color"], ["grape", "purple"], ["cherry", "red"])
349
- assert_equal([3, 4], res)
350
- assert_equal(["grape", "purple"], t.get_values(3, "fruit", "color"))
351
- assert_equal(["cherry", "red"], t.get_values(4, "fruit", "color"))
352
- end
353
-
354
- def test_insert_values_error
355
- t = Tb.new %w[fruit color],
356
- %w[apple red],
357
- %w[banana yellow],
358
- %w[orange orange]
359
- assert_raise(ArgumentError) { t.insert_values(["fruit", "color"], ["grape", "purple", "red"]) }
360
- end
361
-
362
- def test_concat
363
- t1 = Tb.new %w[fruit color],
364
- %w[apple red]
365
- t2 = Tb.new %w[fruit color],
366
- %w[banana yellow],
367
- %w[orange orange]
368
- t3 = t1.concat(t2)
369
- assert_same(t1, t3)
370
- assert_equal(3, t1.size)
371
- assert_equal(["banana", "yellow"], t1.get_values(1, "fruit", "color"))
372
- assert_equal(["orange", "orange"], t1.get_values(2, "fruit", "color"))
373
- end
374
-
375
- def test_each_record_values
376
- t = Tb.new %w[fruit color],
377
- %w[banana yellow],
378
- %w[orange orange]
379
- rs = []
380
- t.each_record_values('fruit') {|r| rs << r }
381
- assert_equal([['banana'], ['orange']], rs)
382
- rs = []
383
- t.each_record_values('fruit', 'color') {|r| rs << r }
384
- assert_equal([['banana', 'yellow'], ['orange', 'orange']], rs)
385
- end
386
-
387
- def test_with_header
388
- t = Tb.new %w[a b], [1, 2], [3, 4]
389
- result = []
390
- t.with_header {|x|
391
- result << x
392
- }.each {|x|
393
- result << x
394
- }
395
- assert_equal(3, result.length)
396
- assert_equal(%w[a b], result[0])
397
- assert_kind_of(Tb::Record, result[1])
398
- assert_kind_of(Tb::Record, result[2])
399
- assert_equal([["a", 1], ["b", 2]], result[1].to_a)
400
- assert_equal([["a", 3], ["b", 4]], result[2].to_a)
401
- end
402
-
403
- end