rdoc 7.2.0 → 8.1.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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +4 -7
- data/LICENSE.rdoc +4 -0
- data/README.md +43 -2
- data/RI.md +75 -75
- data/doc/markup_reference/markdown.md +104 -3
- data/exe/rdoc +2 -2
- data/lib/rdoc/code_object/alias.rb +70 -74
- data/lib/rdoc/code_object/any_method.rb +305 -298
- data/lib/rdoc/code_object/attr.rb +150 -143
- data/lib/rdoc/code_object/class_module.rb +801 -765
- data/lib/rdoc/code_object/constant.rb +178 -150
- data/lib/rdoc/code_object/context/section.rb +133 -160
- data/lib/rdoc/code_object/context.rb +925 -952
- data/lib/rdoc/code_object/extend.rb +7 -5
- data/lib/rdoc/code_object/include.rb +7 -5
- data/lib/rdoc/code_object/method_attr.rb +325 -324
- data/lib/rdoc/code_object/mixin.rb +97 -95
- data/lib/rdoc/code_object/normal_class.rb +77 -78
- data/lib/rdoc/code_object/normal_module.rb +61 -59
- data/lib/rdoc/code_object/require.rb +23 -39
- data/lib/rdoc/code_object/single_class.rb +21 -19
- data/lib/rdoc/code_object/top_level.rb +212 -213
- data/lib/rdoc/code_object.rb +305 -305
- data/lib/rdoc/comment.rb +274 -337
- data/lib/rdoc/cross_reference.rb +194 -212
- data/lib/rdoc/encoding.rb +105 -103
- data/lib/rdoc/erb_partial.rb +13 -11
- data/lib/rdoc/erbio.rb +29 -27
- data/lib/rdoc/generator/aliki.rb +165 -140
- data/lib/rdoc/generator/darkfish.rb +647 -631
- data/lib/rdoc/generator/json_index.rb +233 -229
- data/lib/rdoc/generator/markup.rb +165 -122
- data/lib/rdoc/generator/pot/message_extractor.rb +57 -51
- data/lib/rdoc/generator/pot/po.rb +52 -51
- data/lib/rdoc/generator/pot/po_entry.rb +138 -132
- data/lib/rdoc/generator/pot.rb +85 -81
- data/lib/rdoc/generator/ri.rb +23 -19
- data/lib/rdoc/generator/template/aliki/DESIGN.md +538 -0
- data/lib/rdoc/generator/template/aliki/_aside_toc.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_footer.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_head.rhtml +11 -11
- data/lib/rdoc/generator/template/aliki/_header.rhtml +29 -44
- data/lib/rdoc/generator/template/aliki/_sidebar_extends.rhtml +8 -6
- data/lib/rdoc/generator/template/aliki/_sidebar_includes.rhtml +8 -6
- data/lib/rdoc/generator/template/aliki/_sidebar_installed.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_sidebar_pages.rhtml +2 -2
- data/lib/rdoc/generator/template/aliki/_sidebar_search.rhtml +4 -4
- data/lib/rdoc/generator/template/aliki/_sidebar_sections.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/_sidebar_toggle.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/class.rhtml +56 -46
- data/lib/rdoc/generator/template/aliki/css/rdoc.css +538 -283
- data/lib/rdoc/generator/template/aliki/index.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/js/aliki.js +80 -102
- data/lib/rdoc/generator/template/aliki/page.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/servlet_not_found.rhtml +1 -1
- data/lib/rdoc/generator/template/aliki/servlet_root.rhtml +2 -2
- data/lib/rdoc/generator/template/darkfish/_footer.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +8 -6
- data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +8 -6
- data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +1 -1
- data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +5 -5
- data/lib/rdoc/generator/template/darkfish/class.rhtml +18 -21
- data/lib/rdoc/generator/template/darkfish/css/rdoc.css +0 -1
- data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +3 -3
- data/lib/rdoc/generator.rb +48 -46
- data/lib/rdoc/i18n/locale.rb +99 -95
- data/lib/rdoc/i18n/text.rb +109 -105
- data/lib/rdoc/i18n.rb +7 -5
- data/lib/rdoc/markdown/byte_runtime.rb +80 -0
- data/lib/rdoc/markdown.kpeg +30 -21
- data/lib/rdoc/markdown.rb +329 -151
- data/lib/rdoc/markup/block_quote.rb +12 -8
- data/lib/rdoc/markup/document.rb +127 -123
- data/lib/rdoc/markup/formatter.rb +215 -221
- data/lib/rdoc/markup/heading.rb +1 -4
- data/lib/rdoc/markup/include.rb +33 -29
- data/lib/rdoc/markup/indented_paragraph.rb +37 -33
- data/lib/rdoc/markup/inline_parser.rb +281 -277
- data/lib/rdoc/markup/list.rb +80 -88
- data/lib/rdoc/markup/list_item.rb +73 -85
- data/lib/rdoc/markup/paragraph.rb +23 -19
- data/lib/rdoc/markup/parser.rb +501 -497
- data/lib/rdoc/markup/pre_process.rb +284 -305
- data/lib/rdoc/markup/raw.rb +2 -2
- data/lib/rdoc/markup/rule.rb +16 -12
- data/lib/rdoc/markup/to_ansi.rb +143 -139
- data/lib/rdoc/markup/to_bs.rb +72 -68
- data/lib/rdoc/markup/to_html.rb +600 -493
- data/lib/rdoc/markup/to_html_crossref.rb +221 -191
- data/lib/rdoc/markup/to_html_snippet.rb +232 -227
- data/lib/rdoc/markup/to_joined_paragraph.rb +40 -41
- data/lib/rdoc/markup/to_label.rb +63 -59
- data/lib/rdoc/markup/to_markdown.rb +212 -208
- data/lib/rdoc/markup/to_rdoc.rb +336 -332
- data/lib/rdoc/markup/to_table_of_contents.rb +66 -62
- data/lib/rdoc/markup/to_test.rb +60 -56
- data/lib/rdoc/markup/to_tt_only.rb +83 -86
- data/lib/rdoc/markup/verbatim.rb +62 -58
- data/lib/rdoc/markup.rb +198 -196
- data/lib/rdoc/options.rb +1063 -1076
- data/lib/rdoc/parser/c.rb +1039 -1036
- data/lib/rdoc/parser/changelog.rb +319 -315
- data/lib/rdoc/parser/markdown.rb +17 -13
- data/lib/rdoc/parser/rbs.rb +279 -0
- data/lib/rdoc/parser/rd.rb +17 -13
- data/lib/rdoc/parser/ruby.rb +1231 -2222
- data/lib/rdoc/parser/ruby_colorizer.rb +303 -0
- data/lib/rdoc/parser/simple.rb +31 -27
- data/lib/rdoc/parser/text.rb +12 -8
- data/lib/rdoc/parser.rb +230 -221
- data/lib/rdoc/rbs_helper.rb +186 -0
- data/lib/rdoc/rd/inline.rb +57 -53
- data/lib/rdoc/rd.rb +90 -88
- data/lib/rdoc/rdoc.rb +547 -366
- data/lib/rdoc/ri/driver.rb +1141 -1130
- data/lib/rdoc/ri/formatter.rb +7 -3
- data/lib/rdoc/ri/paths.rb +140 -136
- data/lib/rdoc/ri/servlet.rb +456 -0
- data/lib/rdoc/ri/store.rb +4 -2
- data/lib/rdoc/ri/task.rb +55 -51
- data/lib/rdoc/ri.rb +14 -11
- data/lib/rdoc/rubygems_hook.rb +194 -192
- data/lib/rdoc/server.rb +462 -0
- data/lib/rdoc/stats/normal.rb +46 -42
- data/lib/rdoc/stats/quiet.rb +39 -35
- data/lib/rdoc/stats/verbose.rb +35 -31
- data/lib/rdoc/stats.rb +363 -338
- data/lib/rdoc/store.rb +919 -725
- data/lib/rdoc/task.rb +260 -255
- data/lib/rdoc/text.rb +130 -245
- data/lib/rdoc/token_stream.rb +101 -115
- data/lib/rdoc/tom_doc.rb +203 -201
- data/lib/rdoc/version.rb +1 -1
- data/lib/rdoc.rb +35 -7
- data/lib/rubygems_plugin.rb +2 -11
- data/rdoc-logo.svg +43 -0
- data/rdoc.gemspec +6 -4
- metadata +36 -20
- data/lib/rdoc/code_object/anon_class.rb +0 -10
- data/lib/rdoc/code_object/ghost_method.rb +0 -6
- data/lib/rdoc/code_object/meta_method.rb +0 -6
- data/lib/rdoc/markdown/literals.kpeg +0 -21
- data/lib/rdoc/markdown/literals.rb +0 -454
- data/lib/rdoc/parser/prism_ruby.rb +0 -1112
- data/lib/rdoc/parser/ripper_state_lex.rb +0 -302
- data/lib/rdoc/parser/ruby_tools.rb +0 -163
- data/lib/rdoc/servlet.rb +0 -452
data/lib/rdoc/rdoc.rb
CHANGED
|
@@ -5,192 +5,194 @@ require 'find'
|
|
|
5
5
|
require 'fileutils'
|
|
6
6
|
require 'pathname'
|
|
7
7
|
require 'time'
|
|
8
|
+
require_relative 'rbs_helper'
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
# This is the driver for generating RDoc output. It handles file parsing and
|
|
11
|
-
# generation of output.
|
|
12
|
-
#
|
|
13
|
-
# To use this class to generate RDoc output via the API, the recommended way
|
|
14
|
-
# is:
|
|
15
|
-
#
|
|
16
|
-
# rdoc = RDoc::RDoc.new
|
|
17
|
-
# options = RDoc::Options.load_options # returns an RDoc::Options instance
|
|
18
|
-
# # set extra options
|
|
19
|
-
# rdoc.document options
|
|
20
|
-
#
|
|
21
|
-
# You can also generate output like the +rdoc+ executable:
|
|
22
|
-
#
|
|
23
|
-
# rdoc = RDoc::RDoc.new
|
|
24
|
-
# rdoc.document argv
|
|
25
|
-
#
|
|
26
|
-
# Where +argv+ is an array of strings, each corresponding to an argument you'd
|
|
27
|
-
# give rdoc on the command line. See <tt>rdoc --help</tt> for details.
|
|
28
|
-
|
|
29
|
-
class RDoc::RDoc
|
|
30
|
-
|
|
31
|
-
@current = nil
|
|
32
|
-
|
|
10
|
+
module RDoc
|
|
33
11
|
##
|
|
34
|
-
# This is the
|
|
12
|
+
# This is the driver for generating RDoc output. It handles file parsing and
|
|
13
|
+
# generation of output.
|
|
14
|
+
#
|
|
15
|
+
# To use this class to generate RDoc output via the API, the recommended way
|
|
16
|
+
# is:
|
|
17
|
+
#
|
|
18
|
+
# rdoc = RDoc::RDoc.new
|
|
19
|
+
# options = RDoc::Options.load_options # returns an RDoc::Options instance
|
|
20
|
+
# # set extra options
|
|
21
|
+
# rdoc.document options
|
|
22
|
+
#
|
|
23
|
+
# You can also generate output like the +rdoc+ executable:
|
|
24
|
+
#
|
|
25
|
+
# rdoc = RDoc::RDoc.new
|
|
26
|
+
# rdoc.document argv
|
|
27
|
+
#
|
|
28
|
+
# Where +argv+ is an array of strings, each corresponding to an argument you'd
|
|
29
|
+
# give rdoc on the command line. See <tt>rdoc --help</tt> for details.
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
class RDoc
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
# List of directory names always skipped
|
|
33
|
+
@current = nil
|
|
40
34
|
|
|
41
|
-
|
|
35
|
+
##
|
|
36
|
+
# This is the list of supported output generators
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
# List of directory names skipped if test suites should be skipped
|
|
38
|
+
GENERATORS = {}
|
|
45
39
|
|
|
46
|
-
|
|
40
|
+
##
|
|
41
|
+
# List of directory names always skipped
|
|
47
42
|
|
|
43
|
+
UNCONDITIONALLY_SKIPPED_DIRECTORIES = %w[CVS .svn .git].freeze
|
|
48
44
|
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
##
|
|
46
|
+
# List of directory names skipped if test suites should be skipped
|
|
51
47
|
|
|
52
|
-
|
|
48
|
+
TEST_SUITE_DIRECTORY_NAMES = %w[spec test].freeze
|
|
53
49
|
|
|
54
|
-
##
|
|
55
|
-
# Hash of files and their last modified times.
|
|
56
50
|
|
|
57
|
-
|
|
51
|
+
##
|
|
52
|
+
# Generator instance used for creating output
|
|
58
53
|
|
|
59
|
-
|
|
60
|
-
# RDoc options
|
|
54
|
+
attr_accessor :generator
|
|
61
55
|
|
|
62
|
-
|
|
56
|
+
##
|
|
57
|
+
# Hash of files and their last modified times.
|
|
63
58
|
|
|
64
|
-
|
|
65
|
-
# Accessor for statistics. Available after each call to parse_files
|
|
59
|
+
attr_reader :last_modified
|
|
66
60
|
|
|
67
|
-
|
|
61
|
+
##
|
|
62
|
+
# RDoc options
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
# The current documentation store
|
|
64
|
+
attr_accessor :options
|
|
71
65
|
|
|
72
|
-
|
|
66
|
+
##
|
|
67
|
+
# Accessor for statistics. Available after each call to parse_files
|
|
73
68
|
|
|
74
|
-
|
|
75
|
-
# Add +klass+ that can generate output after parsing
|
|
69
|
+
attr_reader :stats
|
|
76
70
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
GENERATORS[name] = klass
|
|
80
|
-
end
|
|
71
|
+
##
|
|
72
|
+
# The current documentation store
|
|
81
73
|
|
|
82
|
-
|
|
83
|
-
# Active RDoc::RDoc instance
|
|
74
|
+
attr_accessor :store
|
|
84
75
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
end
|
|
76
|
+
##
|
|
77
|
+
# Add +klass+ that can generate output after parsing
|
|
88
78
|
|
|
89
|
-
|
|
90
|
-
|
|
79
|
+
def self.add_generator(klass)
|
|
80
|
+
name = klass.name.sub(/^RDoc::Generator::/, '').downcase
|
|
81
|
+
GENERATORS[name] = klass
|
|
82
|
+
end
|
|
91
83
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
end
|
|
84
|
+
##
|
|
85
|
+
# Active RDoc::RDoc instance
|
|
95
86
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def initialize
|
|
101
|
-
@current = nil
|
|
102
|
-
@generator = nil
|
|
103
|
-
@last_modified = {}
|
|
104
|
-
@old_siginfo = nil
|
|
105
|
-
@options = nil
|
|
106
|
-
@stats = nil
|
|
107
|
-
@store = nil
|
|
108
|
-
end
|
|
87
|
+
def self.current
|
|
88
|
+
@current
|
|
89
|
+
end
|
|
109
90
|
|
|
110
|
-
|
|
111
|
-
|
|
91
|
+
##
|
|
92
|
+
# Sets the active RDoc::RDoc instance
|
|
112
93
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
94
|
+
def self.current=(rdoc)
|
|
95
|
+
@current = rdoc
|
|
96
|
+
end
|
|
116
97
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
98
|
+
##
|
|
99
|
+
# Creates a new RDoc::RDoc instance. Call #document to parse files and
|
|
100
|
+
# generate documentation.
|
|
101
|
+
|
|
102
|
+
def initialize
|
|
103
|
+
@current = nil
|
|
104
|
+
@generator = nil
|
|
105
|
+
@last_modified = {}
|
|
106
|
+
@old_siginfo = nil
|
|
107
|
+
@options = nil
|
|
108
|
+
@stats = nil
|
|
109
|
+
@store = nil
|
|
110
|
+
end
|
|
120
111
|
|
|
121
|
-
|
|
122
|
-
|
|
112
|
+
##
|
|
113
|
+
# Report an error message and exit
|
|
123
114
|
|
|
124
|
-
|
|
115
|
+
def error(msg)
|
|
116
|
+
raise Error, msg
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
##
|
|
120
|
+
# Gathers a set of parseable files from the files and directories listed in
|
|
121
|
+
# +files+.
|
|
122
|
+
|
|
123
|
+
def gather_files(files)
|
|
124
|
+
files = [@options.root.to_s] if files.empty?
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
file_list = normalized_file_list files, true, @options.exclude
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
128
|
+
file_list = remove_duplicate_files(remove_unparseable(file_list))
|
|
129
|
+
|
|
130
|
+
if file_list.count {|name, mtime|
|
|
131
|
+
file_list[name] = @last_modified[name] unless mtime
|
|
132
|
+
mtime
|
|
133
|
+
} > 0
|
|
134
|
+
@last_modified.replace file_list
|
|
135
|
+
file_list.keys.sort
|
|
136
|
+
else
|
|
137
|
+
[]
|
|
138
|
+
end
|
|
136
139
|
end
|
|
137
|
-
end
|
|
138
140
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
+
##
|
|
142
|
+
# Turns RDoc from stdin into HTML
|
|
141
143
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
+
def handle_pipe
|
|
145
|
+
@html = Markup::ToHtml.new(pipe: @options.pipe, output_decoration: @options.output_decoration)
|
|
144
146
|
|
|
145
|
-
|
|
147
|
+
parser = Text::MARKUP_FORMAT[@options.markup]
|
|
146
148
|
|
|
147
|
-
|
|
149
|
+
document = parser.parse $stdin.read
|
|
148
150
|
|
|
149
|
-
|
|
151
|
+
out = @html.convert document
|
|
150
152
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
$stdout.write out
|
|
154
|
+
end
|
|
153
155
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
+
##
|
|
157
|
+
# Installs a siginfo handler that prints the current filename.
|
|
156
158
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
+
def install_siginfo_handler
|
|
160
|
+
return unless Signal.list.include? 'INFO'
|
|
159
161
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
+
@old_siginfo = trap 'INFO' do
|
|
163
|
+
puts @current if @current
|
|
164
|
+
end
|
|
162
165
|
end
|
|
163
|
-
end
|
|
164
166
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
##
|
|
168
|
+
# Create an output dir if it doesn't exist. If it does exist, but doesn't
|
|
169
|
+
# contain the flag file <tt>created.rid</tt> then we refuse to use it, as
|
|
170
|
+
# we may clobber some manually generated documentation
|
|
169
171
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
+
def setup_output_dir(dir, force)
|
|
173
|
+
flag_file = output_flag_file dir
|
|
172
174
|
|
|
173
|
-
|
|
175
|
+
last = {}
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
if @options.dry_run
|
|
178
|
+
# do nothing
|
|
179
|
+
elsif File.exist? dir
|
|
180
|
+
error "#{dir} exists and is not a directory" unless File.directory? dir
|
|
179
181
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
182
|
+
begin
|
|
183
|
+
File.open flag_file do |io|
|
|
184
|
+
unless force
|
|
185
|
+
Time.parse io.gets
|
|
186
|
+
|
|
187
|
+
io.each do |line|
|
|
188
|
+
file, time = line.split "\t", 2
|
|
189
|
+
time = Time.parse(time) rescue next
|
|
190
|
+
last[file] = time
|
|
191
|
+
end
|
|
189
192
|
end
|
|
190
193
|
end
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
error <<-ERROR
|
|
194
|
+
rescue SystemCallError, TypeError
|
|
195
|
+
error <<-ERROR
|
|
194
196
|
|
|
195
197
|
Directory #{dir} already exists, but it looks like it isn't an RDoc directory.
|
|
196
198
|
|
|
@@ -199,183 +201,182 @@ you'll need to specify a different output directory name (using the --op <dir>
|
|
|
199
201
|
option)
|
|
200
202
|
|
|
201
203
|
ERROR
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
end unless @options.force_output
|
|
205
|
+
else
|
|
206
|
+
FileUtils.mkdir_p dir
|
|
207
|
+
FileUtils.touch flag_file
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
last
|
|
206
211
|
end
|
|
207
212
|
|
|
208
|
-
|
|
209
|
-
|
|
213
|
+
##
|
|
214
|
+
# Update the flag file in an output directory.
|
|
210
215
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
unless ENV['SOURCE_DATE_EPOCH'].nil?
|
|
217
|
-
time = Time.at(ENV['SOURCE_DATE_EPOCH'].to_i).gmtime
|
|
218
|
-
end
|
|
216
|
+
def update_output_dir(op_dir, time, last = {})
|
|
217
|
+
return if @options.dry_run or not @options.update_output_dir
|
|
218
|
+
unless ENV['SOURCE_DATE_EPOCH'].nil?
|
|
219
|
+
time = Time.at(ENV['SOURCE_DATE_EPOCH'].to_i).gmtime
|
|
220
|
+
end
|
|
219
221
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
File.open output_flag_file(op_dir), "w" do |f|
|
|
223
|
+
f.puts time.rfc2822
|
|
224
|
+
last.each do |n, t|
|
|
225
|
+
f.puts "#{n}\t#{t.rfc2822}"
|
|
226
|
+
end
|
|
224
227
|
end
|
|
225
228
|
end
|
|
226
|
-
end
|
|
227
229
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
+
##
|
|
231
|
+
# Return the path name of the flag file in an output directory.
|
|
230
232
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
233
|
+
def output_flag_file(op_dir)
|
|
234
|
+
File.join op_dir, "created.rid"
|
|
235
|
+
end
|
|
234
236
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
##
|
|
238
|
+
# The .document file contains a list of file and directory name patterns,
|
|
239
|
+
# representing candidates for documentation. It may also contain comments
|
|
240
|
+
# (starting with '#')
|
|
239
241
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
242
|
+
def parse_dot_doc_file(in_dir, filename)
|
|
243
|
+
# read and strip comments
|
|
244
|
+
patterns = File.read(filename).gsub(/#.*/, '')
|
|
243
245
|
|
|
244
|
-
|
|
246
|
+
result = {}
|
|
245
247
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
patterns.split(' ').each do |patt|
|
|
249
|
+
candidates = Dir.glob(File.join(in_dir, patt))
|
|
250
|
+
result.update normalized_file_list(candidates, false, @options.exclude)
|
|
251
|
+
end
|
|
250
252
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
+
result
|
|
254
|
+
end
|
|
253
255
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
256
|
+
##
|
|
257
|
+
# Given a list of files and directories, create a list of all the Ruby
|
|
258
|
+
# files they contain.
|
|
259
|
+
#
|
|
260
|
+
# If +force_doc+ is true we always add the given files, if false, only
|
|
261
|
+
# add files that we guarantee we can parse. It is true when looking at
|
|
262
|
+
# files given on the command line, false when recursing through
|
|
263
|
+
# subdirectories.
|
|
264
|
+
#
|
|
265
|
+
# The effect of this is that if you want a file with a non-standard
|
|
266
|
+
# extension parsed, you must name it explicitly.
|
|
267
|
+
|
|
268
|
+
def normalized_file_list(relative_files, force_doc = false,
|
|
269
|
+
exclude_pattern = nil)
|
|
270
|
+
file_list = {}
|
|
271
|
+
|
|
272
|
+
relative_files.each do |rel_file_name|
|
|
273
|
+
rel_file_name = rel_file_name.sub(/^\.\//, '')
|
|
274
|
+
next if rel_file_name.end_with? 'created.rid'
|
|
275
|
+
next if exclude_pattern && exclude_pattern =~ rel_file_name
|
|
276
|
+
stat = File.stat rel_file_name rescue next
|
|
277
|
+
|
|
278
|
+
case type = stat.ftype
|
|
279
|
+
when "file"
|
|
280
|
+
mtime = (stat.mtime unless (last_modified = @last_modified[rel_file_name] and
|
|
281
|
+
stat.mtime.to_i <= last_modified.to_i))
|
|
282
|
+
|
|
283
|
+
if force_doc or Parser.can_parse(rel_file_name)
|
|
284
|
+
file_list[rel_file_name] = mtime
|
|
285
|
+
end
|
|
286
|
+
when "directory"
|
|
287
|
+
next if UNCONDITIONALLY_SKIPPED_DIRECTORIES.include?(rel_file_name)
|
|
286
288
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
+
basename = File.basename(rel_file_name)
|
|
290
|
+
next if options.skip_tests && TEST_SUITE_DIRECTORY_NAMES.include?(basename)
|
|
289
291
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
+
created_rid = File.join rel_file_name, "created.rid"
|
|
293
|
+
next if File.file? created_rid
|
|
292
294
|
|
|
293
|
-
|
|
295
|
+
dot_doc = File.join rel_file_name, DOT_DOC_FILENAME
|
|
294
296
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
+
if File.file? dot_doc
|
|
298
|
+
file_list.update(parse_dot_doc_file(rel_file_name, dot_doc))
|
|
299
|
+
else
|
|
300
|
+
file_list.update(list_files_in_directory(rel_file_name))
|
|
301
|
+
end
|
|
297
302
|
else
|
|
298
|
-
|
|
303
|
+
warn "rdoc can't parse the #{type} #{rel_file_name}"
|
|
299
304
|
end
|
|
300
|
-
else
|
|
301
|
-
warn "rdoc can't parse the #{type} #{rel_file_name}"
|
|
302
305
|
end
|
|
303
|
-
end
|
|
304
306
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
##
|
|
309
|
-
# Return a list of the files to be processed in a directory. We know that
|
|
310
|
-
# this directory doesn't have a .document file, so we're looking for real
|
|
311
|
-
# files. However we may well contain subdirectories which must be tested
|
|
312
|
-
# for .document files.
|
|
313
|
-
|
|
314
|
-
def list_files_in_directory(dir)
|
|
315
|
-
files = Dir.glob File.join(dir, "*")
|
|
307
|
+
file_list
|
|
308
|
+
end
|
|
316
309
|
|
|
317
|
-
|
|
318
|
-
|
|
310
|
+
##
|
|
311
|
+
# Return a list of the files to be processed in a directory. We know that
|
|
312
|
+
# this directory doesn't have a .document file, so we're looking for real
|
|
313
|
+
# files. However we may well contain subdirectories which must be tested
|
|
314
|
+
# for .document files.
|
|
319
315
|
|
|
320
|
-
|
|
321
|
-
|
|
316
|
+
def list_files_in_directory(dir)
|
|
317
|
+
files = Dir.glob File.join(dir, "*")
|
|
322
318
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
filename = filename.encode encoding
|
|
319
|
+
normalized_file_list files, false, @options.exclude
|
|
320
|
+
end
|
|
326
321
|
|
|
327
|
-
|
|
322
|
+
##
|
|
323
|
+
# Parses +filename+ and returns an RDoc::TopLevel
|
|
328
324
|
|
|
329
|
-
|
|
325
|
+
def parse_file(filename)
|
|
326
|
+
encoding = @options.encoding
|
|
327
|
+
filename = filename.encode encoding
|
|
330
328
|
|
|
331
|
-
|
|
329
|
+
@stats.add_file filename
|
|
332
330
|
|
|
333
|
-
|
|
331
|
+
return if Parser.binary? filename
|
|
334
332
|
|
|
335
|
-
|
|
336
|
-
begin
|
|
337
|
-
relative_path = filename_path.relative_path_from @options.root
|
|
338
|
-
rescue ArgumentError
|
|
339
|
-
relative_path = filename_path
|
|
340
|
-
end
|
|
333
|
+
content = Encoding.read_file filename, encoding
|
|
341
334
|
|
|
342
|
-
|
|
343
|
-
relative_path.to_s.start_with? @options.page_dir.to_s then
|
|
344
|
-
relative_path =
|
|
345
|
-
relative_path.relative_path_from @options.page_dir
|
|
346
|
-
end
|
|
335
|
+
return unless content
|
|
347
336
|
|
|
348
|
-
|
|
337
|
+
top_level = @store.add_file filename, relative_name: relative_path_for(filename)
|
|
349
338
|
|
|
350
|
-
|
|
339
|
+
parser = Parser.for top_level, content, @options, @stats
|
|
351
340
|
|
|
352
|
-
|
|
341
|
+
return unless parser
|
|
353
342
|
|
|
354
|
-
|
|
343
|
+
parser.scan
|
|
355
344
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
345
|
+
# restart documentation for the classes & modules found
|
|
346
|
+
top_level.classes_or_modules.each do |cm|
|
|
347
|
+
cm.done_documenting = false
|
|
348
|
+
end
|
|
360
349
|
|
|
361
|
-
|
|
350
|
+
top_level
|
|
362
351
|
|
|
363
|
-
|
|
364
|
-
|
|
352
|
+
rescue Errno::EACCES => e
|
|
353
|
+
$stderr.puts <<-EOF
|
|
365
354
|
Unable to read #{filename}, #{e.message}
|
|
366
355
|
|
|
367
356
|
Please check the permissions for this file. Perhaps you do not have access to
|
|
368
357
|
it or perhaps the original author's permissions are to restrictive. If the
|
|
369
358
|
this is not your library please report a bug to the author.
|
|
370
359
|
EOF
|
|
371
|
-
|
|
372
|
-
|
|
360
|
+
rescue => e
|
|
361
|
+
syntax_check_command = syntax_check_command_for filename, parser&.class
|
|
362
|
+
syntax_check_message = if syntax_check_command
|
|
363
|
+
<<~MESSAGE
|
|
373
364
|
Before reporting this, could you check that the file you're documenting
|
|
374
365
|
has proper syntax:
|
|
375
366
|
|
|
376
|
-
#{
|
|
367
|
+
#{syntax_check_command}
|
|
368
|
+
MESSAGE
|
|
369
|
+
else
|
|
370
|
+
<<~MESSAGE
|
|
371
|
+
Before reporting this, could you check that the file you're documenting
|
|
372
|
+
has proper syntax for its language?
|
|
373
|
+
MESSAGE
|
|
374
|
+
end
|
|
377
375
|
|
|
378
|
-
|
|
376
|
+
$stderr.puts <<-EOF
|
|
377
|
+
#{syntax_check_message}
|
|
378
|
+
RDoc's parsers are not full language parsers and may fail when fed invalid
|
|
379
|
+
source files.
|
|
379
380
|
|
|
380
381
|
The internal error was:
|
|
381
382
|
|
|
@@ -383,158 +384,338 @@ The internal error was:
|
|
|
383
384
|
|
|
384
385
|
EOF
|
|
385
386
|
|
|
386
|
-
|
|
387
|
+
$stderr.puts e.backtrace.join("\n\t") if $DEBUG_RDOC
|
|
387
388
|
|
|
388
|
-
|
|
389
|
-
|
|
389
|
+
raise e
|
|
390
|
+
end
|
|
390
391
|
|
|
391
|
-
|
|
392
|
-
|
|
392
|
+
def syntax_check_command_for(filename, parser_class = Parser.can_parse_by_name(filename))
|
|
393
|
+
if parser_class == Parser::Ruby
|
|
394
|
+
"#{Gem.ruby} -c #{filename}"
|
|
395
|
+
elsif parser_class == Parser::C
|
|
396
|
+
cc = ENV['CC']
|
|
397
|
+
cc = 'cc' if cc.nil? || cc.empty?
|
|
398
|
+
"#{cc} -fsyntax-only #{filename}"
|
|
399
|
+
end
|
|
400
|
+
end
|
|
393
401
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
402
|
+
##
|
|
403
|
+
# Returns the relative path for +filename+ against +options.root+ (and
|
|
404
|
+
# +options.page_dir+ when set). This is the key used by RDoc::Store to
|
|
405
|
+
# identify files.
|
|
397
406
|
|
|
398
|
-
|
|
407
|
+
def relative_path_for(filename)
|
|
408
|
+
filename_path = Pathname(filename).expand_path
|
|
409
|
+
begin
|
|
410
|
+
relative_path = filename_path.relative_path_from @options.root
|
|
411
|
+
rescue ArgumentError
|
|
412
|
+
relative_path = filename_path
|
|
413
|
+
end
|
|
399
414
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
415
|
+
if @options.page_dir &&
|
|
416
|
+
relative_path.to_s.start_with?(@options.page_dir.to_s)
|
|
417
|
+
relative_path =
|
|
418
|
+
relative_path.relative_path_from @options.page_dir
|
|
419
|
+
end
|
|
403
420
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
parse_file filename
|
|
407
|
-
end.compact
|
|
421
|
+
relative_path.to_s
|
|
422
|
+
end
|
|
408
423
|
|
|
409
|
-
|
|
424
|
+
##
|
|
425
|
+
# Parse each file on the command line, recursively entering directories.
|
|
410
426
|
|
|
411
|
-
|
|
412
|
-
|
|
427
|
+
def parse_files(files)
|
|
428
|
+
file_list = gather_files files
|
|
429
|
+
@stats = Stats.new @store, file_list.length, @options.verbosity
|
|
413
430
|
|
|
414
|
-
|
|
415
|
-
end
|
|
431
|
+
return [] if file_list.empty?
|
|
416
432
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
433
|
+
# This workaround can be removed after the :main: directive is removed
|
|
434
|
+
original_options = @options.dup
|
|
435
|
+
@stats.begin_adding
|
|
436
|
+
|
|
437
|
+
file_info = file_list.map do |filename|
|
|
438
|
+
@current = filename
|
|
439
|
+
parse_file filename
|
|
440
|
+
end.compact
|
|
441
|
+
|
|
442
|
+
@store.resolve_c_superclasses
|
|
420
443
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
/\A(\f\n[^,]+,\d+$|!_TAG_)/.match?(File.binread(file, 100)))
|
|
444
|
+
@stats.done_adding
|
|
445
|
+
@options = original_options
|
|
446
|
+
|
|
447
|
+
file_info
|
|
426
448
|
end
|
|
427
|
-
end
|
|
428
449
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
#
|
|
433
|
-
# +options+ can be either an RDoc::Options instance or an array of strings
|
|
434
|
-
# equivalent to the strings that would be passed on the command line like
|
|
435
|
-
# <tt>%w[-q -o doc -t My\ Doc\ Title]</tt>. #document will automatically
|
|
436
|
-
# call RDoc::Options#finish if an options instance was given.
|
|
437
|
-
#
|
|
438
|
-
# For a list of options, see either RDoc::Options or <tt>rdoc --help</tt>.
|
|
439
|
-
#
|
|
440
|
-
# By default, output will be stored in a directory called "doc" below the
|
|
441
|
-
# current directory, so make sure you're somewhere writable before invoking.
|
|
450
|
+
##
|
|
451
|
+
# Removes file extensions known to be unparseable from +files+ and TAGS
|
|
452
|
+
# files for emacs and vim.
|
|
442
453
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
454
|
+
def remove_unparseable(files)
|
|
455
|
+
files.reject do |file, *|
|
|
456
|
+
file =~ /\.(?:class|eps|erb|scpt\.txt|svg|ttf|yml)\z/i or
|
|
457
|
+
(file =~ /tags\z/i and
|
|
458
|
+
/\A(\f\n[^,]+,\d+$|!_TAG_)/.match?(File.binread(file, 100)))
|
|
459
|
+
end
|
|
449
460
|
end
|
|
450
|
-
@options.finish
|
|
451
461
|
|
|
452
|
-
|
|
462
|
+
##
|
|
463
|
+
# Removes duplicate canonical paths while preserving the first path found.
|
|
453
464
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
exit
|
|
465
|
+
def remove_duplicate_files(files)
|
|
466
|
+
files.uniq { |file,| File.realpath(file) }.to_h
|
|
457
467
|
end
|
|
458
468
|
|
|
459
|
-
|
|
460
|
-
|
|
469
|
+
##
|
|
470
|
+
# Generates documentation or a coverage report depending upon the settings
|
|
471
|
+
# in +options+.
|
|
472
|
+
#
|
|
473
|
+
# +options+ can be either an RDoc::Options instance or an array of strings
|
|
474
|
+
# equivalent to the strings that would be passed on the command line like
|
|
475
|
+
# <tt>%w[-q -o doc -t My\ Doc\ Title]</tt>. #document will automatically
|
|
476
|
+
# call RDoc::Options#finish if an options instance was given.
|
|
477
|
+
#
|
|
478
|
+
# For a list of options, see either RDoc::Options or <tt>rdoc --help</tt>.
|
|
479
|
+
#
|
|
480
|
+
# By default, output will be stored in a directory called "doc" below the
|
|
481
|
+
# current directory, so make sure you're somewhere writable before invoking.
|
|
482
|
+
|
|
483
|
+
def document(options)
|
|
484
|
+
if Options === options
|
|
485
|
+
@options = options
|
|
486
|
+
else
|
|
487
|
+
@options = Options.load_options
|
|
488
|
+
@options.parse options
|
|
489
|
+
end
|
|
490
|
+
@options.finish
|
|
491
|
+
|
|
492
|
+
@store = Store.new(@options)
|
|
493
|
+
|
|
494
|
+
if @options.pipe
|
|
495
|
+
handle_pipe
|
|
496
|
+
exit
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
if @options.server_port
|
|
500
|
+
@store.load_cache
|
|
501
|
+
|
|
502
|
+
parse_files @options.files
|
|
503
|
+
record_auto_discovered_rbs_signature_mtimes
|
|
504
|
+
|
|
505
|
+
@options.default_title = "RDoc Documentation"
|
|
506
|
+
|
|
507
|
+
load_auto_discovered_rbs_signatures
|
|
508
|
+
@store.complete @options.visibility
|
|
509
|
+
|
|
510
|
+
start_server
|
|
511
|
+
exit
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
unless @options.coverage_report
|
|
515
|
+
@last_modified = setup_output_dir @options.op_dir, @options.force_update
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
@start_time = Time.now
|
|
519
|
+
|
|
520
|
+
@store.load_cache
|
|
521
|
+
|
|
522
|
+
auto_discovered_rbs_signatures_changed = auto_discovered_rbs_signatures_changed?
|
|
523
|
+
# When only auto-discovered RBS signatures changed, no Ruby file would be
|
|
524
|
+
# reparsed under normal mtime checks. The store cache holds class metadata
|
|
525
|
+
# but not live RDoc::Context objects, so the generator would have nothing
|
|
526
|
+
# to iterate. Force a full reparse so updated signatures show up in the
|
|
527
|
+
# rendered output.
|
|
528
|
+
@last_modified.clear if auto_discovered_rbs_signatures_changed
|
|
529
|
+
|
|
530
|
+
file_info = parse_files @options.files
|
|
531
|
+
record_auto_discovered_rbs_signature_mtimes
|
|
532
|
+
|
|
533
|
+
@options.default_title = "RDoc Documentation"
|
|
534
|
+
|
|
535
|
+
load_auto_discovered_rbs_signatures
|
|
536
|
+
|
|
537
|
+
@store.complete @options.visibility
|
|
538
|
+
|
|
539
|
+
@stats.coverage_level = @options.coverage_report
|
|
540
|
+
|
|
541
|
+
if @options.coverage_report
|
|
542
|
+
puts
|
|
543
|
+
|
|
544
|
+
puts @stats.report
|
|
545
|
+
elsif file_info.empty? && !auto_discovered_rbs_signatures_changed
|
|
546
|
+
$stderr.puts "\nNo newer files." unless @options.quiet
|
|
547
|
+
else
|
|
548
|
+
gen_klass = @options.generator
|
|
549
|
+
|
|
550
|
+
@generator = gen_klass.new @store, @options
|
|
551
|
+
|
|
552
|
+
generate
|
|
553
|
+
end
|
|
554
|
+
|
|
555
|
+
if @stats and (@options.coverage_report or not @options.quiet)
|
|
556
|
+
puts
|
|
557
|
+
puts @stats.summary
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
exit @stats.fully_documented? if @options.coverage_report
|
|
461
561
|
end
|
|
462
562
|
|
|
463
|
-
|
|
563
|
+
##
|
|
564
|
+
# Generates documentation for +file_info+ (from #parse_files) into the
|
|
565
|
+
# output dir using the generator selected
|
|
566
|
+
# by the RDoc options
|
|
464
567
|
|
|
465
|
-
|
|
568
|
+
def generate
|
|
569
|
+
if @options.dry_run
|
|
570
|
+
# do nothing
|
|
571
|
+
@generator.generate
|
|
572
|
+
else
|
|
573
|
+
Dir.chdir @options.op_dir do
|
|
574
|
+
unless @options.quiet
|
|
575
|
+
$stderr.puts "\nGenerating #{@generator.class.name.sub(/^.*::/, '')} format into #{Dir.pwd}..."
|
|
576
|
+
uri = "file://#{Dir.pwd}/index.html"
|
|
577
|
+
ref = $stderr.tty? ? "\e]8;;#{uri}\e\\#{uri}\e]8;;\e\\" : uri
|
|
578
|
+
$stderr.puts "\nYou can visit the home page at: #{ref}"
|
|
579
|
+
end
|
|
466
580
|
|
|
467
|
-
|
|
581
|
+
@generator.generate
|
|
582
|
+
update_output_dir '.', @start_time, @last_modified
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
end
|
|
468
586
|
|
|
469
|
-
|
|
587
|
+
##
|
|
588
|
+
# Loads RBS type signatures from the project's +sig+ directory and RBS
|
|
589
|
+
# stdlib, then merges them into the store's code objects.
|
|
590
|
+
|
|
591
|
+
def load_auto_discovered_rbs_signatures
|
|
592
|
+
sig_dirs = []
|
|
593
|
+
sig_dir = File.join(@options.root.to_s, 'sig')
|
|
594
|
+
sig_dirs << sig_dir if File.directory?(sig_dir)
|
|
595
|
+
signatures = RbsHelper.load_signatures(*sig_dirs)
|
|
596
|
+
@store.merge_rbs_signatures(signatures)
|
|
597
|
+
rescue RBS::BaseError, Errno::ENOENT, LoadError => e
|
|
598
|
+
# In server mode, a previous successful load may have populated the store;
|
|
599
|
+
# drop those signatures so a now-broken sig file doesn't keep showing
|
|
600
|
+
# stale types alongside the warning.
|
|
601
|
+
@store.clear_rbs_signatures
|
|
602
|
+
@options.warn "Failed to load RBS type signatures: #{e.message}"
|
|
603
|
+
end
|
|
470
604
|
|
|
471
|
-
|
|
605
|
+
##
|
|
606
|
+
# Returns RBS files that RDoc auto-discovers for signature loading.
|
|
472
607
|
|
|
473
|
-
|
|
608
|
+
def auto_discovered_rbs_signature_files
|
|
609
|
+
Dir[File.join(@options.root.to_s, 'sig', '**', '*.rbs')].sort
|
|
610
|
+
end
|
|
474
611
|
|
|
475
|
-
|
|
476
|
-
|
|
612
|
+
##
|
|
613
|
+
# Returns true if any auto-discovered RBS signature file has changed since
|
|
614
|
+
# the last run.
|
|
477
615
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
else
|
|
482
|
-
gen_klass = @options.generator
|
|
616
|
+
def auto_discovered_rbs_signatures_changed?
|
|
617
|
+
current = auto_discovered_rbs_signature_mtimes
|
|
618
|
+
previous = @last_modified.select { |file, _| auto_discovered_rbs_signature_file?(file) }
|
|
483
619
|
|
|
484
|
-
|
|
620
|
+
return true unless (previous.keys - current.keys).empty?
|
|
485
621
|
|
|
486
|
-
|
|
622
|
+
current.any? do |file, mtime|
|
|
623
|
+
last_modified = @last_modified[file]
|
|
624
|
+
last_modified.nil? || mtime.to_i > last_modified.to_i
|
|
625
|
+
end
|
|
487
626
|
end
|
|
488
627
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
628
|
+
##
|
|
629
|
+
# Records auto-discovered RBS signature file mtimes so normal generation
|
|
630
|
+
# freshness checks and the live server watcher can see signature-only edits.
|
|
631
|
+
|
|
632
|
+
def record_auto_discovered_rbs_signature_mtimes
|
|
633
|
+
@last_modified.reject! { |file, _| auto_discovered_rbs_signature_file?(file) }
|
|
634
|
+
@last_modified.merge! auto_discovered_rbs_signature_mtimes
|
|
492
635
|
end
|
|
493
636
|
|
|
494
|
-
|
|
495
|
-
|
|
637
|
+
##
|
|
638
|
+
# Files watched by the live preview server.
|
|
496
639
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
# by the RDoc options
|
|
501
|
-
|
|
502
|
-
def generate
|
|
503
|
-
if @options.dry_run then
|
|
504
|
-
# do nothing
|
|
505
|
-
@generator.generate
|
|
506
|
-
else
|
|
507
|
-
Dir.chdir @options.op_dir do
|
|
508
|
-
unless @options.quiet then
|
|
509
|
-
$stderr.puts "\nGenerating #{@generator.class.name.sub(/^.*::/, '')} format into #{Dir.pwd}..."
|
|
510
|
-
$stderr.puts "\nYou can visit the home page at: \e]8;;file://#{Dir.pwd}/index.html\e\\file://#{Dir.pwd}/index.html\e]8;;\e\\"
|
|
511
|
-
end
|
|
640
|
+
def watch_files
|
|
641
|
+
(@last_modified.keys + auto_discovered_rbs_signature_files).uniq
|
|
642
|
+
end
|
|
512
643
|
|
|
513
|
-
|
|
514
|
-
|
|
644
|
+
##
|
|
645
|
+
# Returns true for project RBS files that are auto-discovered for signature
|
|
646
|
+
# loading. RDoc parses any selected .rbs file as documentation input, but
|
|
647
|
+
# only +sig/**/*.rbs+ files are loaded through RBS::EnvironmentLoader for
|
|
648
|
+
# type signature merging and live-reload bookkeeping.
|
|
649
|
+
|
|
650
|
+
def auto_discovered_rbs_signature_file?(file) # :nodoc:
|
|
651
|
+
return false unless File.extname(file) == '.rbs'
|
|
652
|
+
|
|
653
|
+
root = Pathname(@options.root.to_s).expand_path
|
|
654
|
+
relative_path = Pathname(file).expand_path.relative_path_from root
|
|
655
|
+
relative_path.each_filename.first == 'sig'
|
|
656
|
+
rescue ArgumentError
|
|
657
|
+
# file and root may be on different drives on Windows
|
|
658
|
+
false
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
##
|
|
662
|
+
# Returns mtimes for auto-discovered RBS signature files.
|
|
663
|
+
|
|
664
|
+
def auto_discovered_rbs_signature_mtimes # :nodoc:
|
|
665
|
+
auto_discovered_rbs_signature_files.each_with_object({}) do |file, mtimes|
|
|
666
|
+
mtime = ::RDoc.safe_mtime(file)
|
|
667
|
+
mtimes[file] = mtime if mtime
|
|
515
668
|
end
|
|
516
669
|
end
|
|
517
|
-
end
|
|
518
670
|
|
|
519
|
-
|
|
520
|
-
|
|
671
|
+
##
|
|
672
|
+
# Starts a live-reloading HTTP server for previewing documentation.
|
|
673
|
+
# Called from #document when <tt>--server</tt> is given.
|
|
521
674
|
|
|
522
|
-
|
|
523
|
-
|
|
675
|
+
def start_server
|
|
676
|
+
server = Server.new(self, @options.server_port)
|
|
677
|
+
server.start
|
|
678
|
+
end
|
|
524
679
|
|
|
525
|
-
|
|
680
|
+
##
|
|
681
|
+
# Removes a siginfo handler and replaces the previous
|
|
526
682
|
|
|
527
|
-
|
|
528
|
-
|
|
683
|
+
def remove_siginfo_handler
|
|
684
|
+
return unless Signal.list.key? 'INFO'
|
|
685
|
+
|
|
686
|
+
handler = @old_siginfo || 'DEFAULT'
|
|
529
687
|
|
|
688
|
+
trap 'INFO', handler
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
##
|
|
692
|
+
# Returns true when +extension+ is the RBS gem's RDoc discovery hook.
|
|
693
|
+
# Released RBS gems install their plugin through this hook, so skip it to
|
|
694
|
+
# avoid replacing the built-in parser during discovery.
|
|
695
|
+
|
|
696
|
+
def self.rbs_discovery_extension?(extension) # :nodoc:
|
|
697
|
+
extension = File.expand_path(extension)
|
|
698
|
+
|
|
699
|
+
Gem::Specification.find_all_by_name('rbs').any? do |spec|
|
|
700
|
+
File.expand_path('lib/rdoc/discover.rb', spec.full_gem_path) == extension
|
|
701
|
+
end
|
|
702
|
+
end
|
|
703
|
+
|
|
704
|
+
end
|
|
530
705
|
end
|
|
531
706
|
|
|
707
|
+
# Load built-in parser registrations before RubyGems discovery, then skip the
|
|
708
|
+
# RBS gem's plugin hook so it cannot replace RDoc::Parser::RBS.
|
|
709
|
+
require_relative 'parser'
|
|
710
|
+
|
|
532
711
|
begin
|
|
533
712
|
require 'rubygems'
|
|
534
713
|
|
|
535
714
|
rdoc_extensions = Gem.find_latest_files 'rdoc/discover'
|
|
536
715
|
|
|
537
716
|
rdoc_extensions.each do |extension|
|
|
717
|
+
next if RDoc::RDoc.rbs_discovery_extension?(extension)
|
|
718
|
+
|
|
538
719
|
begin
|
|
539
720
|
load extension
|
|
540
721
|
rescue => e
|