tb 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +60 -0
- data/bin/tb +1137 -0
- data/lib/tb.rb +35 -0
- data/lib/tb/basic.rb +1071 -0
- data/lib/tb/csv.rb +125 -0
- data/lib/tb/enumerable.rb +284 -0
- data/lib/tb/fieldset.rb +96 -0
- data/lib/tb/pathfinder.rb +569 -0
- data/lib/tb/qtsv.rb +93 -0
- data/lib/tb/reader.rb +213 -0
- data/lib/tb/record.rb +129 -0
- data/lib/tb/tsv.rb +93 -0
- data/sample/excel2csv +270 -0
- data/sample/poi-xls2csv.rb +397 -0
- data/sample/poi-xls2csv.sh +39 -0
- data/test-all.rb +7 -0
- data/test/test_basic.rb +290 -0
- data/test/test_csv.rb +78 -0
- data/test/test_enumerable.rb +122 -0
- data/test/test_record.rb +12 -0
- data/test/test_tsv.rb +41 -0
- metadata +73 -0
@@ -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
|
+
"$@"
|
data/test-all.rb
ADDED
data/test/test_basic.rb
ADDED
@@ -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
|
data/test/test_csv.rb
ADDED
@@ -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
|