tb 0.1

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.
@@ -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