tb 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/README +156 -5
  2. data/bin/tb +2 -1110
  3. data/lib/tb.rb +4 -2
  4. data/lib/tb/catreader.rb +131 -0
  5. data/lib/tb/cmd_cat.rb +65 -0
  6. data/lib/tb/cmd_consecutive.rb +79 -0
  7. data/lib/tb/cmd_crop.rb +105 -0
  8. data/lib/tb/cmd_cross.rb +119 -0
  9. data/lib/tb/cmd_csv.rb +42 -0
  10. data/lib/tb/cmd_cut.rb +77 -0
  11. data/lib/tb/cmd_grep.rb +76 -0
  12. data/lib/tb/cmd_group.rb +82 -0
  13. data/lib/tb/cmd_gsub.rb +77 -0
  14. data/lib/tb/cmd_help.rb +98 -0
  15. data/lib/tb/cmd_join.rb +81 -0
  16. data/lib/tb/cmd_json.rb +60 -0
  17. data/lib/tb/cmd_ls.rb +273 -0
  18. data/lib/tb/cmd_mheader.rb +77 -0
  19. data/lib/tb/cmd_newfield.rb +59 -0
  20. data/lib/tb/cmd_pnm.rb +43 -0
  21. data/lib/tb/cmd_pp.rb +70 -0
  22. data/lib/tb/cmd_rename.rb +58 -0
  23. data/lib/tb/cmd_shape.rb +67 -0
  24. data/lib/tb/cmd_sort.rb +58 -0
  25. data/lib/tb/cmd_svn_log.rb +158 -0
  26. data/lib/tb/cmd_tsv.rb +43 -0
  27. data/lib/tb/cmd_yaml.rb +47 -0
  28. data/lib/tb/cmdmain.rb +45 -0
  29. data/lib/tb/cmdtop.rb +58 -0
  30. data/lib/tb/cmdutil.rb +327 -0
  31. data/lib/tb/csv.rb +30 -6
  32. data/lib/tb/fieldset.rb +39 -41
  33. data/lib/tb/pager.rb +132 -0
  34. data/lib/tb/pnm.rb +357 -0
  35. data/lib/tb/reader.rb +18 -128
  36. data/lib/tb/record.rb +3 -3
  37. data/lib/tb/ropen.rb +70 -0
  38. data/lib/tb/{pathfinder.rb → search.rb} +69 -34
  39. data/lib/tb/tsv.rb +29 -1
  40. data/sample/colors.ppm +0 -0
  41. data/sample/gradation.pgm +0 -0
  42. data/sample/langs.csv +46 -0
  43. data/sample/tbplot +293 -0
  44. data/test-all-cov.rb +65 -0
  45. data/test-all.rb +5 -0
  46. data/test/test_basic.rb +99 -2
  47. data/test/test_catreader.rb +27 -0
  48. data/test/test_cmd_cat.rb +118 -0
  49. data/test/test_cmd_consecutive.rb +90 -0
  50. data/test/test_cmd_crop.rb +101 -0
  51. data/test/test_cmd_cross.rb +113 -0
  52. data/test/test_cmd_csv.rb +129 -0
  53. data/test/test_cmd_cut.rb +100 -0
  54. data/test/test_cmd_grep.rb +89 -0
  55. data/test/test_cmd_group.rb +181 -0
  56. data/test/test_cmd_gsub.rb +103 -0
  57. data/test/test_cmd_help.rb +190 -0
  58. data/test/test_cmd_join.rb +197 -0
  59. data/test/test_cmd_json.rb +75 -0
  60. data/test/test_cmd_ls.rb +203 -0
  61. data/test/test_cmd_mheader.rb +86 -0
  62. data/test/test_cmd_newfield.rb +63 -0
  63. data/test/test_cmd_pnm.rb +35 -0
  64. data/test/test_cmd_pp.rb +62 -0
  65. data/test/test_cmd_rename.rb +91 -0
  66. data/test/test_cmd_shape.rb +50 -0
  67. data/test/test_cmd_sort.rb +105 -0
  68. data/test/test_cmd_tsv.rb +67 -0
  69. data/test/test_cmd_yaml.rb +55 -0
  70. data/test/test_cmdtty.rb +154 -0
  71. data/test/test_cmdutil.rb +43 -0
  72. data/test/test_csv.rb +10 -0
  73. data/test/test_fieldset.rb +42 -0
  74. data/test/test_pager.rb +142 -0
  75. data/test/test_pnm.rb +374 -0
  76. data/test/test_reader.rb +147 -0
  77. data/test/test_record.rb +49 -0
  78. data/test/test_search.rb +575 -0
  79. data/test/test_tsv.rb +7 -0
  80. metadata +108 -5
  81. data/lib/tb/qtsv.rb +0 -93
@@ -0,0 +1,42 @@
1
+ # Copyright (C) 2011 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 are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ Tb::Cmd.subcommands << 'csv'
26
+
27
+ def (Tb::Cmd).op_csv
28
+ op = OptionParser.new
29
+ op.banner = 'Usage: tb csv [OPTS] [TABLE ...]'
30
+ define_common_option(op, "hNo", "--no-pager")
31
+ op
32
+ end
33
+
34
+ def (Tb::Cmd).main_csv(argv)
35
+ op_csv.parse!(argv)
36
+ exit_if_help('csv')
37
+ argv = ['-'] if argv.empty?
38
+ tbl = Tb::CatReader.open(argv, Tb::Cmd.opt_N) {|creader| build_table(creader) }
39
+ with_output {|out|
40
+ tbl_generate_csv(tbl, out)
41
+ }
42
+ end
@@ -0,0 +1,77 @@
1
+ # Copyright (C) 2011 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 are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ Tb::Cmd.subcommands << 'cut'
26
+
27
+ Tb::Cmd.default_option[:opt_cut_v] = nil
28
+
29
+ def (Tb::Cmd).op_cut
30
+ op = OptionParser.new
31
+ op.banner = 'Usage: tb cut [OPTS] FIELD,... [TABLE]'
32
+ define_common_option(op, "hNo", "--no-pager")
33
+ op.def_option('-v', 'invert match') { Tb::Cmd.opt_cut_v = true }
34
+ op
35
+ end
36
+
37
+ def (Tb::Cmd).main_cut(argv)
38
+ op_cut.parse!(argv)
39
+ exit_if_help('cut')
40
+ err('no fields given.') if argv.empty?
41
+ fs = split_field_list_argument(argv.shift)
42
+ argv = ['-'] if argv.empty?
43
+ Tb::CatReader.open(argv, Tb::Cmd.opt_N) {|tblreader|
44
+ if Tb::Cmd.opt_cut_v
45
+ h = {}
46
+ fs.each {|f| h[tblreader.index_from_field(f)] = true }
47
+ header = nil
48
+ if !Tb::Cmd.opt_N
49
+ header = []
50
+ tblreader.header.each_with_index {|f, i|
51
+ header << f if !h[i]
52
+ }
53
+ end
54
+ with_table_stream_output {|gen|
55
+ gen.output_header(header)
56
+ tblreader.each {|ary|
57
+ values = []
58
+ ary.each_with_index {|v, i|
59
+ values << v if !h[i]
60
+ }
61
+ gen << values
62
+ }
63
+ }
64
+ else
65
+ header = tblreader.header
66
+ is = []
67
+ is = fs.map {|f| tblreader.index_from_field_ex(f) }
68
+ with_table_stream_output {|gen|
69
+ gen.output_header(is.map {|i| tblreader.field_from_index_ex(i) })
70
+ tblreader.each {|ary|
71
+ gen << ary.values_at(*is)
72
+ }
73
+ }
74
+ end
75
+ }
76
+ end
77
+
@@ -0,0 +1,76 @@
1
+ # Copyright (C) 2011 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 are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ Tb::Cmd.subcommands << 'grep'
26
+
27
+ Tb::Cmd.default_option[:opt_grep_e] = nil
28
+ Tb::Cmd.default_option[:opt_grep_ruby] = nil
29
+ Tb::Cmd.default_option[:opt_grep_f] = nil
30
+ Tb::Cmd.default_option[:opt_grep_v] = nil
31
+
32
+ def (Tb::Cmd).op_grep
33
+ op = OptionParser.new
34
+ op.banner = 'Usage: tb grep [OPTS] REGEXP [TABLE ...]'
35
+ define_common_option(op, "hNo", "--no-pager")
36
+ op.def_option('-f FIELD', 'search field') {|field| Tb::Cmd.opt_grep_f = field }
37
+ op.def_option('-e REGEXP', 'predicate written in ruby. A hash is given as _. no usual regexp argument.') {|pattern| Tb::Cmd.opt_grep_e = pattern }
38
+ op.def_option('--ruby RUBY-EXP', 'specify a regexp. no usual regexp argument.') {|ruby_exp| Tb::Cmd.opt_grep_ruby = ruby_exp }
39
+ op.def_option('-v', 'ouput the records which doesn\'t match') { Tb::Cmd.opt_grep_v = true }
40
+ op
41
+ end
42
+
43
+ def (Tb::Cmd).main_grep(argv)
44
+ op_grep.parse!(argv)
45
+ exit_if_help('grep')
46
+ if Tb::Cmd.opt_grep_ruby
47
+ pred = eval("lambda {|_| #{Tb::Cmd.opt_grep_ruby} }")
48
+ elsif Tb::Cmd.opt_grep_e
49
+ re = Regexp.new(Tb::Cmd.opt_grep_e)
50
+ pred = Tb::Cmd.opt_grep_f ? lambda {|_| re =~ _[Tb::Cmd.opt_grep_f] } :
51
+ lambda {|_| _.any? {|k, v| re =~ v.to_s } }
52
+ else
53
+ err("no regexp given.") if argv.empty?
54
+ re = Regexp.new(argv.shift)
55
+ pred = Tb::Cmd.opt_grep_f ? lambda {|_| re =~ _[Tb::Cmd.opt_grep_f] } :
56
+ lambda {|_| _.any? {|k, v| re =~ v.to_s } }
57
+ end
58
+ opt_v = Tb::Cmd.opt_grep_v ? true : false
59
+ argv = ['-'] if argv.empty?
60
+ Tb::CatReader.open(argv, Tb::Cmd.opt_N) {|tblreader|
61
+ with_table_stream_output {|gen|
62
+ gen.output_header tblreader.header
63
+ tblreader.each {|ary|
64
+ h = {}
65
+ ary.each_with_index {|str, i|
66
+ f = tblreader.field_from_index_ex(i)
67
+ h[f] = str
68
+ }
69
+ found = pred.call(h)
70
+ found = opt_v ^ !!(found)
71
+ gen << ary if found
72
+ }
73
+ }
74
+ }
75
+ end
76
+
@@ -0,0 +1,82 @@
1
+ # Copyright (C) 2011 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 are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ Tb::Cmd.subcommands << 'group'
26
+
27
+ Tb::Cmd.default_option[:opt_group_fields] = []
28
+
29
+ def (Tb::Cmd).op_group
30
+ op = OptionParser.new
31
+ op.banner = 'Usage: tb group [OPTS] KEY-FIELD1,... [TABLE ...]'
32
+ define_common_option(op, "hNo", "--no-pager")
33
+ op.def_option('-a AGGREGATION-SPEC[,NEW-FIELD]',
34
+ '--aggregate AGGREGATION-SPEC[,NEW-FIELD]') {|arg| Tb::Cmd.opt_group_fields << arg }
35
+ op.def_option('--no-pager', 'don\'t use pager') { Tb::Cmd.opt_no_pager = true }
36
+ op
37
+ end
38
+
39
+ def (Tb::Cmd).main_group(argv)
40
+ op_group.parse!(argv)
41
+ exit_if_help('group')
42
+ err("no key fields given.") if argv.empty?
43
+ kfs = split_field_list_argument(argv.shift)
44
+ opt_group_fields = Tb::Cmd.opt_group_fields.map {|arg|
45
+ aggregation_spec, new_field = split_field_list_argument(arg)
46
+ new_field ||= aggregation_spec
47
+ [new_field,
48
+ lambda {|fields|
49
+ begin
50
+ make_aggregator(aggregation_spec, fields)
51
+ rescue ArgumentError
52
+ err($!.message)
53
+ end
54
+ }
55
+ ]
56
+ }
57
+ argv = ['-'] if argv.empty?
58
+ h = {}
59
+ Tb::CatReader.open(argv, Tb::Cmd.opt_N) {|tblreader|
60
+ kis = kfs.map {|f| tblreader.index_from_field(f) }
61
+ result_fields = kfs + opt_group_fields.map {|nf, maker| nf }
62
+ tblreader.each {|ary|
63
+ kvs = ary.values_at(*kis)
64
+ if !h.include?(kvs)
65
+ h[kvs] = opt_group_fields.map {|nf, maker| ag = maker.call(tblreader.header); ag.update(ary); ag }
66
+ else
67
+ h[kvs].each {|ag|
68
+ ag.update(ary)
69
+ }
70
+ end
71
+ }
72
+ result = Tb.new(result_fields)
73
+ h.keys.sort_by {|k| k.map {|v| smart_cmp_value(v) } }.each {|k|
74
+ a = h[k]
75
+ result.insert_values result_fields, k + a.map {|ag| ag.finish }
76
+ }
77
+ with_output {|out|
78
+ tbl_generate_csv(result, out)
79
+ }
80
+ }
81
+ end
82
+
@@ -0,0 +1,77 @@
1
+ # Copyright (C) 2011 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 are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ Tb::Cmd.subcommands << 'gsub'
26
+
27
+ Tb::Cmd.default_option[:opt_gsub_e] = nil
28
+ Tb::Cmd.default_option[:opt_gsub_f] = nil
29
+
30
+ def (Tb::Cmd).op_gsub
31
+ op = OptionParser.new
32
+ op.banner = 'Usage: tb gsub [OPTS] REGEXP STRING [TABLE ...]'
33
+ define_common_option(op, "hNo", "--no-pager")
34
+ op.def_option('-f FIELD', 'target field') {|field| Tb::Cmd.opt_gsub_f = field }
35
+ op.def_option('-e REGEXP', 'specify regexp, possibly begins with a hyphen') {|pattern| Tb::Cmd.opt_gsub_e = pattern }
36
+ op
37
+ end
38
+
39
+ def (Tb::Cmd).main_gsub(argv)
40
+ op_gsub.parse!(argv)
41
+ exit_if_help('gsub')
42
+ if Tb::Cmd.opt_gsub_e
43
+ re = Regexp.new(Tb::Cmd.opt_gsub_e)
44
+ else
45
+ err('no regexp given.') if argv.empty?
46
+ re = Regexp.new(argv.shift)
47
+ end
48
+ err('no substitution given.') if argv.empty?
49
+ repl = argv.shift
50
+ argv = ['-'] if argv.empty?
51
+ Tb::CatReader.open(argv, Tb::Cmd.opt_N) {|tblreader|
52
+ with_table_stream_output {|gen|
53
+ gen.output_header tblreader.header
54
+ tblreader.each {|ary|
55
+ if Tb::Cmd.opt_gsub_f
56
+ ary2 = []
57
+ ary.each_with_index {|str, i|
58
+ f = tblreader.field_from_index_ex(i)
59
+ if f == Tb::Cmd.opt_gsub_f
60
+ str ||= ''
61
+ ary2 << str.gsub(re, repl)
62
+ else
63
+ ary2 << str
64
+ end
65
+ }
66
+ else
67
+ ary2 = ary.map {|s|
68
+ s ||= ''
69
+ s.gsub(re, repl)
70
+ }
71
+ end
72
+ gen << ary2
73
+ }
74
+ }
75
+ }
76
+ end
77
+
@@ -0,0 +1,98 @@
1
+ # Copyright (C) 2011 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 are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ Tb::Cmd.subcommands << 'help'
26
+
27
+ def (Tb::Cmd).usage_list_subcommands
28
+ with_output {|f|
29
+ f.print <<'End'
30
+ Usage:
31
+ End
32
+ Tb::Cmd.subcommands.each {|subcommand|
33
+ f.puts " " + self.subcommand_send("op", subcommand).banner.sub(/\AUsage: /, '')
34
+ }
35
+ }
36
+ end
37
+
38
+ def (Tb::Cmd).op_help
39
+ op = OptionParser.new
40
+ op.banner = 'Usage: tb help [OPTS] [SUBCOMMAND]'
41
+ define_common_option(op, "hvo", "--no-pager")
42
+ op
43
+ end
44
+
45
+ Tb::Cmd.def_vhelp('help', <<'End')
46
+ Example:
47
+
48
+ tb -h : list subcommands
49
+ tb help : list subcommands
50
+
51
+ tb cat -h : succinct help of "cat" subcommand
52
+ tb cat -hh : verbose help of "cat" subcommand
53
+ tb help cat : succinct help of "cat" subcommand
54
+ tb help -h cat : verbose help of "cat" subcommand
55
+
56
+ tb help -h : succinct help of "help" subcommand
57
+ tb help -hh : verbose help of "help" subcommand
58
+ tb help help : succinct help of "help" subcommand
59
+ tb help -h help : verbose help of "help" subcommand
60
+ End
61
+
62
+ def (Tb::Cmd).exit_if_help(subcommand)
63
+ if 0 < Tb::Cmd.opt_help
64
+ show_help(subcommand)
65
+ exit
66
+ end
67
+ end
68
+
69
+ def (Tb::Cmd).show_help(subcommand)
70
+ if Tb::Cmd.subcommands.include?(subcommand)
71
+ with_output {|f|
72
+ f.puts self.subcommand_send("op", subcommand)
73
+ if 2 <= Tb::Cmd.opt_help && Tb::Cmd.verbose_help[subcommand]
74
+ f.puts
75
+ f.puts Tb::Cmd.verbose_help[subcommand]
76
+ end
77
+ }
78
+ true
79
+ else
80
+ err "unexpected subcommand: #{subcommand.inspect}"
81
+ end
82
+ end
83
+
84
+ def (Tb::Cmd).main_help(argv)
85
+ op_help.parse!(argv)
86
+ if argv.empty?
87
+ if Tb::Cmd.opt_help == 0
88
+ usage_list_subcommands
89
+ return true
90
+ else
91
+ argv.unshift 'help'
92
+ Tb::Cmd.opt_help -= 1
93
+ end
94
+ end
95
+ Tb::Cmd.opt_help += 1
96
+ subcommand = argv.shift
97
+ exit_if_help(subcommand)
98
+ end