bitclust-dev 0.5.0
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/lib/bitclust.rb +9 -0
- data/tools/bc-ancestors.rb +153 -0
- data/tools/bc-checkparams.rb +246 -0
- data/tools/bc-classes.rb +80 -0
- data/tools/bc-convert.rb +165 -0
- data/tools/bc-list.rb +63 -0
- data/tools/bc-methods.rb +171 -0
- data/tools/bc-preproc.rb +42 -0
- data/tools/bc-rdoc.rb +343 -0
- data/tools/bc-tochm.rb +301 -0
- data/tools/bc-tohtml.rb +125 -0
- data/tools/bc-tohtmlpackage.rb +241 -0
- data/tools/check-signature.rb +19 -0
- data/tools/forall-ruby.rb +20 -0
- data/tools/gencatalog.rb +69 -0
- data/tools/statrefm.rb +98 -0
- data/tools/stattodo.rb +150 -0
- data/tools/update-database.rb +146 -0
- metadata +118 -0
data/tools/bc-convert.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
$KCODE = 'UTF-8' unless Object.const_defined?(:Encoding)
|
5
|
+
|
6
|
+
require 'stringio'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'tmpdir'
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
def main
|
12
|
+
mode = :output
|
13
|
+
parser = OptionParser.new
|
14
|
+
parser.banner = "Usage: #{File.basename($0, '.*')} [--diff] [file...]"
|
15
|
+
parser.on('--diff', 'Show the diff between original file and output') {
|
16
|
+
mode = :diff
|
17
|
+
}
|
18
|
+
parser.on('--inplace', 'edit input files in-place (make backup)') {
|
19
|
+
mode = :inplace
|
20
|
+
}
|
21
|
+
parser.on('--help') {
|
22
|
+
puts parser.help
|
23
|
+
exit
|
24
|
+
}
|
25
|
+
begin
|
26
|
+
parser.parse!
|
27
|
+
rescue OptionParser::ParseError => err
|
28
|
+
$stderr.puts err.message
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
case mode
|
32
|
+
when :output
|
33
|
+
do_convert ARGF
|
34
|
+
when :diff
|
35
|
+
ARGV.each do |path|
|
36
|
+
diff_output path
|
37
|
+
end
|
38
|
+
when :inplace
|
39
|
+
ARGV.each do |path|
|
40
|
+
inplace_edit path
|
41
|
+
end
|
42
|
+
else
|
43
|
+
raise "must not happen: mode=#{mode.inspect}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def inplace_edit(path)
|
48
|
+
str = convert_file(path)
|
49
|
+
File.rename path, path + '.bak'
|
50
|
+
File.open(path, 'w') {|f|
|
51
|
+
f.write str
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def diff_output(path)
|
56
|
+
tmppath = "#{Dir.tmpdir}/bc-convert-diff"
|
57
|
+
File.open(tmppath, 'w') {|f|
|
58
|
+
f.write convert_file(path)
|
59
|
+
}
|
60
|
+
system 'diff', '-u', path, tmppath
|
61
|
+
ensure
|
62
|
+
FileUtils.rm_f tmppath
|
63
|
+
end
|
64
|
+
|
65
|
+
def convert_file(path)
|
66
|
+
File.open(path) {|f| convert(f) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def convert(f)
|
70
|
+
buf = StringIO.new
|
71
|
+
do_convert f, buf
|
72
|
+
buf.string
|
73
|
+
end
|
74
|
+
|
75
|
+
def do_convert(f, out = $stdout)
|
76
|
+
f.each do |line|
|
77
|
+
case line
|
78
|
+
when /\A\#@/
|
79
|
+
out.puts line
|
80
|
+
when /\A\#/
|
81
|
+
out.puts '#@' + line
|
82
|
+
when /\A---\s/
|
83
|
+
sig = convert_signature(line.sub(/\A---/, '').sub(/\(\(<.*?>\)\)/i, '').strip)
|
84
|
+
out.puts "--- #{sig}"
|
85
|
+
if meta = line.slice(/\(\(<.*?>\)\)/i)
|
86
|
+
out.puts
|
87
|
+
out.puts meta
|
88
|
+
out.puts
|
89
|
+
end
|
90
|
+
else
|
91
|
+
out.puts convert_link(line.rstrip)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def convert_signature(sig)
|
97
|
+
case sig
|
98
|
+
when /\A([\w:\.\#]+[?!]?)\s*(?:[\(\{]|--|->|\z)/
|
99
|
+
# name(arg), name{}, name,
|
100
|
+
# name() -- obsolete
|
101
|
+
# name() -> return value type
|
102
|
+
sig
|
103
|
+
when /\A[\w:]+[\.\#]([+\-<>=~*^&|%\/]+)/ # Complex#+
|
104
|
+
sig
|
105
|
+
when /\Aself\s*(==|===|=~)\s*(\w+)/ # self == other
|
106
|
+
"#{$1}(#{$2})"
|
107
|
+
when /\A([\w:\.\#]+)\s*\=(\(|\s*\w+)?/ # name=
|
108
|
+
"#{remove_class_spec($1)}=(#{remove_paren($2.to_s.strip)})"
|
109
|
+
when /\A\w+\[(.*)\]=(.*)/ # self[key]=
|
110
|
+
"[]=(#{$1}, #{$2.strip})"
|
111
|
+
when /\A[\w\:]+\[(.*)\]/ # self[key]
|
112
|
+
"[](#{$1})"
|
113
|
+
when /\Aself\s*([+\-<>=~*^&|%\/]+)\s*(\w+)/ # self + other
|
114
|
+
"#{$1}(#{$2})"
|
115
|
+
when /\A([+\-~`])\s*\w+/ # ~ self
|
116
|
+
case op = $1
|
117
|
+
when '+', '-' then op + '@'
|
118
|
+
else op
|
119
|
+
end
|
120
|
+
when /\A(?:[\w:]+[\.\#])?(\[\]=?)/ # Matrix.[](i)
|
121
|
+
sig
|
122
|
+
when /\A([+\-<>=~*^&|%]+)/ # +(m)
|
123
|
+
sig
|
124
|
+
when /\A([A-Z]\w+\*)/ # HKEY_*
|
125
|
+
sig
|
126
|
+
when /\Aself([+\-<>=~*^&|%\/\[\]]+)\(\w/ # self+(other)
|
127
|
+
sig.sub(/\Aself/, '')
|
128
|
+
else
|
129
|
+
$stderr.puts "warning: unknown method signature: #{sig.inspect}"
|
130
|
+
sig
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def remove_class_spec(str)
|
135
|
+
str.sub(/\A[A-Z]\w*(?:::[A-Z]\w*)*[\.\#]/, '')
|
136
|
+
end
|
137
|
+
|
138
|
+
def remove_paren(str)
|
139
|
+
str.sub(/\A\(/, '').sub(/\)\z/, '')
|
140
|
+
end
|
141
|
+
|
142
|
+
def convert_link(line)
|
143
|
+
line.gsub(/\(\(\{(.*?)\}\)\)/) { $1 }\
|
144
|
+
.gsub(/\(\(\|(.*?)\|\)\)/) { $1 }\
|
145
|
+
.gsub(/\(\(<(.*?)>\)\)/) { convert_href($1) }
|
146
|
+
end
|
147
|
+
|
148
|
+
def convert_href(link)
|
149
|
+
case link
|
150
|
+
when /\Atrap::(.*)/ then "[[trap:#{$1}]]"
|
151
|
+
when /\Aruby 1\.\S+ feature/ then "((<#{link}>))"
|
152
|
+
when /\Aobsolete/ then "((<obsolete>))"
|
153
|
+
when /\A組み込み変数\/(.*)/u then "[[m:#{$1}]]"
|
154
|
+
when /\A組み込み定数\/(.*)/u then "[[m:Kernel::#{$1}]]"
|
155
|
+
when /\A組み込み関数\/(.*)/u then "[[m:Kernel\##{$1}]]"
|
156
|
+
when /\A([\w:]+[\#\.][^|]+)\|/ then "[[m:#{$1}]]"
|
157
|
+
when /\A(.*?)\|manual page\z/ then "[[man:#{$1}]]"
|
158
|
+
when /\A([\w:]+)\/(.*)\z/n then "[[m:#{$1}\##{$2}]]"
|
159
|
+
when /\A([A-Z][\w:]*)\z/ then "[[c:#{$1}]]"
|
160
|
+
else
|
161
|
+
"[[unknown:#{link}]]"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
main
|
data/tools/bc-list.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
bindir = Pathname.new(__FILE__).realpath.dirname
|
6
|
+
$LOAD_PATH.unshift((bindir + '../lib').realpath)
|
7
|
+
|
8
|
+
require 'bitclust'
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
def main
|
12
|
+
check_only = false
|
13
|
+
parser = OptionParser.new
|
14
|
+
parser.banner = "Usage: #{File.basename($0, '.*')} <file>..."
|
15
|
+
parser.on('-c', '--check-only', 'Check syntax and output status.') {
|
16
|
+
check_only = true
|
17
|
+
}
|
18
|
+
parser.on('--help', 'Prints this message and quit.') {
|
19
|
+
puts parser.help
|
20
|
+
exit
|
21
|
+
}
|
22
|
+
begin
|
23
|
+
parser.parse!
|
24
|
+
rescue OptionParser::ParseError => err
|
25
|
+
$stderr.puts err.message
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
success = true
|
30
|
+
ARGV.each do |path|
|
31
|
+
begin
|
32
|
+
lib = BitClust::RRDParser.parse_stdlib_file(path)
|
33
|
+
if check_only
|
34
|
+
$stderr.puts "#{path}: OK"
|
35
|
+
else
|
36
|
+
show_library lib
|
37
|
+
end
|
38
|
+
rescue BitClust::WriterError => err
|
39
|
+
raise if $DEBUG
|
40
|
+
$stderr.puts "#{File.basename($0, '.*')}: FAIL: #{err.message}"
|
41
|
+
success = false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
exit success
|
45
|
+
end
|
46
|
+
|
47
|
+
def show_library(lib)
|
48
|
+
puts "= Library #{lib.name}"
|
49
|
+
lib.classes.each do |c|
|
50
|
+
puts "#{c.type} #{c.name}"
|
51
|
+
c.each do |m|
|
52
|
+
puts "\t* #{m.klass.name}#{m.typemark}#{m.names.join(',')}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
unless lib.methods.empty?
|
56
|
+
puts "Additional Methods:"
|
57
|
+
lib.methods.each do |m|
|
58
|
+
puts "\t* #{m.klass.name}#{m.typemark}#{m.names.join(',')}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
main
|
data/tools/bc-methods.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# bc-methods.rb -- list all methods of existing rubys.
|
4
|
+
#
|
5
|
+
# This program is derived from bc-vdtb.rb, posted in
|
6
|
+
# [ruby-reference-manual:160] by sheepman.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
|
11
|
+
bindir = Pathname.new(__FILE__).realpath.dirname
|
12
|
+
$LOAD_PATH.unshift((bindir + '../lib').realpath)
|
13
|
+
|
14
|
+
require 'bitclust'
|
15
|
+
require 'bitclust/crossrubyutils'
|
16
|
+
require 'optparse'
|
17
|
+
|
18
|
+
include BitClust::CrossRubyUtils
|
19
|
+
|
20
|
+
def main
|
21
|
+
@requires = []
|
22
|
+
@verbose = false
|
23
|
+
@ver = RUBY_VERSION
|
24
|
+
mode = :list
|
25
|
+
target = nil
|
26
|
+
opts = OptionParser.new
|
27
|
+
opts.banner = "Usage: #{File.basename($0, '.*')} [-r<lib>] <classname>"
|
28
|
+
opts.on('-r LIB', 'Requires library LIB') {|lib|
|
29
|
+
@requires.push lib
|
30
|
+
}
|
31
|
+
opts.on('-v', '--verbose', "Prints each ruby's version") {
|
32
|
+
@verbose = true
|
33
|
+
}
|
34
|
+
opts.on('--diff=RDFILE', 'RD file name') {|path|
|
35
|
+
mode = :diff
|
36
|
+
target = path
|
37
|
+
}
|
38
|
+
opts.on('-c', '') {
|
39
|
+
@content = true
|
40
|
+
require 'bitclust/ridatabase'
|
41
|
+
}
|
42
|
+
opts.on('--ruby=[VER]', "The version of Ruby interpreter"){|ver|
|
43
|
+
@ver = ver
|
44
|
+
}
|
45
|
+
opts.on('--ri-database', 'The path of ri database'){|path|
|
46
|
+
@ri_path = path
|
47
|
+
}
|
48
|
+
opts.on('--help', 'Prints this message and quit.') {
|
49
|
+
puts opts.help
|
50
|
+
exit 0
|
51
|
+
}
|
52
|
+
begin
|
53
|
+
opts.parse!(ARGV)
|
54
|
+
rescue OptionParser::ParseError => err
|
55
|
+
$stderr.puts err.message
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
unless ARGV.size == 1
|
59
|
+
$stderr.puts "wrong number of arguments"
|
60
|
+
$stderr.puts opts.help
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
classname = ARGV[0]
|
64
|
+
|
65
|
+
case mode
|
66
|
+
when :list
|
67
|
+
print_crossruby_table {|ruby| defined_methods(ruby, classname) }
|
68
|
+
when :diff
|
69
|
+
unless ruby = get_ruby(@ver)
|
70
|
+
raise "Not found Ruby interpreter of the given version"
|
71
|
+
end
|
72
|
+
keys = defined_methods(ruby, classname)
|
73
|
+
lib = BitClust::RRDParser.parse_stdlib_file(target, { 'version' => @ver })
|
74
|
+
c = lib.fetch_class(classname)
|
75
|
+
list0 = lib.classes.find_all{|c0| /\A#{classname}\b/o =~ c0.name }
|
76
|
+
list0 = c.entries + list0
|
77
|
+
list = list0.map {|ent| ent.labels.map {|n| expand_mf(n) } }.flatten
|
78
|
+
if @content
|
79
|
+
ri = @ri_path ? RiDatabase.open(@ri_path, nil) : RiDatabase.open_system_db
|
80
|
+
ri.current_class = c.name
|
81
|
+
mthds = ( ri.singleton_methods + ri.instance_methods )
|
82
|
+
fmt = Formatter.new
|
83
|
+
(keys - list).sort.each do |name|
|
84
|
+
mthd = mthds.find{|m| name == m.fullname }
|
85
|
+
if mthd
|
86
|
+
puts fmt.method_info(mthd.entry)
|
87
|
+
else
|
88
|
+
name = name.sub(/\A\w+#/, '')
|
89
|
+
puts "--- #{name}\n\#@todo\n\n"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
else
|
93
|
+
(keys - list).sort.each do |name|
|
94
|
+
puts "-#{name}"
|
95
|
+
end
|
96
|
+
(list - keys).sort.each do |name|
|
97
|
+
puts "+#{name}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
else
|
101
|
+
raise "must not happen: #{mode.inspect}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def expand_mf(n)
|
106
|
+
if /\.\#/ =~ n
|
107
|
+
[n.sub(/\.\#/, '.'), n.sub(/\.\#/, '#')]
|
108
|
+
else
|
109
|
+
n
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def crossrubyutils_sort_entries(ents)
|
114
|
+
ents.sort_by {|m| m_order(m) }
|
115
|
+
end
|
116
|
+
|
117
|
+
ORDER = { '.' => 1, '#' => 2, '::' => 3 }
|
118
|
+
|
119
|
+
def m_order(m)
|
120
|
+
m, t, c = *m.reverse.split(/(\#|\.|::)/, 2)
|
121
|
+
[ORDER[t] || 0, m.reverse]
|
122
|
+
end
|
123
|
+
|
124
|
+
def defined_methods(ruby, classname)
|
125
|
+
req = @requires.map {|lib| "-r#{lib}" }.join(' ')
|
126
|
+
avoid_tracer = ""
|
127
|
+
avoid_tracer = "Tracer.off" if @requires.include?("tracer")
|
128
|
+
if classname == 'Object'
|
129
|
+
`#{ruby} #{req} -e '
|
130
|
+
c = #{classname}
|
131
|
+
c.singleton_methods(false).each do |m|
|
132
|
+
puts "#{classname}.\#{m}"
|
133
|
+
end
|
134
|
+
c.instance_methods(true).each do |m|
|
135
|
+
puts "#{classname}\\#\#{m}"
|
136
|
+
end
|
137
|
+
'`.split
|
138
|
+
elsif classname == 'Kernel'
|
139
|
+
`#{ruby} #{req} -e '
|
140
|
+
c = #{classname}
|
141
|
+
c.singleton_methods(true).each do |m|
|
142
|
+
puts "#{classname}.\#{m}"
|
143
|
+
end
|
144
|
+
( c.private_instance_methods(false) && c.methods(false) ).each do |m|
|
145
|
+
puts "#{classname}\\#\#{m}"
|
146
|
+
end
|
147
|
+
Object::constants.delete_if{|c| cl = Object.const_get(c).class; cl == Class or cl == Module }.each do |m|
|
148
|
+
puts "#{classname}::\#{m}"
|
149
|
+
end
|
150
|
+
global_variables.each do |m|
|
151
|
+
puts "#{classname}\#{m}"
|
152
|
+
end
|
153
|
+
'`.split
|
154
|
+
else
|
155
|
+
`#{ruby} #{req} -e '
|
156
|
+
#{avoid_tracer}
|
157
|
+
c = #{classname}
|
158
|
+
c.singleton_methods(false).each do |m|
|
159
|
+
puts "#{classname}.\#{m}"
|
160
|
+
end
|
161
|
+
c.instance_methods(false).each do |m|
|
162
|
+
puts "#{classname}\\#\#{m}"
|
163
|
+
end
|
164
|
+
c.ancestors.map {|mod| mod.constants }.inject {|r,n| r-n }.each do |m|
|
165
|
+
puts "#{classname}::\#{m}"
|
166
|
+
end
|
167
|
+
'`.split
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
main
|
data/tools/bc-preproc.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
bindir = Pathname.new(__FILE__).realpath.dirname
|
6
|
+
$LOAD_PATH.unshift((bindir + '../lib').realpath)
|
7
|
+
|
8
|
+
require 'bitclust/rrdparser'
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
def main
|
12
|
+
params = {"version" => "1.9.0"}
|
13
|
+
parser = OptionParser.new
|
14
|
+
parser.banner = "Usage: #{File.basename($0, '.*')} <file>..."
|
15
|
+
parser.on('--param=KVPAIR', 'Set parameter by key/value pair.') {|kv|
|
16
|
+
k, v = kv.split('=', 2)
|
17
|
+
params[k] = v
|
18
|
+
}
|
19
|
+
parser.on('--help', 'Prints this message and quit.') {
|
20
|
+
puts parser.help
|
21
|
+
exit
|
22
|
+
}
|
23
|
+
begin
|
24
|
+
parser.parse!
|
25
|
+
rescue OptionParser::ParseError => err
|
26
|
+
$stderr.puts err.message
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
|
30
|
+
ARGV.each do |path|
|
31
|
+
File.open(path) {|f|
|
32
|
+
BitClust::Preprocessor.wrap(f, params).each do |line|
|
33
|
+
puts line
|
34
|
+
end
|
35
|
+
}
|
36
|
+
end
|
37
|
+
rescue BitClust::WriterError => err
|
38
|
+
$stderr.puts err.message
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
|
42
|
+
main
|
data/tools/bc-rdoc.rb
ADDED
@@ -0,0 +1,343 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# bc-rdoc.rb -- handle rdoc (ri) database.
|
4
|
+
#
|
5
|
+
# "bc-rdoc history" code is derived from bc-history.rb, posted in
|
6
|
+
# [ruby-reference-manual:150] by moriq.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
|
11
|
+
srcdir_root = Pathname.new(__FILE__).realpath.dirname.parent.cleanpath
|
12
|
+
$LOAD_PATH.unshift srcdir_root + 'lib'
|
13
|
+
|
14
|
+
require 'bitclust'
|
15
|
+
require 'bitclust/ridatabase'
|
16
|
+
require 'rdoc/ri/ri_reader'
|
17
|
+
require 'rdoc/ri/ri_cache'
|
18
|
+
require 'rdoc/ri/ri_paths'
|
19
|
+
require 'rdoc/markup/simple_markup/fragments'
|
20
|
+
require 'stringio'
|
21
|
+
require 'pp'
|
22
|
+
require 'optparse'
|
23
|
+
|
24
|
+
class ApplicationError < StandardError; end
|
25
|
+
class RiClassNotFound < ApplicationError; end
|
26
|
+
|
27
|
+
def main
|
28
|
+
Signal.trap(:PIPE) { exit 1 } rescue nil # Win32 does not have SIGPIPE
|
29
|
+
Signal.trap(:INT) { exit 1 }
|
30
|
+
|
31
|
+
parser = OptionParser.new
|
32
|
+
parser.banner = <<-EndUsage
|
33
|
+
Usage: #{File.basename($0)} (list|diff|history) [options]
|
34
|
+
|
35
|
+
Subcommands:
|
36
|
+
list List methods stored in ri database.
|
37
|
+
diff Compare between BitClust and ri database.
|
38
|
+
history Show class/method history stored in ri database.
|
39
|
+
|
40
|
+
Global Options:
|
41
|
+
EndUsage
|
42
|
+
parser.on('--help', 'Prints this message and quit.') {
|
43
|
+
puts parser.help
|
44
|
+
exit 0
|
45
|
+
}
|
46
|
+
begin
|
47
|
+
parser.order!
|
48
|
+
rescue OptionParser::ParseError => err
|
49
|
+
$stderr.puts err.message
|
50
|
+
$stderr.puts parser.help
|
51
|
+
exit 1
|
52
|
+
end
|
53
|
+
|
54
|
+
subcommands = {
|
55
|
+
'list' => ListCommand.new,
|
56
|
+
'diff' => DiffCommand.new,
|
57
|
+
'history' => HistoryCommand.new
|
58
|
+
}
|
59
|
+
subcommands['hist'] = subcommands['history']
|
60
|
+
unless ARGV[0]
|
61
|
+
$stderr.puts 'no subcommand given'
|
62
|
+
$stderr.puts parser.help
|
63
|
+
exit 1
|
64
|
+
end
|
65
|
+
unless subcommands.key?(ARGV[0])
|
66
|
+
$stderr.puts "unknown subcommand: #{ARGV[0].inspect}"
|
67
|
+
$stderr.puts parser.help
|
68
|
+
exit 1
|
69
|
+
end
|
70
|
+
sub = subcommands[ARGV.shift]
|
71
|
+
begin
|
72
|
+
sub.parse ARGV
|
73
|
+
rescue OptionParser::ParseError => err
|
74
|
+
$stderr.puts err.message
|
75
|
+
$stderr.puts sub.parser.help
|
76
|
+
exit 1
|
77
|
+
end
|
78
|
+
sub.exec
|
79
|
+
rescue Errno::EPIPE
|
80
|
+
exit 1
|
81
|
+
rescue ApplicationError, BitClust::UserError => err
|
82
|
+
$stderr.puts err.message
|
83
|
+
exit 1
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
class Subcommand
|
88
|
+
|
89
|
+
def open_ri_database(prefix)
|
90
|
+
if prefix
|
91
|
+
RiDatabase.open(prefix, nil)
|
92
|
+
else
|
93
|
+
RiDatabase.open_system_db
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
class ListCommand < Subcommand
|
101
|
+
|
102
|
+
def initialize
|
103
|
+
@prefix = nil
|
104
|
+
@type = :name
|
105
|
+
@parser = OptionParser.new
|
106
|
+
@parser.banner = "Usage: #{File.basename($0, '.*')} list"
|
107
|
+
@parser.on('--ri-database=PREFIX', 'Ri database prefix') {|path|
|
108
|
+
@prefix = path
|
109
|
+
}
|
110
|
+
@parser.on('-c', '--content', 'Prints method description') {
|
111
|
+
@type = :content
|
112
|
+
}
|
113
|
+
@parser.on('--help', 'Prints this message and quit.') {
|
114
|
+
puts @parser.help
|
115
|
+
exit 0
|
116
|
+
}
|
117
|
+
end
|
118
|
+
|
119
|
+
attr_reader :parser
|
120
|
+
|
121
|
+
def parse(argv)
|
122
|
+
@parser.parse! argv
|
123
|
+
unless argv.size == 1
|
124
|
+
$stderr.puts "class name not given"
|
125
|
+
exit 1
|
126
|
+
end
|
127
|
+
@classname = argv[0]
|
128
|
+
@ri = open_ri_database(@prefix)
|
129
|
+
end
|
130
|
+
|
131
|
+
def exec
|
132
|
+
c = @ri.lookup_class(@classname)
|
133
|
+
case @type
|
134
|
+
when :name
|
135
|
+
c.method_entries.each do |m|
|
136
|
+
puts m.fullname
|
137
|
+
end
|
138
|
+
when :content
|
139
|
+
fmt = Formatter.new
|
140
|
+
c.method_entries.each do |m|
|
141
|
+
puts fmt.method_info(@ri.get_method(m))
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
class DiffCommand < Subcommand
|
150
|
+
|
151
|
+
def initialize
|
152
|
+
@bcprefix = nil
|
153
|
+
@riprefix = nil
|
154
|
+
@type = :name
|
155
|
+
@parser = OptionParser.new
|
156
|
+
@parser.banner = "Usage: #{File.basename($0, '.*')} diff --bc=PATH --ri=PATH <classname>"
|
157
|
+
@parser.on('--bc-database=PREFIX', 'BitClust database prefix') {|path|
|
158
|
+
@bcprefix = path
|
159
|
+
}
|
160
|
+
@parser.on('--ri-database=PREFIX', 'Ri database prefix') {|path|
|
161
|
+
@riprefix = path
|
162
|
+
}
|
163
|
+
@parser.on('-c', '--content', 'Prints method description') {
|
164
|
+
@type = :content
|
165
|
+
}
|
166
|
+
@parser.on('--help', 'Prints this message and quit.') {
|
167
|
+
puts @parser.help
|
168
|
+
exit 0
|
169
|
+
}
|
170
|
+
end
|
171
|
+
|
172
|
+
attr_reader :parser
|
173
|
+
|
174
|
+
def parse(argv)
|
175
|
+
@parser.parse! argv
|
176
|
+
unless @bcprefix
|
177
|
+
$stderr.puts 'missing BitClust database prefix. Use --bc option'
|
178
|
+
exit 1
|
179
|
+
end
|
180
|
+
@bc = BitClust::MethodDatabase.new(@bcprefix)
|
181
|
+
@ri = open_ri_database(@riprefix)
|
182
|
+
unless argv.size == 1
|
183
|
+
$stderr.puts "wrong number of arguments (#{argv.size} for 1)"
|
184
|
+
$stderr.puts @parser.help
|
185
|
+
exit 1
|
186
|
+
end
|
187
|
+
@classname = argv[0]
|
188
|
+
end
|
189
|
+
|
190
|
+
def exec
|
191
|
+
@ri.current_class = @classname
|
192
|
+
win, lose = *diff_class(bc_lookup_class(@classname), @ri)
|
193
|
+
case @type
|
194
|
+
when :name
|
195
|
+
win.each do |m|
|
196
|
+
puts "+ #{m.id}"
|
197
|
+
end
|
198
|
+
lose.each do |m|
|
199
|
+
puts "- #{m.fullname}"
|
200
|
+
end
|
201
|
+
when :content
|
202
|
+
fmt = Formatter.new
|
203
|
+
lose.each do |m|
|
204
|
+
# puts "\#@\# bc-rdoc: detected missing name: #{m.name}"
|
205
|
+
puts fmt.method_info(m.entry)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def bc_lookup_class(classname)
|
211
|
+
@bc.fetch_class(classname)
|
212
|
+
rescue BitClust::ClassNotFound
|
213
|
+
$stderr.puts "warning: class #{classname} not exist in BitClust database"
|
214
|
+
@bc.get_class(classname)
|
215
|
+
end
|
216
|
+
|
217
|
+
def diff_class(bc, ri)
|
218
|
+
unzip(diff_entries(bc, bc_wrap(bc.singleton_methods), ri.singleton_methods),
|
219
|
+
diff_entries(bc, bc_wrap(bc.instance_methods), ri.instance_methods))\
|
220
|
+
.map {|list| list.flatten }
|
221
|
+
end
|
222
|
+
|
223
|
+
def bc_wrap(ents)
|
224
|
+
ents.map {|m|
|
225
|
+
m.names.map {|name| BCMethodEntry.new(name, m) }
|
226
|
+
}.flatten.uniq
|
227
|
+
end
|
228
|
+
|
229
|
+
def unzip(*tuples)
|
230
|
+
[tuples.map {|s, i| s }, tuples.map {|s, i| i }]
|
231
|
+
end
|
232
|
+
|
233
|
+
def diff_entries(bc_class, bc, ri)
|
234
|
+
bc = bc.sort
|
235
|
+
ri = ri.sort
|
236
|
+
[bc - ri, (ri - bc).reject {|m| true_exist?(bc_class, m) }]
|
237
|
+
end
|
238
|
+
|
239
|
+
def true_exist?(c, m)
|
240
|
+
if m.singleton_method?
|
241
|
+
c.singleton_method?(m.name, true)
|
242
|
+
else
|
243
|
+
c.instance_method?(m.name, true)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
class HistoryCommand < Subcommand
|
251
|
+
|
252
|
+
def initialize
|
253
|
+
@riprefix = nil
|
254
|
+
@parser = OptionParser.new
|
255
|
+
@parser.banner = "Usage: #{File.basename($0, '.*')} history --ri=PATH <classname>"
|
256
|
+
@parser.on('--ri-database=PREFIX', 'Ri database prefix') {|path|
|
257
|
+
@riprefix = path
|
258
|
+
}
|
259
|
+
@parser.on('--help', 'Prints this message and quit.') {
|
260
|
+
puts @parser.help
|
261
|
+
exit 0
|
262
|
+
}
|
263
|
+
end
|
264
|
+
|
265
|
+
attr_reader :parser
|
266
|
+
|
267
|
+
def parse(argv)
|
268
|
+
@parser.parse! argv
|
269
|
+
unless @riprefix
|
270
|
+
$stderr.puts 'ri database not given; use --ri option'
|
271
|
+
exit 1
|
272
|
+
end
|
273
|
+
@ris = Dir.glob("#{@riprefix}/1.*").map {|dir|
|
274
|
+
RiDatabase.open(dir, File.basename(dir))
|
275
|
+
}
|
276
|
+
if @ris.empty?
|
277
|
+
$stderr.puts 'wrong ri database directory; directories like <path>/1.8.3/, <path>/1.8.4/, ... must exist'
|
278
|
+
exit 1
|
279
|
+
end
|
280
|
+
unless argv.size == 1
|
281
|
+
$stderr.puts "wrong number of arguments (#{argv.size} for 1)"
|
282
|
+
$stderr.puts @parser.help
|
283
|
+
exit 1
|
284
|
+
end
|
285
|
+
@classname = argv[0]
|
286
|
+
end
|
287
|
+
|
288
|
+
def exec
|
289
|
+
@ris.each do |ri|
|
290
|
+
ri.current_class = @classname
|
291
|
+
end
|
292
|
+
s = {}
|
293
|
+
i = {}
|
294
|
+
@ris.each do |ri|
|
295
|
+
ri.singleton_methods.each do |m|
|
296
|
+
(s[m] ||= []).push ri.version
|
297
|
+
end
|
298
|
+
ri.instance_methods.each do |m|
|
299
|
+
(i[m] ||= []).push ri.version
|
300
|
+
end
|
301
|
+
end
|
302
|
+
namecols = calculate_n_namecols(s.keys + i.keys)
|
303
|
+
versions = @ris.map {|ri| ri.version }
|
304
|
+
print_header namecols, versions
|
305
|
+
print_records namecols, versions, (s.to_a + i.to_a)
|
306
|
+
end
|
307
|
+
|
308
|
+
def calculate_n_namecols(ms)
|
309
|
+
tabstop = 8
|
310
|
+
maxnamelen = ms.map {|m| m.fullname.size }.max
|
311
|
+
(maxnamelen / tabstop + 1) * tabstop
|
312
|
+
end
|
313
|
+
|
314
|
+
def print_header(namecols, versions)
|
315
|
+
print ' ' * namecols
|
316
|
+
versions.each do |ver|
|
317
|
+
printf '%4s', ver.tr('.', '')
|
318
|
+
end
|
319
|
+
puts
|
320
|
+
end
|
321
|
+
|
322
|
+
def print_records(namecols, versions, records)
|
323
|
+
veridx = {}
|
324
|
+
versions.each_with_index do |ver, idx|
|
325
|
+
veridx[ver] = idx
|
326
|
+
end
|
327
|
+
records.sort_by {|m, vers| m.fullname }.each do |m, vers|
|
328
|
+
printf "%-#{namecols}s", m.fullname
|
329
|
+
|
330
|
+
fmt = '%4s' * versions.size
|
331
|
+
cols = ['-'] * versions.size
|
332
|
+
vers.each do |ver|
|
333
|
+
cols[veridx[ver]] = 'o'
|
334
|
+
end
|
335
|
+
printf fmt, *cols
|
336
|
+
puts
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
main
|