bitclust-core 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ChangeLog +7 -0
- data/Gemfile +1 -0
- data/bitclust.gemspec +1 -0
- data/data/bitclust/template.offline/class +1 -1
- data/lib/bitclust/crossrubyutils.rb +2 -2
- data/lib/bitclust/methodentry.rb +1 -2
- data/lib/bitclust/progress_bar.rb +7 -0
- data/lib/bitclust/rdcompiler.rb +1 -1
- data/lib/bitclust/runner.rb +46 -32
- data/lib/bitclust/searcher.rb +14 -13
- data/lib/bitclust/silent_progress_bar.rb +17 -0
- data/lib/bitclust/subcommand.rb +27 -0
- data/lib/bitclust/subcommands/ancestors_command.rb +145 -0
- data/lib/bitclust/subcommands/chm_command.rb +268 -0
- data/lib/bitclust/subcommands/classes_command.rb +73 -0
- data/lib/bitclust/subcommands/extract_command.rb +55 -0
- data/lib/bitclust/subcommands/htmlfile_command.rb +105 -0
- data/lib/bitclust/subcommands/init_command.rb +29 -30
- data/lib/bitclust/subcommands/list_command.rb +39 -41
- data/lib/bitclust/subcommands/lookup_command.rb +71 -73
- data/lib/bitclust/subcommands/methods_command.rb +159 -0
- data/lib/bitclust/subcommands/preproc_command.rb +35 -0
- data/lib/bitclust/subcommands/property_command.rb +47 -48
- data/lib/bitclust/subcommands/query_command.rb +12 -18
- data/lib/bitclust/subcommands/server_command.rb +180 -182
- data/lib/bitclust/subcommands/setup_command.rb +85 -89
- data/lib/bitclust/subcommands/statichtml_command.rb +276 -0
- data/lib/bitclust/subcommands/update_command.rb +39 -41
- data/lib/bitclust/version.rb +1 -1
- data/test/test_bitclust.rb +1 -1
- data/test/test_rdcompiler.rb +1 -1
- data/test/test_runner.rb +7 -14
- metadata +120 -114
@@ -0,0 +1,268 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'bitclust'
|
4
|
+
require 'bitclust/subcommand'
|
5
|
+
|
6
|
+
require 'fileutils'
|
7
|
+
# TODO Remove this line when we drop 1.8 support
|
8
|
+
require 'kconv'
|
9
|
+
require 'bitclust/progress_bar'
|
10
|
+
|
11
|
+
module BitClust
|
12
|
+
module Subcommands
|
13
|
+
class ChmCommand < Subcommand
|
14
|
+
|
15
|
+
HHP_SKEL = <<EOS
|
16
|
+
[OPTIONS]
|
17
|
+
Compatibility=1.1 or later
|
18
|
+
Compiled file=refm.chm
|
19
|
+
Contents file=refm.hhc
|
20
|
+
Default Window=titlewindow
|
21
|
+
Default topic=doc/index.html
|
22
|
+
Display compile progress=No
|
23
|
+
Error log file=refm.log
|
24
|
+
Full-text search=Yes
|
25
|
+
Index file=refm.hhk
|
26
|
+
Language=0x411 日本語 (日本)
|
27
|
+
Title=Rubyリファレンスマニュアル
|
28
|
+
|
29
|
+
[WINDOWS]
|
30
|
+
titlewindow="Rubyリファレンスマニュアル","refm.hhc","refm.hhk","doc/index.html","doc/index.html",,,,,0x21420,,0x387e,,,,,,,,0
|
31
|
+
|
32
|
+
[FILES]
|
33
|
+
<%= @html_files.join("\n") %>
|
34
|
+
EOS
|
35
|
+
|
36
|
+
HHC_SKEL = <<EOS
|
37
|
+
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
38
|
+
<HTML>
|
39
|
+
<HEAD>
|
40
|
+
</HEAD>
|
41
|
+
<BODY>
|
42
|
+
<UL><% [:library].each do |k| %>
|
43
|
+
<%= @sitemap[k].to_html %>
|
44
|
+
<% end %></UL>
|
45
|
+
</BODY>
|
46
|
+
</HTML>
|
47
|
+
EOS
|
48
|
+
|
49
|
+
HHK_SKEL = <<EOS
|
50
|
+
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
51
|
+
<HTML>
|
52
|
+
<HEAD>
|
53
|
+
</HEAD>
|
54
|
+
<BODY>
|
55
|
+
<UL><% @index_contents.sort.each do |content| %>
|
56
|
+
<%= content.to_html %>
|
57
|
+
<% end %></UL>
|
58
|
+
</BODY>
|
59
|
+
</HTML>
|
60
|
+
EOS
|
61
|
+
|
62
|
+
class Sitemap
|
63
|
+
def initialize(name, local = nil)
|
64
|
+
@name = name
|
65
|
+
@contents = Content.new(name, local)
|
66
|
+
end
|
67
|
+
|
68
|
+
def method_missing(name, *args, &block)
|
69
|
+
@contents.send(name, *args, &block)
|
70
|
+
end
|
71
|
+
|
72
|
+
class Content
|
73
|
+
include Enumerable
|
74
|
+
include ERB::Util
|
75
|
+
|
76
|
+
def initialize(name, local = nil)
|
77
|
+
@name = name
|
78
|
+
@local = local
|
79
|
+
@contents = []
|
80
|
+
end
|
81
|
+
attr_reader :name, :local, :contents
|
82
|
+
|
83
|
+
def [](index)
|
84
|
+
@contents[index]
|
85
|
+
end
|
86
|
+
|
87
|
+
def <<(content)
|
88
|
+
@contents << content
|
89
|
+
end
|
90
|
+
|
91
|
+
def <=>(other)
|
92
|
+
@name <=> other.name
|
93
|
+
end
|
94
|
+
|
95
|
+
def each
|
96
|
+
@contents.each do |content|
|
97
|
+
yield content
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_html
|
102
|
+
str = "<LI> <OBJECT type=\"text/sitemap\">\n"
|
103
|
+
str << " <param name=\"Name\" value=\"<%=h @name%>\">\n"
|
104
|
+
if @local
|
105
|
+
str << " <param name=\"Local\" value=\"<%=@local%>\">\n"
|
106
|
+
end
|
107
|
+
str << " </OBJECT>\n"
|
108
|
+
unless contents.empty?
|
109
|
+
str << "<UL>\n"
|
110
|
+
@contents.each do |content|
|
111
|
+
str << content.to_html
|
112
|
+
end
|
113
|
+
str << "</UL>\n"
|
114
|
+
end
|
115
|
+
ERB.new(str).result(binding)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class URLMapperEx < URLMapper
|
121
|
+
def library_url(name)
|
122
|
+
if name == '/'
|
123
|
+
"/library/index.html"
|
124
|
+
else
|
125
|
+
"/library/#{encodename_fs(name)}.html"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def class_url(name)
|
130
|
+
"/class/#{encodename_fs(name)}.html"
|
131
|
+
end
|
132
|
+
|
133
|
+
def method_url(spec)
|
134
|
+
cname, tmark, mname = *split_method_spec(spec)
|
135
|
+
"/method/#{encodename_fs(cname)}/#{typemark2char(tmark)}/#{encodename_fs(mname)}.html"
|
136
|
+
end
|
137
|
+
|
138
|
+
def document_url(name)
|
139
|
+
"/doc/#{encodename_fs(name)}.html"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def initialize
|
144
|
+
super
|
145
|
+
@sitemap = {
|
146
|
+
:library => Sitemap.new('ライブラリ', 'library/index.html'),
|
147
|
+
}
|
148
|
+
@sitemap[:library] << Sitemap::Content.new('標準ライブラリ', 'library/_builtin.html')
|
149
|
+
@sitemap[:library] << Sitemap::Content.new('添付ライブラリ')
|
150
|
+
@stdlibs = {}
|
151
|
+
@index_contents = []
|
152
|
+
@parser.banner = "Usage: #{File.basename($0, '.*')} chm [options]"
|
153
|
+
@parser.on('-o', '--outputdir=PATH', 'Output directory') do |path|
|
154
|
+
begin
|
155
|
+
@outputdir = Pathname.new(path).realpath
|
156
|
+
rescue Errno::ENOENT
|
157
|
+
FileUtils.mkdir_p(path, :verbose => true)
|
158
|
+
retry
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def exec(argv, options)
|
164
|
+
create_manager_config
|
165
|
+
prefix = options[:prefix]
|
166
|
+
db = MethodDatabase.new(prefix.to_s)
|
167
|
+
manager = ScreenManager.new(@manager_config)
|
168
|
+
@html_files = []
|
169
|
+
db.transaction do
|
170
|
+
methods = {}
|
171
|
+
db.methods.each do |entry|
|
172
|
+
method_name = entry.klass.name + entry.typemark + entry.name
|
173
|
+
(methods[method_name] ||= []) << entry
|
174
|
+
end
|
175
|
+
|
176
|
+
entries = db.docs + db.libraries.sort + db.classes.sort + methods.values.sort
|
177
|
+
pb = ProgressBar.new('entry', entries.size)
|
178
|
+
entries.each do |c|
|
179
|
+
filename = create_html_file(c, manager, @outputdir, db)
|
180
|
+
@html_files << filename
|
181
|
+
e = c.is_a?(Array) ? c.sort.first : c
|
182
|
+
case e.type_id
|
183
|
+
when :library
|
184
|
+
content = Sitemap::Content.new(e.name.to_s, filename)
|
185
|
+
if e.name.to_s != '_builtin'
|
186
|
+
@sitemap[:library][1] << content
|
187
|
+
@stdlibs[e.name.to_s] = content
|
188
|
+
end
|
189
|
+
@index_contents << Sitemap::Content.new(e.name.to_s, filename)
|
190
|
+
when :class
|
191
|
+
content = Sitemap::Content.new(e.name.to_s, filename)
|
192
|
+
if e.library.name.to_s == '_builtin'
|
193
|
+
@sitemap[:library][0] << content
|
194
|
+
else
|
195
|
+
@stdlibs[e.library.name.to_s] << content
|
196
|
+
end
|
197
|
+
@index_contents << Sitemap::Content.new("#{e.name} (#{e.library.name})", filename)
|
198
|
+
when :method
|
199
|
+
e.names.each do |e_name|
|
200
|
+
name = e.typename == :special_variable ? "$#{e_name}" : e_name
|
201
|
+
@index_contents <<
|
202
|
+
Sitemap::Content.new("#{name} (#{e.library.name} - #{e.klass.name})", filename)
|
203
|
+
@index_contents <<
|
204
|
+
Sitemap::Content.new("#{e.klass.name}#{e.typemark}#{name} (#{e.library.name})", filename)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
pb.title.replace(e.name)
|
208
|
+
pb.inc
|
209
|
+
end
|
210
|
+
pb.finish
|
211
|
+
end
|
212
|
+
@html_files.sort!
|
213
|
+
create_file(@outputdir + 'refm.hhp', HHP_SKEL, true)
|
214
|
+
create_file(@outputdir + 'refm.hhc', HHC_SKEL, true)
|
215
|
+
create_file(@outputdir + 'refm.hhk', HHK_SKEL, true)
|
216
|
+
create_file(@outputdir + 'library/index.html', manager.library_index_screen(db.libraries.sort, {:database => db}).body)
|
217
|
+
create_file(@outputdir + 'class/index.html', manager.class_index_screen(db.classes.sort, {:database => db}).body)
|
218
|
+
FileUtils.cp(@manager_config[:themedir] + @manager_config[:css_url],
|
219
|
+
@outputdir.to_s, {:verbose => true, :preserve => true})
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
def create_manager_config
|
225
|
+
@manager_config = {
|
226
|
+
:baseurl => 'http://example.com/',
|
227
|
+
:suffix => '.html',
|
228
|
+
:templatedir => srcdir_root + 'data'+ 'bitclust' + 'template',
|
229
|
+
:themedir => srcdir_root + 'theme' + 'default',
|
230
|
+
:css_url => 'style.css',
|
231
|
+
:cgi_url => '',
|
232
|
+
:tochm_mode => true
|
233
|
+
}
|
234
|
+
@manager_config[:urlmapper] = URLMapperEx.new(@manager_config)
|
235
|
+
end
|
236
|
+
|
237
|
+
def create_html_file(entry, manager, outputdir, db)
|
238
|
+
html = manager.entry_screen(entry, {:database => db}).body
|
239
|
+
e = entry.is_a?(Array) ? entry.sort.first : entry
|
240
|
+
path = case e.type_id
|
241
|
+
when :library, :class, :doc
|
242
|
+
outputdir + e.type_id.to_s + (NameUtils.encodename_fs(e.name) + '.html')
|
243
|
+
when :method
|
244
|
+
outputdir + e.type_id.to_s + NameUtils.encodename_fs(e.klass.name) +
|
245
|
+
e.typechar + (NameUtils.encodename_fs(e.name) + '.html')
|
246
|
+
else
|
247
|
+
raise
|
248
|
+
end
|
249
|
+
FileUtils.mkdir_p(path.dirname) unless path.dirname.directory?
|
250
|
+
path.open('w') do |f|
|
251
|
+
f.write(html)
|
252
|
+
end
|
253
|
+
path.relative_path_from(outputdir).to_s
|
254
|
+
end
|
255
|
+
|
256
|
+
def create_file(path, skel, sjis_flag = false)
|
257
|
+
$stderr.print("creating #{path} ...")
|
258
|
+
str = ERB.new(skel).result(binding)
|
259
|
+
# TODO Use String#encode when we drop 1.8 support
|
260
|
+
str = str.tosjis if sjis_flag
|
261
|
+
path.open('w') do |f|
|
262
|
+
f.write(str)
|
263
|
+
end
|
264
|
+
$stderr.puts(" done.")
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
require 'bitclust/crossrubyutils'
|
5
|
+
|
6
|
+
module BitClust
|
7
|
+
module Subcommands
|
8
|
+
class ClassesCommand < Subcommand
|
9
|
+
include CrossRubyUtils
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super
|
13
|
+
@rejects = []
|
14
|
+
@verbose = false
|
15
|
+
@parser.banner = "Usage: #{File.basename($0, '.*')} [-r<lib>] <lib>"
|
16
|
+
@parser.on('-r', '--reject=LIB', 'Reject library LIB') {|lib|
|
17
|
+
@rejects.concat lib.split(',')
|
18
|
+
}
|
19
|
+
@parser.on('-v', '--verbose', 'Show all ruby version.') {
|
20
|
+
@verbose = true
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse(argv)
|
25
|
+
super
|
26
|
+
option_error('wrong number of arguments') unless argv.size == 1
|
27
|
+
end
|
28
|
+
|
29
|
+
def exec(argv, options)
|
30
|
+
lib = argv[0]
|
31
|
+
print_crossruby_table {|ruby| defined_classes(ruby, lib, @rejects) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def defined_classes(ruby, lib, rejects)
|
35
|
+
script = <<-SCRIPT
|
36
|
+
def class_extent
|
37
|
+
result = []
|
38
|
+
ObjectSpace.each_object(Module) do |c|
|
39
|
+
result.push c
|
40
|
+
end
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
%w(#{rejects.join(" ")}).each do |lib|
|
45
|
+
begin
|
46
|
+
require lib
|
47
|
+
rescue LoadError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
if "#{lib}" == "_builtin"
|
51
|
+
class_extent().each do |c|
|
52
|
+
puts c
|
53
|
+
end
|
54
|
+
else
|
55
|
+
before = class_extent()
|
56
|
+
begin
|
57
|
+
require "#{lib}"
|
58
|
+
rescue LoadError
|
59
|
+
$stderr.puts "\#{RUBY_VERSION} (\#{RUBY_RELEASE_DATE}): library not exist: #{lib}"
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
after = class_extent()
|
63
|
+
(after - before).each do |c|
|
64
|
+
puts c
|
65
|
+
end
|
66
|
+
end
|
67
|
+
SCRIPT
|
68
|
+
output = `#{ruby} -e '#{script}'`
|
69
|
+
output.split
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
require 'bitclust'
|
5
|
+
require 'bitclust/subcommand'
|
6
|
+
|
7
|
+
module BitClust
|
8
|
+
module Subcommands
|
9
|
+
class ExtractCommand < Subcommand
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super
|
13
|
+
@parser.banner = "Usage: #{File.basename($0, '.*')} <file>..."
|
14
|
+
@parser.on('-c', '--check-only', 'Check syntax and output status.') {
|
15
|
+
@check_only = true
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def exec(argv, options)
|
20
|
+
success = true
|
21
|
+
argv.each do |path|
|
22
|
+
begin
|
23
|
+
lib = RRDParser.parse_stdlib_file(path)
|
24
|
+
if @check_only
|
25
|
+
$stderr.puts "#{path}: OK"
|
26
|
+
else
|
27
|
+
show_library lib
|
28
|
+
end
|
29
|
+
rescue WriterError => err
|
30
|
+
raise if $DEBUG
|
31
|
+
$stderr.puts "#{File.basename($0, '.*')}: FAIL: #{err.message}"
|
32
|
+
success = false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
exit success
|
36
|
+
end
|
37
|
+
|
38
|
+
def show_library(lib)
|
39
|
+
puts "= Library #{lib.name}"
|
40
|
+
lib.classes.each do |c|
|
41
|
+
puts "#{c.type} #{c.name}"
|
42
|
+
c.each do |m|
|
43
|
+
puts "\t* #{m.klass.name}#{m.typemark}#{m.names.join(',')}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
unless lib.methods.empty?
|
47
|
+
puts "Additional Methods:"
|
48
|
+
lib.methods.each do |m|
|
49
|
+
puts "\t* #{m.klass.name}#{m.typemark}#{m.names.join(',')}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# Copyright (c) 2006-2007 Minero Aoki
|
2
|
+
#
|
3
|
+
# This program is free software.
|
4
|
+
# You can distribute/modify this program under the Ruby License.
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'bitclust'
|
8
|
+
require 'bitclust/subcommand'
|
9
|
+
|
10
|
+
module BitClust
|
11
|
+
module Subcommands
|
12
|
+
class HtmlfileCommand < Subcommand
|
13
|
+
def initialize
|
14
|
+
super
|
15
|
+
@target = nil
|
16
|
+
@templatedir = srcdir_root + "data/bitclust/template.offline"
|
17
|
+
@baseurl = "file://" + srcdir_root.to_s
|
18
|
+
@version = "2.0.0"
|
19
|
+
@parser.banner = "Usage: #{File.basename($0, '.*')} htmlfile [options] rdfile"
|
20
|
+
@parser.on('--target=NAME', 'Compile NAME to HTML.') {|name|
|
21
|
+
@target = name
|
22
|
+
}
|
23
|
+
@parser.on('--force', '-f', 'Force to use rd_file template.') {|name|
|
24
|
+
@rd_file = true
|
25
|
+
}
|
26
|
+
@parser.on('--ruby_version=VER', '--ruby=VER', 'Set Ruby version') {|version|
|
27
|
+
@version = version
|
28
|
+
}
|
29
|
+
@parser.on('--baseurl=URL', 'Base URL of generated HTML') {|url|
|
30
|
+
@baseurl = url
|
31
|
+
}
|
32
|
+
@parser.on('--templatedir=PATH', 'Template directory') {|path|
|
33
|
+
@templatedir = path
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def exec(argv, options)
|
38
|
+
db = MethodDatabase.dummy({'version' => @version})
|
39
|
+
if options[:prefix]
|
40
|
+
db = MethodDatabase.new(options[:prefix])
|
41
|
+
end
|
42
|
+
@capi = options[:capi]
|
43
|
+
target_file = argv[0]
|
44
|
+
options = { 'version' => @version }
|
45
|
+
manager = ScreenManager.new(:templatedir => @templatedir,
|
46
|
+
:base_url => @baseurl,
|
47
|
+
:cgi_url => @baseurl,
|
48
|
+
:default_encoding => 'utf-8')
|
49
|
+
|
50
|
+
unless @rd_file
|
51
|
+
begin
|
52
|
+
if @capi
|
53
|
+
lib = FunctionReferenceParser.parse_file(target_file, options)
|
54
|
+
unless @target
|
55
|
+
raise NotImplementedError, "generating a C API html without --target=NAME is not implemented yet."
|
56
|
+
end
|
57
|
+
else
|
58
|
+
lib = RRDParser.parse_stdlib_file(target_file, options)
|
59
|
+
end
|
60
|
+
entry = @target ? lookup(lib, @target) : lib
|
61
|
+
puts manager.entry_screen(entry, { :database => db }).body
|
62
|
+
return
|
63
|
+
rescue ParseError => ex
|
64
|
+
$stderr.puts ex.message
|
65
|
+
$stderr.puts ex.backtrace[0], ex.backtrace[1..-1].map{|s| "\tfrom " + s}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
begin
|
70
|
+
entry = DocEntry.new(db, target_file)
|
71
|
+
source = Preprocessor.read(target_file, options)
|
72
|
+
entry.source = source
|
73
|
+
puts manager.doc_screen(entry, { :database => db }).body
|
74
|
+
rescue WriterError => ex
|
75
|
+
$stderr.puts ex.message
|
76
|
+
exit 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def lookup(lib, key)
|
83
|
+
case
|
84
|
+
when @capi && NameUtils.functionname?(key)
|
85
|
+
lib.find {|func| func.name == key}
|
86
|
+
when NameUtils.method_spec?(key)
|
87
|
+
spec = MethodSpec.parse(key)
|
88
|
+
if spec.constant?
|
89
|
+
begin
|
90
|
+
lib.fetch_class(key)
|
91
|
+
rescue UserError
|
92
|
+
lib.fetch_methods(spec)
|
93
|
+
end
|
94
|
+
else
|
95
|
+
lib.fetch_methods(spec)
|
96
|
+
end
|
97
|
+
when NameUtils.classname?(key)
|
98
|
+
lib.fetch_class(key)
|
99
|
+
else
|
100
|
+
raise InvalidKey, "wrong search key: #{key.inspect}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|