tb 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,39 @@
1
+ #!/bin/sh
2
+
3
+ # sample/poi-xls2csv.sh - script to run sample/poi-xls2csv.rb
4
+ #
5
+ # Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright notice, this
11
+ # list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
19
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
23
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
27
+ # OF SUCH DAMAGE.
28
+
29
+ # Ubuntu libjakarta-poi-java package installs /usr/share/java/jakarta-poi.jar.
30
+
31
+ d="`dirname $0`"
32
+ d="`cd $d; pwd`"
33
+ d="`dirname $d`"
34
+
35
+ exec jruby -Ku \
36
+ -I"$d/lib" \
37
+ -I/usr/share/java \
38
+ "$d/sample/poi-xls2csv.rb" \
39
+ "$@"
@@ -0,0 +1,7 @@
1
+ $VERBOSE = true
2
+
3
+ $:.unshift "lib"
4
+
5
+ Dir.glob('test/test_*.rb') {|filename|
6
+ load filename
7
+ }
@@ -0,0 +1,290 @@
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_enumerable
35
+ t = Tb.new
36
+ assert_kind_of(Enumerable, t)
37
+ end
38
+
39
+ def test_define_field
40
+ t = Tb.new %w[fruit color],
41
+ %w[apple red],
42
+ %w[banana yellow],
43
+ %w[orange orange]
44
+ t.define_field("namelen") {|record| record["fruit"].length }
45
+ t.each {|rec|
46
+ case rec['fruit']
47
+ when 'apple' then assert_equal(5, rec['namelen'])
48
+ when 'banana' then assert_equal(6, rec['namelen'])
49
+ when 'orange' then assert_equal(6, rec['namelen'])
50
+ else raise
51
+ end
52
+ }
53
+ end
54
+
55
+ def test_list_fields
56
+ t = Tb.new
57
+ assert_equal([], t.list_fields)
58
+ assert_equal([], t.list_fields)
59
+ assert_equal(["_recordid"], t.list_fields_all)
60
+ t = Tb.new %w[fruit color],
61
+ %w[apple red],
62
+ %w[banana yellow],
63
+ %w[orange orange]
64
+ assert_equal(%w[fruit color], t.list_fields)
65
+ assert_equal(%w[fruit color], t.list_fields)
66
+ assert_equal(%w[_recordid fruit color], t.list_fields_all)
67
+ end
68
+
69
+ def test_list_recordids
70
+ t = Tb.new
71
+ assert_equal([], t.list_recordids)
72
+ recordid1 = t.allocate_recordid
73
+ assert_equal([recordid1], t.list_recordids)
74
+ recordid2 = t.allocate_recordid
75
+ assert_equal([recordid1, recordid2], t.list_recordids)
76
+ assert_equal(nil, t.delete_recordid(recordid1))
77
+ assert_equal([recordid2], t.list_recordids)
78
+ end
79
+
80
+ def test_cell
81
+ t = Tb.new %w[f g]
82
+ recordid = t.allocate_recordid
83
+ assert_equal(nil, t.get_cell(recordid, :f))
84
+ t.set_cell(recordid, :f, 1)
85
+ assert_equal(1, t.get_cell(recordid, :f))
86
+ assert_equal(1, t.delete_cell(recordid, :f))
87
+ assert_equal(nil, t.get_cell(recordid, :f))
88
+ t.set_cell(recordid, :f, nil)
89
+ assert_equal(nil, t.get_cell(recordid, :f))
90
+ t.set_cell(recordid, :g, 2)
91
+ assert_equal(2, t.get_cell(recordid, :g))
92
+ t.set_cell(recordid, :g, nil)
93
+ assert_equal(nil, t.get_cell(recordid, :g))
94
+ t.delete_cell(recordid, :g)
95
+ assert_equal(nil, t.get_cell(recordid, :g))
96
+ t.delete_recordid(recordid)
97
+ assert_raise(IndexError) { t.get_cell(recordid, :g) }
98
+ assert_raise(IndexError) { t.get_cell(100, :g) }
99
+ assert_raise(IndexError) { t.get_cell(-1, :g) }
100
+ assert_raise(TypeError) { t.get_cell(:invalid_recordid, :g) }
101
+ end
102
+
103
+ def test_each_field
104
+ t = Tb.new %w[a b z]
105
+ a = []
106
+ t.each_field_with_reserved {|f| a << f }
107
+ assert_equal(%w[_recordid a b z], a)
108
+ a = []
109
+ t.each_field {|f| a << f }
110
+ assert_equal(%w[a b z], a)
111
+ end
112
+
113
+ def test_each_record
114
+ t = Tb.new %w[a], [1], [2]
115
+ records = []
116
+ t.each {|record| records << record.to_h_with_reserved }
117
+ assert_equal([{"_recordid"=>0, "a"=>1}, {"_recordid"=>1, "a"=>2}], records)
118
+ end
119
+
120
+ def test_categorize
121
+ t = Tb.new %w[a b c], [1,2,3], [2,4,3]
122
+ assert_raise(ArgumentError) { t.tb_categorize('a') }
123
+ assert_equal({1=>[2], 2=>[4]}, t.tb_categorize('a', 'b'))
124
+ assert_equal({1=>{2=>[3]}, 2=>{4=>[3]}}, t.tb_categorize('a', 'b', 'c'))
125
+ assert_equal({1=>[[2,3]], 2=>[[4,3]]}, t.tb_categorize('a', ['b', 'c']))
126
+ assert_equal({[1,2]=>[3], [2,4]=>[3]}, t.tb_categorize(['a', 'b'], 'c'))
127
+ assert_equal({3=>[2,4]}, t.tb_categorize('c', 'b'))
128
+ assert_equal({3=>[true,true]}, t.tb_categorize('c', lambda {|e| true }))
129
+ assert_equal({3=>2}, t.tb_categorize('c', 'b') {|ks, vs| vs.length } )
130
+ assert_equal({3=>2}, t.tb_categorize('c', 'b',
131
+ :seed=>0,
132
+ :update=> lambda {|ks, s, v| s + 1 }))
133
+ assert_equal({true => [1,2]}, t.tb_categorize(lambda {|e| true }, 'a'))
134
+ h = t.tb_categorize('a', lambda {|e| e })
135
+ assert_equal(2, h.size)
136
+ assert_equal([1, 2], h.keys.sort)
137
+ assert_instance_of(Array, h[1])
138
+ assert_instance_of(Array, h[2])
139
+ assert_equal(1, h[1].length)
140
+ assert_equal(1, h[2].length)
141
+ assert_instance_of(Tb::Record, h[1][0])
142
+ assert_instance_of(Tb::Record, h[2][0])
143
+ assert_same(t, h[1][0].table)
144
+ assert_same(t, h[2][0].table)
145
+ assert_equal(0, h[1][0].record_id)
146
+ assert_equal(1, h[2][0].record_id)
147
+ assert_same(t, h[2][0].table)
148
+
149
+ assert_raise(ArgumentError) { t.tb_categorize(:_foo, lambda {|e| true }) }
150
+ assert_equal({3=>[2], 6=>[4]}, t.tb_categorize(lambda {|rec| rec['a'] * 3 }, 'b'))
151
+ assert_equal({[1,2]=>[[2,3]], [2,4]=>[[4,3]]}, t.tb_categorize(['a', 'b'], ['b', 'c']))
152
+ assert_equal({1=>2, 2=>4}, t.tb_categorize('a', 'b', :seed=>0, :op=>:+))
153
+ assert_raise(ArgumentError) { t.tb_categorize('a', 'b', :op=>:+, :update=>lambda {|ks, s, v| v }) }
154
+ i = -1
155
+ assert_equal({3=>[0, 1]}, t.tb_categorize('c', lambda {|e| i += 1 }))
156
+ end
157
+
158
+ def test_unique_categorize
159
+ t = Tb.new %w[a b c], [1,2,3], [2,4,4]
160
+ assert_equal({1=>3, 2=>4}, t.tb_unique_categorize("a", "c"))
161
+ assert_equal({1=>[3], 2=>[4]}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? [v] : (seed << v) })
162
+ assert_equal({1=>1, 2=>1}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? 1 : seed + 1 })
163
+ assert_equal({1=>{2=>3}, 2=>{4=>4}}, t.tb_unique_categorize("a", "b", "c"))
164
+ t.insert({"a"=>2, "b"=>7, "c"=>8})
165
+ assert_equal({1=>{2=>3}, 2=>{4=>4, 7=>8}}, t.tb_unique_categorize("a", "b", "c"))
166
+ end
167
+
168
+ def test_unique_categorize_ambiguous
169
+ t = Tb.new %w[a b c], [1,2,3], [1,4,4]
170
+ assert_raise(ArgumentError) { t.tb_unique_categorize("a", "c") }
171
+ assert_equal({1=>[3,4]}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? [v] : (seed << v) })
172
+ assert_equal({1=>2}, t.tb_unique_categorize("a", "c", :seed=>nil) {|seed, v| !seed ? 1 : seed + 1 })
173
+ end
174
+
175
+ def test_category_count
176
+ t = Tb.new %w[a b c], [1,2,3], [2,4,3]
177
+ assert_equal({1=>1, 2=>1}, t.tb_category_count("a"))
178
+ assert_equal({2=>1, 4=>1}, t.tb_category_count("b"))
179
+ assert_equal({3=>2}, t.tb_category_count("c"))
180
+ assert_equal({3=>{1=>1, 2=>1}}, t.tb_category_count("c", "a"))
181
+ end
182
+
183
+ def test_natjoin2
184
+ t1 = Tb.new %w[a b], %w[1 2], %w[3 4], %w[0 4]
185
+ t2 = Tb.new %w[b c], %w[2 3], %w[4 5]
186
+ t3 = t1.natjoin2(t2)
187
+ assert_equal([{"_recordid"=>0, "a"=>"1", "b"=>"2", "c"=>"3"},
188
+ {"_recordid"=>1, "a"=>"3", "b"=>"4", "c"=>"5"},
189
+ {"_recordid"=>2, "a"=>"0", "b"=>"4", "c"=>"5"}], t3.to_a.map {|r| r.to_h_with_reserved })
190
+ end
191
+
192
+ def test_natjoin2_nocommon
193
+ t1 = Tb.new %w[a b], %w[1 2], %w[3 4]
194
+ t2 = Tb.new %w[c d], %w[5 6], %w[7 8]
195
+ t3 = t1.natjoin2(t2)
196
+ assert_equal([{"a"=>"1", "b"=>"2", "c"=>"5", "d"=>"6"},
197
+ {"a"=>"1", "b"=>"2", "c"=>"7", "d"=>"8"},
198
+ {"a"=>"3", "b"=>"4", "c"=>"5", "d"=>"6"},
199
+ {"a"=>"3", "b"=>"4", "c"=>"7", "d"=>"8"}],
200
+ t3.to_a.map {|r| r.to_h })
201
+ end
202
+
203
+ def test_fmap!
204
+ t = Tb.new %w[a b], %w[1 2], %w[3 4]
205
+ t.fmap!("a") {|record, v| "foo" + v }
206
+ assert_equal([{"_recordid"=>0, "a"=>"foo1", "b"=>"2"},
207
+ {"_recordid"=>1, "a"=>"foo3", "b"=>"4"}], t.to_a.map {|r| r.to_h_with_reserved })
208
+ end
209
+
210
+ def test_delete_field
211
+ t = Tb.new(%w[a b], %w[1 2], %w[3 4])
212
+ t.delete_field("a")
213
+ assert_equal([{"_recordid"=>0, "b"=>"2"},
214
+ {"_recordid"=>1, "b"=>"4"}], t.to_a.map {|r| r.to_h_with_reserved })
215
+ end
216
+
217
+ def test_delete_recordid
218
+ t = Tb.new %w[a]
219
+ recordid = t.insert({"a"=>"foo"})
220
+ t.insert({"a"=>"bar"})
221
+ t.delete_recordid(recordid)
222
+ t.insert({"a"=>"foo"})
223
+ records = []
224
+ t.each {|record|
225
+ record = record.to_h
226
+ record.delete('_recordid')
227
+ records << record
228
+ }
229
+ records = records.sort_by {|record| record['a'] }
230
+ assert_equal([{"a"=>"bar"}, {"a"=>"foo"}], records)
231
+ end
232
+
233
+ def test_rename_field
234
+ t1 = Tb.new %w[a b], [1, 2]
235
+ assert_equal([{"_recordid"=>0, "a"=>1, "b"=>2}], t1.to_a.map {|r| r.to_h_with_reserved })
236
+ t2 = t1.rename_field("a" => "c", "b" => "d")
237
+ assert_equal([{"_recordid"=>0, "a"=>1, "b"=>2}], t1.to_a.map {|r| r.to_h_with_reserved })
238
+ assert_equal([{"_recordid"=>0, "c"=>1, "d"=>2}], t2.to_a.map {|r| r.to_h_with_reserved })
239
+ end
240
+
241
+ def test_allocate_recordid
242
+ t = Tb.new
243
+ recordid1 = t.allocate_recordid(100)
244
+ assert_equal(100, recordid1)
245
+ recordid2 = t.allocate_recordid(200)
246
+ assert_equal(200, recordid2)
247
+ recordid3 = t.allocate_recordid
248
+ assert(recordid3 != recordid1)
249
+ assert(recordid3 != recordid2)
250
+ end
251
+
252
+ def test_reorder_fields!
253
+ t = Tb.new %w[fruit color],
254
+ %w[apple red],
255
+ %w[banana yellow],
256
+ %w[orange orange]
257
+ assert_equal(%w[fruit color], t.list_fields)
258
+ t.reorder_fields! %w[color fruit]
259
+ assert_equal(%w[_recordid color fruit], t.list_fields_all)
260
+ t.reorder_fields! %w[fruit _recordid color]
261
+ assert_equal(%w[fruit _recordid color], t.list_fields_all)
262
+ end
263
+
264
+ def test_has_field?
265
+ t = Tb.new %w[fruit color],
266
+ %w[apple red],
267
+ %w[banana yellow],
268
+ %w[orange orange]
269
+ assert_equal(true, t.has_field?("fruit"))
270
+ assert_equal(false, t.has_field?("foo"))
271
+ end
272
+
273
+ def test_filter
274
+ t = Tb.new %w[fruit color],
275
+ %w[apple red],
276
+ %w[banana yellow],
277
+ %w[orange orange]
278
+ t2 = t.filter {|rec| rec["fruit"] == "banana" }
279
+ assert_equal(1, t2.size)
280
+ end
281
+
282
+ def test_reorder_records_by
283
+ t = Tb.new %w[fruit color],
284
+ %w[apple red],
285
+ %w[banana yellow],
286
+ %w[orange orange]
287
+ t2 = t.reorder_records_by {|rec| rec["color"] }
288
+ assert_equal(t.map {|rec| rec["color"] }.sort, t2.map {|rec| rec["color"] })
289
+ end
290
+ end
@@ -0,0 +1,78 @@
1
+ require 'tb'
2
+ require 'test/unit'
3
+
4
+ class TestTbCSV < Test::Unit::TestCase
5
+ def test_parse
6
+ csv = <<-'End'.gsub(/^\s+/, '')
7
+ a,b
8
+ 1,2
9
+ 3,4
10
+ End
11
+ t = Tb.parse_csv(csv)
12
+ records = []
13
+ t.each_record {|record|
14
+ records << record.to_h_with_reserved
15
+ }
16
+ assert_equal(
17
+ [{"_recordid"=>0, "a"=>"1", "b"=>"2"},
18
+ {"_recordid"=>1, "a"=>"3", "b"=>"4"}],
19
+ records)
20
+ end
21
+
22
+ def test_parse_empty
23
+ csv = <<-'End'.gsub(/^\s+/, '')
24
+ a,b,c
25
+ 1,,2
26
+ 3,"",4
27
+ End
28
+ t = Tb.parse_csv(csv)
29
+ records = []
30
+ t.each_record {|record|
31
+ records << record.to_h_with_reserved
32
+ }
33
+ assert_equal(
34
+ [{"_recordid"=>0, "a"=>"1", "c"=>"2"},
35
+ {"_recordid"=>1, "a"=>"3", "b"=>"", "c"=>"4"}],
36
+ records)
37
+ end
38
+
39
+ def test_parse_conv
40
+ csv = "foo\na,b\n1,2\n"
41
+ t = Tb.parse_csv(csv) {|aa|
42
+ assert_equal([%w[foo],
43
+ %w[a b],
44
+ %w[1 2]],
45
+ aa)
46
+ aa.shift
47
+ aa
48
+ }
49
+ records = []
50
+ t.each_record {|record|
51
+ records << record.to_h_with_reserved
52
+ }
53
+ assert_equal(
54
+ [{"_recordid"=>0, "a"=>"1", "b"=>"2"}],
55
+ records)
56
+ end
57
+
58
+ def test_generate
59
+ t = Tb.new %w[a b], [1, 2], [3, 4]
60
+ out = t.generate_csv('', ['a', 'b'])
61
+ assert_equal(<<-'End'.gsub(/^\s+/, ''), out)
62
+ a,b
63
+ 1,2
64
+ 3,4
65
+ End
66
+ end
67
+
68
+ def test_generate_empty
69
+ t = Tb.new %w[a b c], [1, nil, 2], [3, '', 4]
70
+ out = t.generate_csv('', ['a', 'b', 'c'])
71
+ assert_equal(<<-'End'.gsub(/^\s+/, ''), out)
72
+ a,b,c
73
+ 1,,2
74
+ 3,"",4
75
+ End
76
+ end
77
+
78
+ end
@@ -0,0 +1,122 @@
1
+ require 'tb/enumerable'
2
+ require 'test/unit'
3
+
4
+ class TestTbEnumerable < Test::Unit::TestCase
5
+ def test_categorize
6
+ a = [{:fruit => "banana", :color => "yellow", :taste => "sweet", :price => 100},
7
+ {:fruit => "melon", :color => "green", :taste => "sweet", :price => 300},
8
+ {:fruit => "grapefruit", :color => "yellow", :taste => "tart", :price => 200}]
9
+ assert_equal({"yellow"=>["banana", "grapefruit"], "green"=>["melon"]},
10
+ a.tb_categorize(:color, :fruit))
11
+ assert_equal({"sweet"=>["banana", "melon"], "tart"=>["grapefruit"]},
12
+ a.tb_categorize(:taste, :fruit))
13
+ assert_equal({"sweet"=>{"yellow"=>["banana"], "green"=>["melon"]}, "tart"=>{"yellow"=>["grapefruit"]}},
14
+ a.tb_categorize(:taste, :color, :fruit))
15
+ assert_equal({"sweet"=>["yellow", "green"], "tart"=>["yellow"]},
16
+ a.tb_categorize(:taste, :color))
17
+ assert_equal({?n=>["banana", "melon"], ?e=>["grapefruit"]},
18
+ a.tb_categorize(lambda {|elt| elt[:fruit][4] }, :fruit))
19
+
20
+ assert_equal({"yellow"=>[true, true], "green"=>[true]},
21
+ a.tb_categorize(:color, lambda {|e| true }))
22
+
23
+ i = -1
24
+ assert_equal({"yellow"=>[0, 2], "green"=>[1]},
25
+ a.tb_categorize(:color, lambda {|e| i += 1 }))
26
+
27
+ assert_equal({"yellow"=>[{:fruit=>"banana", :color=>"yellow", :taste=>"sweet", :price=>100},
28
+ {:fruit=>"grapefruit", :color=>"yellow", :taste=>"tart", :price=>200}],
29
+ "green"=>[{:fruit=>"melon", :color=>"green", :taste=>"sweet", :price=>300}]},
30
+ a.tb_categorize(:color, lambda {|e| e }))
31
+
32
+ assert_equal({"yellow"=>[{:fruit=>"banana", :color=>"yellow", :taste=>"sweet", :price=>100},
33
+ {:fruit=>"grapefruit", :color=>"yellow", :taste=>"tart", :price=>200}],
34
+ "green"=>[{:fruit=>"melon", :color=>"green", :taste=>"sweet", :price=>300}]},
35
+ a.tb_categorize(:color, lambda {|e| e }))
36
+
37
+ i = -1
38
+ assert_equal({"yellow"=>[["banana", "sweet", 0], ["grapefruit", "tart", 2]],
39
+ "green"=>[["melon", "sweet", 1]]},
40
+ a.tb_categorize(:color, [:fruit, :taste, lambda {|e| i += 1 }]))
41
+
42
+ assert_equal({true=>["banana", "melon", "grapefruit"]},
43
+ a.tb_categorize(lambda {|e| true }, :fruit))
44
+
45
+ assert_equal({"yellow"=>2, "green"=>1},
46
+ a.tb_categorize(:color, lambda {|e| true }, :seed=>0, :op=>lambda {|s, v| s+1 }))
47
+
48
+ assert_raise(ArgumentError) { a.tb_categorize(:color, lambda {|e| true }, :seed=>0,
49
+ :seed=>nil,
50
+ :op=>lambda {|s, v| s+1 },
51
+ :update=>lambda {|ks, s, v| s+1 }) }
52
+
53
+ assert_equal({"yellow"=>"bananagrapefruit", "green"=>"melon"},
54
+ a.tb_categorize(:color, :fruit, :seed=>"", :op=>:+))
55
+
56
+ assert_equal({"yellow"=>2, "green"=>1},
57
+ a.tb_categorize(:color, lambda {|e| 1 }, :op=>:+))
58
+
59
+ assert_equal({"yellow"=>"banana,grapefruit", "green"=>"melon"},
60
+ a.tb_categorize(:color, :fruit) {|ks, vs| vs.join(",") } )
61
+
62
+ assert_equal({"yellow"=>150.0, "green"=>300.0},
63
+ a.tb_categorize(:color, :price) {|ks, vs| vs.inject(0.0, &:+) / vs.length })
64
+
65
+ assert_equal({"yellow"=>{"banana"=>100.0, "grapefruit"=>200.0}, "green"=>{"melon"=>300.0}},
66
+ a.tb_categorize(:color, :fruit, :price) {|ks, vs| vs.inject(0.0, &:+) / vs.length })
67
+
68
+ assert_raise(ArgumentError) { a.tb_categorize('a') }
69
+ end
70
+
71
+ def test_categorize_proc
72
+ c = Object.new
73
+ def c.call(v) 10 end
74
+ assert_equal({10=>[10]}, [[1]].tb_categorize(c, c))
75
+ assert_raise(NoMethodError) { [[1]].tb_categorize(0, 0, :seed=>nil, :update=>c) }
76
+ assert_raise(NoMethodError) { [[1]].tb_categorize(0, 0, :seed=>nil, :op=>c) }
77
+
78
+ t = Object.new
79
+ def t.to_proc() lambda {|*| 11 } end
80
+ assert_raise(TypeError) { [[1]].tb_categorize(t, t) }
81
+ assert_equal({1=>11}, [[1]].tb_categorize(0, 0, :seed=>nil, :update=>t))
82
+ assert_equal({1=>11}, [[1]].tb_categorize(0, 0, :seed=>nil, :op=>t))
83
+
84
+ ct = Object.new
85
+ def ct.call(v) 12 end
86
+ def ct.to_proc() lambda {|*| 13 } end
87
+ assert_equal({12=>[12]}, [[1]].tb_categorize(ct, ct))
88
+ assert_equal({1=>13}, [[1]].tb_categorize(0, 0, :seed=>nil, :update=>ct))
89
+ assert_equal({1=>13}, [[1]].tb_categorize(0, 0, :seed=>nil, :op=>ct))
90
+ end
91
+
92
+ def test_unique_categorize
93
+ a = [{:fruit => "banana", :color => "yellow", :taste => "sweet", :price => 100},
94
+ {:fruit => "melon", :color => "green", :taste => "sweet", :price => 300},
95
+ {:fruit => "grapefruit", :color => "yellow", :taste => "tart", :price => 200}]
96
+ assert_equal({"banana"=>100, "melon"=>300, "grapefruit"=>200},
97
+ a.tb_unique_categorize(:fruit, :price))
98
+
99
+ assert_raise(ArgumentError) { a.tb_unique_categorize(:color, :price) }
100
+
101
+ assert_equal({"sweet"=>400, "tart"=>200},
102
+ a.tb_unique_categorize(:taste, :price) {|s, v| !s ? v : s + v })
103
+
104
+ assert_equal({"yellow"=>300, "green"=>300},
105
+ a.tb_unique_categorize(:color, :price, :seed=>0) {|s, v| s + v })
106
+ end
107
+
108
+ def test_category_count
109
+ a = [{:fruit => "banana", :color => "yellow", :taste => "sweet", :price => 100},
110
+ {:fruit => "melon", :color => "green", :taste => "sweet", :price => 300},
111
+ {:fruit => "grapefruit", :color => "yellow", :taste => "tart", :price => 200}]
112
+
113
+ assert_equal({"yellow"=>2, "green"=>1},
114
+ a.tb_category_count(:color))
115
+
116
+ assert_equal({"sweet"=>2, "tart"=>1},
117
+ a.tb_category_count(:taste))
118
+
119
+ assert_equal({"sweet"=>{"yellow"=>1, "green"=>1}, "tart"=>{"yellow"=>1}},
120
+ a.tb_category_count(:taste, :color))
121
+ end
122
+ end