tb 0.2 → 0.3
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.
- 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
|