tb 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +62 -50
- data/bin/tb +22 -18
- data/lib/tb.rb +35 -19
- data/lib/tb/basic.rb +85 -86
- data/lib/tb/catreader.rb +33 -116
- data/lib/tb/cmd_cat.rb +31 -27
- data/lib/tb/cmd_consecutive.rb +45 -35
- data/lib/tb/cmd_crop.rb +86 -52
- data/lib/tb/cmd_cross.rb +113 -71
- data/lib/tb/cmd_cut.rb +49 -44
- data/lib/tb/cmd_git_log.rb +193 -0
- data/lib/tb/cmd_grep.rb +43 -32
- data/lib/tb/cmd_group.rb +63 -39
- data/lib/tb/cmd_gsub.rb +53 -43
- data/lib/tb/cmd_help.rb +51 -24
- data/lib/tb/cmd_join.rb +32 -35
- data/lib/tb/cmd_ls.rb +233 -205
- data/lib/tb/cmd_mheader.rb +47 -37
- data/lib/tb/cmd_nest.rb +94 -0
- data/lib/tb/cmd_newfield.rb +29 -33
- data/lib/tb/cmd_rename.rb +40 -32
- data/lib/tb/cmd_shape.rb +31 -24
- data/lib/tb/cmd_sort.rb +46 -25
- data/lib/tb/cmd_svn_log.rb +47 -28
- data/lib/tb/cmd_tar_tvf.rb +447 -0
- data/lib/tb/cmd_to_csv.rb +60 -0
- data/lib/tb/cmd_to_json.rb +60 -0
- data/lib/tb/cmd_to_pnm.rb +48 -0
- data/lib/tb/cmd_to_pp.rb +71 -0
- data/lib/tb/cmd_to_tsv.rb +48 -0
- data/lib/tb/cmd_to_yaml.rb +52 -0
- data/lib/tb/cmd_unnest.rb +118 -0
- data/lib/tb/cmdmain.rb +24 -20
- data/lib/tb/cmdtop.rb +33 -25
- data/lib/tb/cmdutil.rb +26 -66
- data/lib/tb/csv.rb +46 -34
- data/lib/tb/enum.rb +294 -0
- data/lib/tb/enumerable.rb +198 -7
- data/lib/tb/enumerator.rb +73 -0
- data/lib/tb/fieldset.rb +27 -19
- data/lib/tb/fileenumerator.rb +365 -0
- data/lib/tb/json.rb +50 -0
- data/lib/tb/pager.rb +6 -6
- data/lib/tb/pairs.rb +227 -0
- data/lib/tb/pnm.rb +23 -22
- data/lib/tb/reader.rb +52 -49
- data/lib/tb/record.rb +48 -19
- data/lib/tb/revcmp.rb +38 -0
- data/lib/tb/ropen.rb +74 -57
- data/lib/tb/search.rb +25 -21
- data/lib/tb/tsv.rb +31 -34
- data/sample/excel2csv +24 -20
- data/sample/poi-xls2csv.rb +24 -20
- data/sample/poi-xls2csv.sh +22 -18
- data/sample/tbplot +185 -127
- data/test-all-cov.rb +3 -3
- data/test-all.rb +1 -1
- data/test/test_basic.rb +26 -10
- data/test/test_catreader.rb +7 -6
- data/test/test_cmd_cat.rb +32 -0
- data/test/test_cmd_consecutive.rb +10 -0
- data/test/test_cmd_crop.rb +4 -4
- data/test/test_cmd_cross.rb +16 -4
- data/test/test_cmd_git_log.rb +46 -0
- data/test/test_cmd_help.rb +17 -12
- data/test/test_cmd_join.rb +21 -1
- data/test/test_cmd_ls.rb +3 -4
- data/test/test_cmd_mheader.rb +17 -11
- data/test/test_cmd_nest.rb +49 -0
- data/test/test_cmd_sort.rb +15 -0
- data/test/test_cmd_tar_tvf.rb +281 -0
- data/test/{test_cmd_csv.rb → test_cmd_to_csv.rb} +35 -21
- data/test/{test_cmd_json.rb → test_cmd_to_json.rb} +31 -3
- data/test/{test_cmd_pnm.rb → test_cmd_to_pnm.rb} +2 -2
- data/test/{test_cmd_pp.rb → test_cmd_to_pp.rb} +4 -4
- data/test/{test_cmd_tsv.rb → test_cmd_to_tsv.rb} +4 -4
- data/test/{test_cmd_yaml.rb → test_cmd_to_yaml.rb} +3 -3
- data/test/test_cmd_unnest.rb +89 -0
- data/test/test_cmdtty.rb +19 -13
- data/test/test_enumerable.rb +83 -1
- data/test/test_fileenumerator.rb +265 -0
- data/test/test_json.rb +15 -0
- data/test/test_pager.rb +3 -4
- data/test/test_pairs.rb +122 -0
- data/test/test_pnm.rb +24 -24
- data/test/test_reader.rb +35 -13
- data/test/test_revcmp.rb +10 -0
- data/test/test_tbenum.rb +173 -0
- metadata +51 -23
- data/lib/tb/cmd_csv.rb +0 -42
- data/lib/tb/cmd_json.rb +0 -60
- data/lib/tb/cmd_pnm.rb +0 -43
- data/lib/tb/cmd_pp.rb +0 -70
- data/lib/tb/cmd_tsv.rb +0 -43
- data/lib/tb/cmd_yaml.rb +0 -47
data/lib/tb/cmdmain.rb
CHANGED
@@ -1,26 +1,30 @@
|
|
1
|
-
# Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
|
1
|
+
# Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
|
2
2
|
#
|
3
3
|
# Redistribution and use in source and binary forms, with or without
|
4
|
-
# modification, are permitted provided that the following conditions
|
4
|
+
# modification, are permitted provided that the following conditions
|
5
|
+
# are met:
|
5
6
|
#
|
6
|
-
# 1. Redistributions of source code must retain the above copyright
|
7
|
-
# list of conditions and the following disclaimer.
|
8
|
-
# 2. Redistributions in binary form must reproduce the above
|
9
|
-
# this list of conditions and the following
|
10
|
-
# and/or other materials provided
|
11
|
-
#
|
12
|
-
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above
|
10
|
+
# copyright notice, this list of conditions and the following
|
11
|
+
# disclaimer in the documentation and/or other materials provided
|
12
|
+
# with the distribution.
|
13
|
+
# 3. The name of the author may not be used to endorse or promote
|
14
|
+
# products derived from this software without specific prior
|
15
|
+
# written permission.
|
13
16
|
#
|
14
|
-
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
15
|
-
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
16
|
-
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
17
|
-
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# IN
|
23
|
-
# OF
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
18
|
+
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
21
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
23
|
+
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
25
|
+
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
26
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
27
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
24
28
|
|
25
29
|
def (Tb::Cmd).main_body(argv)
|
26
30
|
subcommand = argv.shift
|
@@ -39,7 +43,7 @@ end
|
|
39
43
|
def (Tb::Cmd).main(argv)
|
40
44
|
main_body(argv)
|
41
45
|
rescue SystemExit
|
42
|
-
|
46
|
+
$stderr.puts $!.message if $!.message != 'exit'
|
43
47
|
raise
|
44
48
|
end
|
45
49
|
|
data/lib/tb/cmdtop.rb
CHANGED
@@ -1,26 +1,30 @@
|
|
1
|
-
# Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
|
1
|
+
# Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
|
2
2
|
#
|
3
3
|
# Redistribution and use in source and binary forms, with or without
|
4
|
-
# modification, are permitted provided that the following conditions
|
4
|
+
# modification, are permitted provided that the following conditions
|
5
|
+
# are met:
|
5
6
|
#
|
6
|
-
# 1. Redistributions of source code must retain the above copyright
|
7
|
-
# list of conditions and the following disclaimer.
|
8
|
-
# 2. Redistributions in binary form must reproduce the above
|
9
|
-
# this list of conditions and the following
|
10
|
-
# and/or other materials provided
|
11
|
-
#
|
12
|
-
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above
|
10
|
+
# copyright notice, this list of conditions and the following
|
11
|
+
# disclaimer in the documentation and/or other materials provided
|
12
|
+
# with the distribution.
|
13
|
+
# 3. The name of the author may not be used to endorse or promote
|
14
|
+
# products derived from this software without specific prior
|
15
|
+
# written permission.
|
13
16
|
#
|
14
|
-
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
15
|
-
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
16
|
-
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
17
|
-
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# IN
|
23
|
-
# OF
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
18
|
+
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
21
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
23
|
+
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
25
|
+
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
26
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
27
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
24
28
|
|
25
29
|
require 'tb'
|
26
30
|
require 'optparse'
|
@@ -31,12 +35,12 @@ require 'enumerator'
|
|
31
35
|
require 'tb/pager'
|
32
36
|
require 'tb/cmdutil'
|
33
37
|
require 'tb/cmd_help'
|
34
|
-
require 'tb/
|
35
|
-
require 'tb/
|
36
|
-
require 'tb/
|
37
|
-
require 'tb/
|
38
|
-
require 'tb/
|
39
|
-
require 'tb/
|
38
|
+
require 'tb/cmd_to_csv'
|
39
|
+
require 'tb/cmd_to_tsv'
|
40
|
+
require 'tb/cmd_to_pnm'
|
41
|
+
require 'tb/cmd_to_json'
|
42
|
+
require 'tb/cmd_to_yaml'
|
43
|
+
require 'tb/cmd_to_pp'
|
40
44
|
require 'tb/cmd_grep'
|
41
45
|
require 'tb/cmd_gsub'
|
42
46
|
require 'tb/cmd_sort'
|
@@ -48,11 +52,15 @@ require 'tb/cmd_join'
|
|
48
52
|
require 'tb/cmd_consecutive'
|
49
53
|
require 'tb/cmd_group'
|
50
54
|
require 'tb/cmd_cross'
|
55
|
+
require 'tb/cmd_nest'
|
56
|
+
require 'tb/cmd_unnest'
|
51
57
|
require 'tb/cmd_shape'
|
52
58
|
require 'tb/cmd_mheader'
|
53
59
|
require 'tb/cmd_crop'
|
54
60
|
require 'tb/cmd_ls'
|
61
|
+
require 'tb/cmd_tar_tvf'
|
55
62
|
require 'tb/cmd_svn_log'
|
63
|
+
require 'tb/cmd_git_log'
|
56
64
|
require 'tb/cmdmain'
|
57
65
|
|
58
66
|
Tb::Cmd.init_option
|
data/lib/tb/cmdutil.rb
CHANGED
@@ -1,26 +1,30 @@
|
|
1
|
-
# Copyright (C) 2011 Tanaka Akira <akr@fsij.org>
|
1
|
+
# Copyright (C) 2011-2012 Tanaka Akira <akr@fsij.org>
|
2
2
|
#
|
3
3
|
# Redistribution and use in source and binary forms, with or without
|
4
|
-
# modification, are permitted provided that the following conditions
|
4
|
+
# modification, are permitted provided that the following conditions
|
5
|
+
# are met:
|
5
6
|
#
|
6
|
-
# 1. Redistributions of source code must retain the above copyright
|
7
|
-
# list of conditions and the following disclaimer.
|
8
|
-
# 2. Redistributions in binary form must reproduce the above
|
9
|
-
# this list of conditions and the following
|
10
|
-
# and/or other materials provided
|
11
|
-
#
|
12
|
-
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above
|
10
|
+
# copyright notice, this list of conditions and the following
|
11
|
+
# disclaimer in the documentation and/or other materials provided
|
12
|
+
# with the distribution.
|
13
|
+
# 3. The name of the author may not be used to endorse or promote
|
14
|
+
# products derived from this software without specific prior
|
15
|
+
# written permission.
|
13
16
|
#
|
14
|
-
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
15
|
-
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
16
|
-
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
17
|
-
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
# IN
|
23
|
-
# OF
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
18
|
+
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
21
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
23
|
+
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
25
|
+
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
26
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
27
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
24
28
|
|
25
29
|
class Tb::Cmd
|
26
30
|
@subcommands = []
|
@@ -245,52 +249,8 @@ def split_csv_argument(arg)
|
|
245
249
|
return []
|
246
250
|
end
|
247
251
|
|
248
|
-
def build_table(tblreader)
|
249
|
-
arys = []
|
250
|
-
tblreader.each {|ary|
|
251
|
-
arys << ary
|
252
|
-
}
|
253
|
-
header = tblreader.header
|
254
|
-
tbl = Tb.new(header)
|
255
|
-
arys.each {|ary|
|
256
|
-
ary << nil while ary.length < header.length
|
257
|
-
tbl.insert_values header, ary
|
258
|
-
}
|
259
|
-
tbl
|
260
|
-
end
|
261
|
-
|
262
|
-
def load_table(filename)
|
263
|
-
tablereader_open(filename) {|tblreader|
|
264
|
-
build_table(tblreader)
|
265
|
-
}
|
266
|
-
end
|
267
|
-
|
268
252
|
def tablereader_open(filename, &b)
|
269
|
-
Tb
|
270
|
-
end
|
271
|
-
|
272
|
-
def with_table_stream_output
|
273
|
-
with_output {|out|
|
274
|
-
Tb.csv_stream_output(out) {|gen|
|
275
|
-
def gen.output_header(header)
|
276
|
-
self << header if !Tb::Cmd.opt_N
|
277
|
-
end
|
278
|
-
yield gen
|
279
|
-
}
|
280
|
-
}
|
281
|
-
end
|
282
|
-
|
283
|
-
def tbl_generate_csv(tbl, out)
|
284
|
-
if Tb::Cmd.opt_N
|
285
|
-
header = tbl.list_fields
|
286
|
-
Tb.csv_stream_output(out) {|gen|
|
287
|
-
tbl.each {|rec|
|
288
|
-
gen << rec.values_at(*header)
|
289
|
-
}
|
290
|
-
}
|
291
|
-
else
|
292
|
-
tbl.generate_csv(out)
|
293
|
-
end
|
253
|
+
Tb.open_reader(filename, {:numeric=>Tb::Cmd.opt_N}, &b)
|
294
254
|
end
|
295
255
|
|
296
256
|
def tbl_generate_tsv(tbl, out)
|
@@ -317,11 +277,11 @@ def with_output
|
|
317
277
|
ensure
|
318
278
|
File.unlink tmp if File.exist? tmp
|
319
279
|
end
|
320
|
-
elsif
|
280
|
+
elsif $stdout.tty? && !Tb::Cmd.opt_no_pager
|
321
281
|
Tb::Pager.open {|pager|
|
322
282
|
yield pager
|
323
283
|
}
|
324
284
|
else
|
325
|
-
yield
|
285
|
+
yield $stdout
|
326
286
|
end
|
327
287
|
end
|
data/lib/tb/csv.rb
CHANGED
@@ -1,28 +1,32 @@
|
|
1
1
|
# lib/tb/csv.rb - CSV related fetures for table library
|
2
2
|
#
|
3
|
-
# Copyright (C) 2010-
|
3
|
+
# Copyright (C) 2010-2012 Tanaka Akira <akr@fsij.org>
|
4
4
|
#
|
5
5
|
# Redistribution and use in source and binary forms, with or without
|
6
|
-
# modification, are permitted provided that the following conditions
|
6
|
+
# modification, are permitted provided that the following conditions
|
7
|
+
# are met:
|
7
8
|
#
|
8
|
-
# 1. Redistributions of source code must retain the above copyright
|
9
|
-
# list of conditions and the following disclaimer.
|
10
|
-
# 2. Redistributions in binary form must reproduce the above
|
11
|
-
# this list of conditions and the following
|
12
|
-
# and/or other materials provided
|
13
|
-
#
|
14
|
-
#
|
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.
|
15
18
|
#
|
16
|
-
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
17
|
-
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
-
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
-
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# IN
|
25
|
-
# OF
|
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.
|
26
30
|
|
27
31
|
require 'csv'
|
28
32
|
|
@@ -38,22 +42,18 @@ class Tb
|
|
38
42
|
}
|
39
43
|
aa = yield aa if block_given?
|
40
44
|
if header_fields.empty?
|
41
|
-
reader = Tb::Reader.new(aa)
|
42
|
-
|
43
|
-
reader.each {|ary|
|
44
|
-
arys << ary
|
45
|
-
}
|
46
|
-
header = reader.header
|
45
|
+
reader = Tb::Reader.new {|body| body.call(aa) }
|
46
|
+
reader.to_tb
|
47
47
|
else
|
48
48
|
header = header_fields
|
49
49
|
arys = aa
|
50
|
+
t = Tb.new(header)
|
51
|
+
arys.each {|ary|
|
52
|
+
ary << nil while ary.length < header.length
|
53
|
+
t.insert_values header, ary
|
54
|
+
}
|
55
|
+
t
|
50
56
|
end
|
51
|
-
t = Tb.new(header)
|
52
|
-
arys.each {|ary|
|
53
|
-
ary << nil while ary.length < header.length
|
54
|
-
t.insert_values header, ary
|
55
|
-
}
|
56
|
-
t
|
57
57
|
end
|
58
58
|
|
59
59
|
def Tb.csv_stream_input(csv, &b)
|
@@ -102,9 +102,6 @@ class Tb
|
|
102
102
|
end
|
103
103
|
nil
|
104
104
|
end
|
105
|
-
|
106
|
-
def close
|
107
|
-
end
|
108
105
|
end
|
109
106
|
|
110
107
|
def Tb.csv_stream_output(out)
|
@@ -125,6 +122,21 @@ class Tb
|
|
125
122
|
end
|
126
123
|
end
|
127
124
|
|
125
|
+
def Tb.csv_encode_row(ary)
|
126
|
+
require 'csv'
|
127
|
+
if defined? CSV::Writer
|
128
|
+
# Ruby 1.8
|
129
|
+
out = ''
|
130
|
+
CSV::Writer.generate(out) {|csvgen|
|
131
|
+
csvgen << ary
|
132
|
+
}
|
133
|
+
out
|
134
|
+
else
|
135
|
+
# Ruby 1.9
|
136
|
+
ary.to_csv
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
128
140
|
# :call-seq:
|
129
141
|
# generate_csv(out='', fields=nil) {|recordids| modified_recordids }
|
130
142
|
# generate_csv(out='', fields=nil)
|
data/lib/tb/enum.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
# Copyright (C) 2012 Tanaka Akira <akr@fsij.org>
|
2
|
+
#
|
3
|
+
# Redistribution and use in source and binary forms, with or without
|
4
|
+
# modification, are permitted provided that the following conditions
|
5
|
+
# are met:
|
6
|
+
#
|
7
|
+
# 1. Redistributions of source code must retain the above copyright
|
8
|
+
# notice, this list of conditions and the following disclaimer.
|
9
|
+
# 2. Redistributions in binary form must reproduce the above
|
10
|
+
# copyright notice, this list of conditions and the following
|
11
|
+
# disclaimer in the documentation and/or other materials provided
|
12
|
+
# with the distribution.
|
13
|
+
# 3. The name of the author may not be used to endorse or promote
|
14
|
+
# products derived from this software without specific prior
|
15
|
+
# written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
|
18
|
+
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
21
|
+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
23
|
+
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
25
|
+
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
26
|
+
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
27
|
+
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
28
|
+
|
29
|
+
module Tb::Enum
|
30
|
+
include Enumerable
|
31
|
+
|
32
|
+
def with_header(&header_proc)
|
33
|
+
Enumerator.new {|y|
|
34
|
+
header_and_each(header_proc) {|pairs|
|
35
|
+
y.yield pairs
|
36
|
+
}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def with_cumulative_header(&header_proc)
|
41
|
+
Enumerator.new {|y|
|
42
|
+
hset = {}
|
43
|
+
internal_header_proc = lambda {|header0|
|
44
|
+
if header0
|
45
|
+
header0.each {|f|
|
46
|
+
hset[f] = true
|
47
|
+
}
|
48
|
+
end
|
49
|
+
header_proc.call(header0) if header_proc
|
50
|
+
}
|
51
|
+
header_and_each(internal_header_proc) {|pairs|
|
52
|
+
pairs.each {|f, v|
|
53
|
+
if !hset[f]
|
54
|
+
hset[f] = true
|
55
|
+
end
|
56
|
+
}
|
57
|
+
y.yield [pairs, hset.keys.freeze]
|
58
|
+
}
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
def cat(*ers, &b)
|
63
|
+
ers = [self, *ers]
|
64
|
+
rec = lambda {|y, header|
|
65
|
+
if ers.empty?
|
66
|
+
if header
|
67
|
+
y.set_header header
|
68
|
+
end
|
69
|
+
else
|
70
|
+
last_e = ers.pop
|
71
|
+
last_e.with_header {|last_e_header|
|
72
|
+
if last_e_header && header
|
73
|
+
header = last_e_header | header
|
74
|
+
else
|
75
|
+
header = nil
|
76
|
+
end
|
77
|
+
rec.call(y, header)
|
78
|
+
}.each {|v|
|
79
|
+
y.yield v
|
80
|
+
}
|
81
|
+
end
|
82
|
+
}
|
83
|
+
er = Tb::Enumerator.new {|y|
|
84
|
+
rec.call(y, [])
|
85
|
+
}
|
86
|
+
if block_given?
|
87
|
+
er.each(&b)
|
88
|
+
else
|
89
|
+
er
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# creates a new Tb::Enumerator object which have
|
94
|
+
# new field named by _field_ with the value returned by the block.
|
95
|
+
#
|
96
|
+
# t1 = Tb.new %w[a b], [1, 2], [3, 4]
|
97
|
+
# p t1.newfield("x") {|row| row["a"] + row["b"] + 100 }.to_a
|
98
|
+
# #=> [#<Tb::Pairs: "x"=>103, "a"=>1, "b"=>2>,
|
99
|
+
# # #<Tb::Pairs: "x"=>107, "a"=>3, "b"=>4>]
|
100
|
+
#
|
101
|
+
def newfield(field)
|
102
|
+
Tb::Enumerator.new {|y|
|
103
|
+
self.with_header {|header|
|
104
|
+
if header
|
105
|
+
y.set_header(Tb::FieldSet.normalize([field, *header]))
|
106
|
+
end
|
107
|
+
}.each {|row|
|
108
|
+
keys = row.keys
|
109
|
+
keys = Tb::FieldSet.normalize([field, *keys])
|
110
|
+
vals = row.values
|
111
|
+
vals = [yield(row), *vals]
|
112
|
+
y << Tb::Pairs.new(keys.zip(vals))
|
113
|
+
}
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
# :call-seq:
|
118
|
+
# table1.natjoin2(table2, missing_value=nil, retain_left=false, retain_right=false)
|
119
|
+
def natjoin2(tbl2, missing_value=nil, retain_left=false, retain_right=false)
|
120
|
+
Tb::Enumerator.new {|y|
|
121
|
+
tbl1 = self
|
122
|
+
header1 = header2 = nil
|
123
|
+
sorted_tbl2 = nil
|
124
|
+
common_header = nil
|
125
|
+
total_header = nil
|
126
|
+
sorted_tbl1 = tbl1.with_header {|h1|
|
127
|
+
header1 = h1
|
128
|
+
sorted_tbl2 = tbl2.with_header {|h2|
|
129
|
+
header2 = h2
|
130
|
+
common_header = header1 & header2
|
131
|
+
total_header = header1 | header2
|
132
|
+
y.set_header total_header
|
133
|
+
}.lazy_map {|pairs|
|
134
|
+
[common_header.map {|f| pairs[f] }, pairs]
|
135
|
+
}.extsort_by {|cv, pairs| cv }.to_fileenumerator
|
136
|
+
}.lazy_map {|pairs|
|
137
|
+
[common_header.map {|f| pairs[f] }, pairs]
|
138
|
+
}.extsort_by {|cv, pairs| cv }.to_fileenumerator
|
139
|
+
sorted_tbl1.open_reader {|t1|
|
140
|
+
sorted_tbl2.open_reader {|t2|
|
141
|
+
t1_eof = t2_eof = false
|
142
|
+
while true
|
143
|
+
begin
|
144
|
+
cv1, pairs1 = t1.peek
|
145
|
+
rescue StopIteration
|
146
|
+
t1_eof = true
|
147
|
+
end
|
148
|
+
begin
|
149
|
+
cv2, pairs2 = t2.peek
|
150
|
+
rescue StopIteration
|
151
|
+
t2_eof = true
|
152
|
+
end
|
153
|
+
break if t1_eof || t2_eof
|
154
|
+
cmp = cv1 <=> cv2
|
155
|
+
if cmp < 0
|
156
|
+
t1.subeach_by {|_cv1, _| _cv1 }.each {|_, _pairs1|
|
157
|
+
if retain_left
|
158
|
+
h = {}
|
159
|
+
total_header.each {|f|
|
160
|
+
h[f] = missing_value if !_pairs1.has_key?(f)
|
161
|
+
}
|
162
|
+
y.yield _pairs1.merge(h)
|
163
|
+
end
|
164
|
+
}
|
165
|
+
elsif 0 < cmp
|
166
|
+
t2.subeach_by {|_cv2, _| _cv2 }.each {|_, _pairs2|
|
167
|
+
if retain_right
|
168
|
+
h = {}
|
169
|
+
total_header.each {|f|
|
170
|
+
h[f] = missing_value if !_pairs2.has_key?(f)
|
171
|
+
}
|
172
|
+
y.yield _pairs2.merge(h)
|
173
|
+
end
|
174
|
+
}
|
175
|
+
else
|
176
|
+
t2_pos = t2.pos
|
177
|
+
t1.subeach_by {|_cv1, _| _cv1 }.each {|_, _pairs1|
|
178
|
+
t2.pos = t2_pos
|
179
|
+
t2.subeach_by {|_cv2, _| _cv2 }.each {|_, _pairs2|
|
180
|
+
pairs = {}
|
181
|
+
_pairs1.each {|f, v| pairs[f] = v }
|
182
|
+
_pairs2.each {|f, v| pairs[f] = v if !pairs.has_key?(f) }
|
183
|
+
y.yield(pairs)
|
184
|
+
}
|
185
|
+
}
|
186
|
+
end
|
187
|
+
end
|
188
|
+
begin
|
189
|
+
cv1, pairs1 = t1.next
|
190
|
+
if retain_left
|
191
|
+
h = {}
|
192
|
+
total_header.each {|f|
|
193
|
+
h[f] = missing_value if !pairs1.has_key?(f)
|
194
|
+
}
|
195
|
+
y.yield pairs1.merge(h)
|
196
|
+
end
|
197
|
+
rescue StopIteration
|
198
|
+
end
|
199
|
+
begin
|
200
|
+
cv2, pairs2 = t2.next
|
201
|
+
if retain_right
|
202
|
+
h = {}
|
203
|
+
total_header.each {|f|
|
204
|
+
h[f] = missing_value if !pairs2.has_key?(f)
|
205
|
+
}
|
206
|
+
y.yield pairs2.merge(h)
|
207
|
+
end
|
208
|
+
rescue StopIteration
|
209
|
+
end
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
end
|
214
|
+
|
215
|
+
# :call-seq:
|
216
|
+
# table1.natjoin2_outer(table2, missing=nil, retain_left=true, retain_right=true)
|
217
|
+
def natjoin2_outer(tbl2, missing_value=nil, retain_left=true, retain_right=true)
|
218
|
+
natjoin2(tbl2, missing_value, retain_left, retain_right)
|
219
|
+
end
|
220
|
+
|
221
|
+
def to_tb
|
222
|
+
tb = Tb.new
|
223
|
+
self.each {|pairs|
|
224
|
+
pairs.each {|k, v|
|
225
|
+
unless tb.has_field? k
|
226
|
+
tb.define_field(k)
|
227
|
+
end
|
228
|
+
}
|
229
|
+
tb.insert pairs
|
230
|
+
}
|
231
|
+
tb
|
232
|
+
end
|
233
|
+
|
234
|
+
def write_to_csv(io, with_header=true)
|
235
|
+
stream = nil
|
236
|
+
header = []
|
237
|
+
fgen = fnew = nil
|
238
|
+
self.with_cumulative_header {|header0|
|
239
|
+
if !with_header
|
240
|
+
stream = true
|
241
|
+
elsif header0
|
242
|
+
stream = true
|
243
|
+
io.puts Tb.csv_encode_row(header0)
|
244
|
+
else
|
245
|
+
stream = false
|
246
|
+
fgen, fnew = Tb::FileEnumerator.gen_new
|
247
|
+
end
|
248
|
+
}.each {|pairs, header1|
|
249
|
+
pairs = Tb::Pairs.new(pairs) unless pairs.respond_to? :has_key?
|
250
|
+
header = header1
|
251
|
+
if stream
|
252
|
+
fs = header.dup
|
253
|
+
while !fs.empty? && !pairs.has_key?(fs.last)
|
254
|
+
fs.pop
|
255
|
+
end
|
256
|
+
ary = fs.map {|f| pairs[f] }
|
257
|
+
io.puts Tb.csv_encode_row(ary)
|
258
|
+
else
|
259
|
+
fgen.call Tb::Pairs.new(pairs)
|
260
|
+
end
|
261
|
+
}
|
262
|
+
if !stream
|
263
|
+
if with_header
|
264
|
+
io.puts Tb.csv_encode_row(header)
|
265
|
+
end
|
266
|
+
fnew.call.each {|pairs|
|
267
|
+
fs = header.dup
|
268
|
+
while !fs.empty? && !pairs.has_key?(fs.last)
|
269
|
+
fs.pop
|
270
|
+
end
|
271
|
+
ary = fs.map {|f| pairs[f] }
|
272
|
+
io.puts Tb.csv_encode_row(ary)
|
273
|
+
}
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def extsort_by(opts={}, &cmpvalue_from)
|
278
|
+
Tb::Enumerator.new {|ty|
|
279
|
+
header = []
|
280
|
+
er = Enumerator.new {|y|
|
281
|
+
self.with_cumulative_header {|header0|
|
282
|
+
header = header0 if header0
|
283
|
+
}.each {|pairs, header1|
|
284
|
+
header = header1
|
285
|
+
y.yield pairs
|
286
|
+
}
|
287
|
+
ty.set_header header
|
288
|
+
}
|
289
|
+
er.extsort_by(opts, &cmpvalue_from).each {|pairs|
|
290
|
+
ty.yield pairs
|
291
|
+
}
|
292
|
+
}
|
293
|
+
end
|
294
|
+
end
|