tb 0.3 → 0.4

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 (55) hide show
  1. data/README +2 -1
  2. data/lib/tb.rb +7 -3
  3. data/lib/tb/basic.rb +1 -1
  4. data/lib/tb/cmd_cat.rb +1 -3
  5. data/lib/tb/cmd_consecutive.rb +4 -6
  6. data/lib/tb/cmd_crop.rb +5 -7
  7. data/lib/tb/cmd_cross.rb +51 -49
  8. data/lib/tb/cmd_cut.rb +2 -6
  9. data/lib/tb/cmd_git_log.rb +20 -11
  10. data/lib/tb/cmd_grep.rb +1 -3
  11. data/lib/tb/cmd_group.rb +18 -44
  12. data/lib/tb/cmd_gsub.rb +2 -4
  13. data/lib/tb/cmd_join.rb +1 -3
  14. data/lib/tb/cmd_ls.rb +8 -15
  15. data/lib/tb/cmd_mheader.rb +3 -4
  16. data/lib/tb/cmd_nest.rb +4 -9
  17. data/lib/tb/cmd_newfield.rb +1 -3
  18. data/lib/tb/cmd_rename.rb +2 -4
  19. data/lib/tb/cmd_shape.rb +2 -3
  20. data/lib/tb/cmd_sort.rb +3 -5
  21. data/lib/tb/cmd_svn_log.rb +3 -5
  22. data/lib/tb/cmd_tar_tvf.rb +2 -4
  23. data/lib/tb/cmd_to_csv.rb +1 -1
  24. data/lib/tb/cmd_unnest.rb +1 -3
  25. data/lib/tb/cmdutil.rb +57 -135
  26. data/lib/tb/csv.rb +11 -54
  27. data/lib/tb/customcmp.rb +41 -0
  28. data/lib/tb/customeq.rb +41 -0
  29. data/lib/tb/enumerable.rb +225 -435
  30. data/lib/tb/enumerator.rb +22 -14
  31. data/lib/tb/ex_enumerable.rb +659 -0
  32. data/lib/tb/ex_enumerator.rb +102 -0
  33. data/lib/tb/fileenumerator.rb +2 -2
  34. data/lib/tb/func.rb +141 -0
  35. data/lib/tb/json.rb +1 -1
  36. data/lib/tb/reader.rb +4 -4
  37. data/lib/tb/search.rb +2 -4
  38. data/lib/tb/zipper.rb +60 -0
  39. data/test/test_cmd_cat.rb +40 -0
  40. data/test/test_cmd_git_log.rb +116 -0
  41. data/test/test_cmd_ls.rb +90 -0
  42. data/test/test_cmd_svn_log.rb +87 -0
  43. data/test/test_cmd_to_csv.rb +14 -0
  44. data/test/test_cmdutil.rb +25 -10
  45. data/test/test_csv.rb +10 -0
  46. data/test/test_customcmp.rb +14 -0
  47. data/test/test_customeq.rb +20 -0
  48. data/test/{test_enumerable.rb → test_ex_enumerable.rb} +181 -3
  49. data/test/test_search.rb +2 -10
  50. data/test/test_tbenum.rb +3 -3
  51. data/test/test_zipper.rb +22 -0
  52. metadata +20 -8
  53. data/lib/tb/enum.rb +0 -294
  54. data/lib/tb/pairs.rb +0 -227
  55. data/test/test_pairs.rb +0 -122
@@ -35,6 +35,15 @@ class TestTbCmdLs < Test::Unit::TestCase
35
35
  end
36
36
  end
37
37
 
38
+ def with_stderr_log
39
+ File.open("log", "w") {|log|
40
+ with_stderr(log) {
41
+ yield
42
+ }
43
+ }
44
+ File.read('log')
45
+ end
46
+
38
47
  def reader_thread(io)
39
48
  Thread.new {
40
49
  r = ''
@@ -199,4 +208,85 @@ class TestTbCmdLs < Test::Unit::TestCase
199
208
  end
200
209
  end
201
210
 
211
+ def test_ls_info_symlink
212
+ lsobj = Tb::Cmd::Ls.new(nil, {})
213
+ st = Object.new
214
+ def st.symlink?() true end
215
+ log = with_stderr_log {
216
+ assert_nil(lsobj.ls_info_symlink('.', st))
217
+ }
218
+ assert(!log.empty?)
219
+ end
220
+
221
+ end
222
+
223
+ class TestTbCmdLsNoTmpDir < Test::Unit::TestCase
224
+ def setup
225
+ Tb::Cmd.reset_option
226
+ #@curdir = Dir.pwd
227
+ #@tmpdir = Dir.mktmpdir
228
+ #Dir.chdir @tmpdir
229
+ end
230
+ def teardown
231
+ Tb::Cmd.reset_option
232
+ #Dir.chdir @curdir
233
+ #FileUtils.rmtree @tmpdir
234
+ end
235
+
236
+ def test_ls_info_filemode
237
+ lsobj = Tb::Cmd::Ls.new(nil, {})
238
+ st = Object.new
239
+ def st.mode() 0 end
240
+ def st.ftype() @ftype end
241
+ def st.ftype=(arg) @ftype = arg end
242
+ st.ftype = 'file'
243
+ assert_equal("----------", lsobj.ls_info_filemode(nil, st))
244
+ st.ftype = 'directory'
245
+ assert_equal("d---------", lsobj.ls_info_filemode(nil, st))
246
+ st.ftype = 'characterSpecial'
247
+ assert_equal("c---------", lsobj.ls_info_filemode(nil, st))
248
+ st.ftype = 'blockSpecial'
249
+ assert_equal("b---------", lsobj.ls_info_filemode(nil, st))
250
+ st.ftype = 'fifo'
251
+ assert_equal("p---------", lsobj.ls_info_filemode(nil, st))
252
+ st.ftype = 'link'
253
+ assert_equal("l---------", lsobj.ls_info_filemode(nil, st))
254
+ st.ftype = 'socket'
255
+ assert_equal("s---------", lsobj.ls_info_filemode(nil, st))
256
+ st.ftype = 'unknown'
257
+ assert_equal("?---------", lsobj.ls_info_filemode(nil, st))
258
+ st.ftype = 'foobar'
259
+ assert_equal("?---------", lsobj.ls_info_filemode(nil, st))
260
+ end
261
+
262
+ def test_ls_info_user
263
+ lsobj = Tb::Cmd::Ls.new(nil, {})
264
+ st = Object.new
265
+ # assumes Etc.getpwuid(-100) causes ArgumentError.
266
+ def st.uid() -100 end
267
+ assert_equal("-100", lsobj.ls_info_user(nil, st))
268
+ end
269
+
270
+ def test_ls_info_group
271
+ lsobj = Tb::Cmd::Ls.new(nil, {})
272
+ st = Object.new
273
+ # assumes Etc.getgrgid(-200) causes ArgumentError.
274
+ def st.gid() -200 end
275
+ assert_equal("-200", lsobj.ls_info_group(nil, st))
276
+ end
277
+
278
+ def test_ls_info_atime
279
+ lsobj = Tb::Cmd::Ls.new(nil, {:l => 1})
280
+ st = Object.new
281
+ def st.atime() Time.utc(2000) end
282
+ assert_equal("2000-01-01T00:00:00Z", lsobj.ls_info_atime(nil, st))
283
+ end
284
+
285
+ def test_ls_info_ctime
286
+ lsobj = Tb::Cmd::Ls.new(nil, {:l => 1})
287
+ st = Object.new
288
+ def st.ctime() Time.utc(2000) end
289
+ assert_equal("2000-01-01T00:00:00Z", lsobj.ls_info_ctime(nil, st))
290
+ end
291
+
202
292
  end
@@ -0,0 +1,87 @@
1
+ require 'test/unit'
2
+ require 'tb/cmdtop'
3
+ require 'tmpdir'
4
+
5
+ class TestTbCmdSvnLog < Test::Unit::TestCase
6
+ def setup
7
+ Tb::Cmd.reset_option
8
+ @curdir = Dir.pwd
9
+ @tmpdir = Dir.mktmpdir
10
+ Dir.chdir @tmpdir
11
+ end
12
+ def teardown
13
+ Tb::Cmd.reset_option
14
+ Dir.chdir @curdir
15
+ FileUtils.rmtree @tmpdir
16
+ end
17
+
18
+ def with_stderr(io)
19
+ save = $stderr
20
+ $stderr = io
21
+ begin
22
+ yield
23
+ ensure
24
+ $stderr = save
25
+ end
26
+ end
27
+
28
+ def test_basic
29
+ system("svnadmin create repo")
30
+ system("svn co -q file://#{@tmpdir}/repo .")
31
+ File.open("foo", "w") {|f| f.puts "bar" }
32
+ File.open("hoge", "w") {|f| f.puts "moge" }
33
+ system("svn add -q foo hoge")
34
+ system("svn commit -q -m baz foo hoge")
35
+ system("svn update -q") # update the revision of the directory.
36
+ Tb::Cmd.main_svn_log(['-o', o="o.csv"])
37
+ result = File.read(o)
38
+ tb = Tb.parse_csv(result)
39
+ assert_equal(1, tb.size)
40
+ assert_match(/baz/, tb.get_record(0)["msg"])
41
+ end
42
+
43
+ def test_verbose
44
+ system("svnadmin create repo")
45
+ system("svn co -q file://#{@tmpdir}/repo .")
46
+ File.open("foo", "w") {|f| f.puts "bar" }
47
+ File.open("hoge", "w") {|f| f.puts "moge" }
48
+ system("svn add -q foo hoge")
49
+ system("svn commit -q -m baz foo hoge")
50
+ system("svn update -q") # update the revision of the directory.
51
+ Tb::Cmd.main_svn_log(['-o', o="o.csv", '--', '-v'])
52
+ result = File.read(o)
53
+ tb = Tb.parse_csv(result)
54
+ assert_equal(2, tb.size)
55
+ recs = [tb.get_record(0), tb.get_record(1)]
56
+ recs = recs.sort_by {|rec| rec['path'] }
57
+ recs.each {|rec|
58
+ assert_match(/baz/, rec["msg"])
59
+ }
60
+ assert_match(/foo/, recs[0]["path"])
61
+ assert_match(/hoge/, recs[1]["path"])
62
+ end
63
+
64
+ def test_log_xml
65
+ system("svnadmin create repo")
66
+ system("svn co -q file://#{@tmpdir}/repo .")
67
+ File.open("foo", "w") {|f| f.puts "bar" }
68
+ File.open("hoge", "w") {|f| f.puts "moge" }
69
+ system("svn add -q foo hoge")
70
+ system("svn commit -q -m baz foo hoge")
71
+ system("svn update -q") # update the revision of the directory.
72
+ ###
73
+ Tb::Cmd.main_svn_log(['-o', o="o.csv"])
74
+ result = File.read(o)
75
+ tb = Tb.parse_csv(result)
76
+ assert_equal(1, tb.size)
77
+ assert_match(/baz/, tb.get_record(0)["msg"])
78
+ ###
79
+ system("svn log --xml > log.xml")
80
+ FileUtils.rmtree('.svn')
81
+ Tb::Cmd.main_svn_log(['-o', o="o.csv", '--svn-log-xml=log.xml'])
82
+ result = File.read(o)
83
+ tb = Tb.parse_csv(result)
84
+ assert_equal(1, tb.size)
85
+ assert_match(/baz/, tb.get_record(0)["msg"])
86
+ end
87
+ end
@@ -140,4 +140,18 @@ class TestTbCmdToCSV < Test::Unit::TestCase
140
140
  End
141
141
  end
142
142
 
143
+ def test_output_extension
144
+ File.open(i="i.tsv", "w") {|f| f << <<-"End".gsub(/^[ \t]+/, '') }
145
+ a\tb\tc
146
+ 0\t1\t2
147
+ 4\t5\t6
148
+ End
149
+ Tb::Cmd.main_to_csv(['-o', o="o.json", i])
150
+ assert_equal(<<-"End".gsub(/^[ \t]+/, ''), File.read(o))
151
+ a,b,c
152
+ 0,1,2
153
+ 4,5,6
154
+ End
155
+ end
156
+
143
157
  end
@@ -26,18 +26,33 @@ class TestTbCmdUtil < Test::Unit::TestCase
26
26
  end
27
27
 
28
28
  def test_smart_cmp_value
29
- assert_equal(0, smart_cmp_value(0) <=> smart_cmp_value(0))
30
- assert_equal(1, smart_cmp_value(10) <=> smart_cmp_value(0))
31
- assert_equal(-1, smart_cmp_value(-10) <=> smart_cmp_value(0))
32
- assert_equal(0, smart_cmp_value("a") <=> smart_cmp_value("a"))
33
- assert_equal(1, smart_cmp_value("z") <=> smart_cmp_value("a"))
34
- assert_equal(-1, smart_cmp_value("a") <=> smart_cmp_value("b"))
35
- assert_equal(1, smart_cmp_value("08") <=> smart_cmp_value("7"))
36
- assert_raise(ArgumentError) { smart_cmp_value(Object.new) }
29
+ assert_equal(0, Tb::Func.smart_cmp_value(0) <=> Tb::Func.smart_cmp_value(0))
30
+ assert_equal(1, Tb::Func.smart_cmp_value(10) <=> Tb::Func.smart_cmp_value(0))
31
+ assert_equal(-1, Tb::Func.smart_cmp_value(-10) <=> Tb::Func.smart_cmp_value(0))
32
+ assert_equal(0, Tb::Func.smart_cmp_value("a") <=> Tb::Func.smart_cmp_value("a"))
33
+ assert_equal(1, Tb::Func.smart_cmp_value("z") <=> Tb::Func.smart_cmp_value("a"))
34
+ assert_equal(-1, Tb::Func.smart_cmp_value("a") <=> Tb::Func.smart_cmp_value("b"))
35
+ assert_equal(1, Tb::Func.smart_cmp_value("08") <=> Tb::Func.smart_cmp_value("7"))
36
+ assert_raise(ArgumentError) { Tb::Func.smart_cmp_value(Object.new) }
37
37
  end
38
38
 
39
- def test_conv_to_numeric
40
- assert_raise(ArgumentError) { conv_to_numeric("foo") }
39
+ def test_parse_aggregator_spec2
40
+ assert_raise(ArgumentError) { parse_aggregator_spec2("foo") }
41
+ end
42
+
43
+ def test_with_output_preserve_mtime
44
+ Dir.mktmpdir {|d|
45
+ fn = "#{d}/a"
46
+ File.open(fn, "w") {|f| f.print "foo" }
47
+ t0 = Time.utc(2000)
48
+ File.utime(t0, t0, fn)
49
+ t1 = File.stat(fn).mtime
50
+ with_output(fn) {|f|
51
+ f.print "foo"
52
+ }
53
+ t2 = File.stat(fn).mtime
54
+ assert_equal(t1, t2)
55
+ }
41
56
  end
42
57
 
43
58
  end
@@ -65,6 +65,16 @@ class TestTbCSV < Test::Unit::TestCase
65
65
  End
66
66
  end
67
67
 
68
+ def test_generate_without_explicit_fields
69
+ t = Tb.new %w[a b], [1, 2], [3, 4]
70
+ out = t.generate_csv('')
71
+ assert_equal(<<-'End'.gsub(/^\s+/, ''), out)
72
+ a,b
73
+ 1,2
74
+ 3,4
75
+ End
76
+ end
77
+
68
78
  def test_generate_with_block
69
79
  t = Tb.new %w[a b], [1, 2], [3, 4]
70
80
  out = t.generate_csv('', ['a', 'b']) {|recids| recids.reverse }
@@ -0,0 +1,14 @@
1
+ require 'tb'
2
+ require 'test/unit'
3
+
4
+ class TestCustomCmp < Test::Unit::TestCase
5
+ def test_revcmp
6
+ cmp = lambda {|a, b| b <=> a }
7
+ v1 = Tb::CustomCmp.new(1, &cmp)
8
+ v2 = Tb::CustomCmp.new(2, &cmp)
9
+ v3 = Tb::CustomCmp.new(3, &cmp)
10
+ assert_equal(2 <=> 1, v1 <=> v2)
11
+ assert_equal(1 <=> 2, v2 <=> v1)
12
+ assert_equal(3 <=> 3, v3 <=> v3)
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ require 'tb'
2
+ require 'test/unit'
3
+
4
+ class TestCustomEq < Test::Unit::TestCase
5
+ def test_decreasing
6
+ rel = lambda {|a, b| a > b }
7
+ v1 = Tb::CustomEq.new(1, &rel)
8
+ v2 = Tb::CustomEq.new(2, &rel)
9
+ v3 = Tb::CustomEq.new(3, &rel)
10
+ assert_equal(false, v1 == v1)
11
+ assert_equal(false, v1 == v2)
12
+ assert_equal(false, v1 == v3)
13
+ assert_equal(true, v2 == v1)
14
+ assert_equal(false, v2 == v2)
15
+ assert_equal(false, v2 == v3)
16
+ assert_equal(true, v3 == v1)
17
+ assert_equal(true, v3 == v2)
18
+ assert_equal(false, v3 == v3)
19
+ end
20
+ end
@@ -173,10 +173,84 @@ class TestTbEnumerable < Test::Unit::TestCase
173
173
  }
174
174
  end
175
175
 
176
- def test_each_group_element
176
+ def test_extsort_by_map
177
+ assert_equal([20,12,13],
178
+ [10,2,3].extsort_by(:map => lambda {|v| v + 10 }) {|v| v.to_s }.to_a)
179
+ end
180
+
181
+ def test_extsort_by_unique
182
+ [
183
+ [[1,1], [2]],
184
+ [[1,2,1], [2,2]],
185
+ [[1,2,3,2,1], [2,4,3]],
186
+ [[1,1,2,2,3], [2,4,3]]
187
+ ].each {|ary, result|
188
+ [nil, 0].each {|memsize|
189
+ assert_equal(result,
190
+ ary.extsort_by(:memsize => memsize,
191
+ :unique => lambda {|x,y| x + y }) {|x| x }.to_a)
192
+ }
193
+ }
194
+ end
195
+
196
+ def test_extsort_by_unique_random
197
+ [nil, 0].each {|memsize|
198
+ 3.times {|i|
199
+ len = rand(100)
200
+ ary = []
201
+ len.times { ary << rand(100) }
202
+ h = ary.group_by {|v| v }
203
+ ary1 = h.keys.sort.map {|k| h[k].inject(&:+) }
204
+ ary2 = ary.extsort_by(:memsize => memsize,
205
+ :unique => lambda {|x, y| x + y }) {|v| v }.to_a
206
+ assert_equal(ary1, ary2)
207
+ }
208
+ }
209
+ end
210
+
211
+ def test_extsort_reduce
212
+ result = [
213
+ [:cat, 1],
214
+ [:dog, 2],
215
+ [:cat, 3],
216
+ [:dog, 1],
217
+ ].extsort_reduce(:+.to_proc) {|pair| pair }.to_a
218
+ assert_equal([[:cat, 4], [:dog, 3]], result)
219
+ end
220
+
221
+ def test_each_group_element_by_customeq
222
+ result = []
223
+ (0..9).to_a.each_group_element_by(
224
+ lambda {|v| Tb::CustomEq.new(v) {|a, b| a / 3 == b / 3 } },
225
+ lambda {|v| result << [:before, v] },
226
+ lambda {|v| result << [:body, v] },
227
+ lambda {|v| result << [:after, v] })
228
+ assert_equal(
229
+ [[:before, 0],
230
+ [:body, 0],
231
+ [:body, 1],
232
+ [:body, 2],
233
+ [:after, 2],
234
+ [:before, 3],
235
+ [:body, 3],
236
+ [:body, 4],
237
+ [:body, 5],
238
+ [:after, 5],
239
+ [:before, 6],
240
+ [:body, 6],
241
+ [:body, 7],
242
+ [:body, 8],
243
+ [:after, 8],
244
+ [:before, 9],
245
+ [:body, 9],
246
+ [:after, 9]],
247
+ result)
248
+ end
249
+
250
+ def test_each_group_element_by
177
251
  result = []
178
- (0..9).to_a.each_group_element(
179
- lambda {|a, b| a / 3 != b / 3 },
252
+ (0..9).to_a.each_group_element_by(
253
+ lambda {|v| v / 3 },
180
254
  lambda {|v| result << [:before, v] },
181
255
  lambda {|v| result << [:body, v] },
182
256
  lambda {|v| result << [:after, v] })
@@ -201,4 +275,108 @@ class TestTbEnumerable < Test::Unit::TestCase
201
275
  [:after, 9]],
202
276
  result)
203
277
  end
278
+
279
+ def test_detect_group_by
280
+ enum = (0..9).to_a
281
+ result = []
282
+ e3 = enum.detect_group_by(
283
+ lambda {|elt| result << [:before, 3, elt] },
284
+ lambda {|elt| result << [:after, 3, elt] }) {|elt|
285
+ elt / 3
286
+ }
287
+ e4 = e3.detect_group_by(
288
+ lambda {|elt| result << [:before, 4, elt] },
289
+ lambda {|elt| result << [:after, 4, elt] }) {|elt|
290
+ elt / 4
291
+ }
292
+ e4.each {|elt|
293
+ result << [:body, elt]
294
+ }
295
+ assert_equal(
296
+ [[:before, 3, 0],
297
+ [:before, 4, 0],
298
+ [:body, 0],
299
+ [:body, 1],
300
+ [:body, 2],
301
+ [:after, 3, 2],
302
+ [:before, 3, 3],
303
+ [:body, 3],
304
+ [:after, 4, 3],
305
+ [:before, 4, 4],
306
+ [:body, 4],
307
+ [:body, 5],
308
+ [:after, 3, 5],
309
+ [:before, 3, 6],
310
+ [:body, 6],
311
+ [:body, 7],
312
+ [:after, 4, 7],
313
+ [:before, 4, 8],
314
+ [:body, 8],
315
+ [:after, 3, 8],
316
+ [:before, 3, 9],
317
+ [:body, 9],
318
+ [:after, 3, 9],
319
+ [:after, 4, 9]],
320
+ result)
321
+ end
322
+
323
+ def test_detect_nested_group_by_simple
324
+ assert_equal([], [].detect_nested_group_by([]).to_a)
325
+ assert_equal([1], [1].detect_nested_group_by([]).to_a)
326
+
327
+ result = []
328
+ [].detect_nested_group_by(
329
+ [[lambda {|v| v.even? },
330
+ lambda {|v| result << [:s, v] },
331
+ lambda {|v| result << [:e, v] }]]).each {|v| result << v }
332
+ assert_equal([], result)
333
+ end
334
+
335
+ def test_detect_nested_group_by
336
+ enum = (0..9).to_a
337
+ result = []
338
+ e = enum.detect_nested_group_by(
339
+ [[lambda {|elt| elt / 3 },
340
+ lambda {|elt| result << [:before, 3, elt] },
341
+ lambda {|elt| result << [:after, 3, elt] }],
342
+ [lambda {|elt| elt / 4 },
343
+ lambda {|elt| result << [:before, 4, elt] },
344
+ lambda {|elt| result << [:after, 4, elt] }]])
345
+ e.each {|elt|
346
+ result << [:body, elt]
347
+ }
348
+ assert_equal(
349
+ [[:before, 3, 0],
350
+ [:before, 4, 0],
351
+ [:body, 0],
352
+ [:body, 1],
353
+ [:body, 2],
354
+ [:after, 4, 2],
355
+ [:after, 3, 2],
356
+ [:before, 3, 3],
357
+ [:before, 4, 3],
358
+ [:body, 3],
359
+ [:after, 4, 3],
360
+ [:before, 4, 4],
361
+ [:body, 4],
362
+ [:body, 5],
363
+ [:after, 4, 5],
364
+ [:after, 3, 5],
365
+ [:before, 3, 6],
366
+ [:before, 4, 6],
367
+ [:body, 6],
368
+ [:body, 7],
369
+ [:after, 4, 7],
370
+ [:before, 4, 8],
371
+ [:body, 8],
372
+ [:after, 4, 8],
373
+ [:after, 3, 8],
374
+ [:before, 3, 9],
375
+ [:before, 4, 9],
376
+ [:body, 9],
377
+ [:after, 4, 9],
378
+ [:after, 3, 9]],
379
+ result)
380
+ end
381
+
204
382
  end