Skip to content

Commit ee289f4

Browse files
authored
Merge pull request #1 from kou/add-rubygems-hook-default-gem
Add support for the case that RDoc is installed as a default gem
2 parents a6cddd8 + 75c928d commit ee289f4

File tree

2 files changed

+291
-270
lines changed

2 files changed

+291
-270
lines changed

lib/rdoc/rubygems_hook.rb

Lines changed: 290 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,300 @@
1+
# frozen_string_literal: true
2+
3+
require 'rubygems/user_interaction'
4+
require 'fileutils'
5+
6+
require_relative '../rdoc'
7+
8+
# We define the following two similar name classes in this file:
19
#
10+
# - RDoc::RubyGemsHook
11+
# - RDoc::RubygemsHook
12+
#
13+
# RDoc::RubyGemsHook is the main class that has real logic.
14+
#
15+
# RDoc::RubygemsHook is a class that is only for
16+
# compatibility. RDoc::RubygemsHook is used by RubyGems directly. We
17+
# can remove this when all maintained RubyGems remove
18+
# `rubygems/rdoc.rb`.
19+
20+
class RDoc::RubyGemsHook
21+
22+
include Gem::UserInteraction
23+
extend Gem::UserInteraction
24+
25+
@rdoc_version = nil
26+
@specs = []
27+
28+
##
29+
# Force installation of documentation?
30+
31+
attr_accessor :force
32+
33+
##
34+
# Generate rdoc?
35+
36+
attr_accessor :generate_rdoc
37+
38+
##
39+
# Generate ri data?
40+
41+
attr_accessor :generate_ri
42+
43+
class << self
44+
45+
##
46+
# Loaded version of RDoc. Set by ::load_rdoc
47+
48+
attr_reader :rdoc_version
49+
50+
end
51+
52+
##
53+
# Post installs hook that generates documentation for each specification in
54+
# +specs+
55+
56+
def self.generate installer, specs
57+
start = Time.now
58+
types = installer.document
59+
60+
generate_rdoc = types.include? 'rdoc'
61+
generate_ri = types.include? 'ri'
62+
63+
specs.each do |spec|
64+
new(spec, generate_rdoc, generate_ri).generate
65+
end
66+
67+
return unless generate_rdoc or generate_ri
68+
69+
duration = (Time.now - start).to_i
70+
names = specs.map(&:name).join ', '
71+
72+
say "Done installing documentation for #{names} after #{duration} seconds"
73+
end
74+
75+
def self.remove uninstaller
76+
new(uninstaller.spec).remove
77+
end
78+
79+
##
80+
# Loads the RDoc generator
81+
82+
def self.load_rdoc
83+
return if @rdoc_version
84+
85+
require_relative 'rdoc'
86+
87+
@rdoc_version = Gem::Version.new ::RDoc::VERSION
88+
end
89+
90+
##
91+
# Creates a new documentation generator for +spec+. RDoc and ri data
92+
# generation can be enabled or disabled through +generate_rdoc+ and
93+
# +generate_ri+ respectively.
94+
#
95+
# Only +generate_ri+ is enabled by default.
96+
97+
def initialize spec, generate_rdoc = false, generate_ri = true
98+
@doc_dir = spec.doc_dir
99+
@force = false
100+
@rdoc = nil
101+
@spec = spec
102+
103+
@generate_rdoc = generate_rdoc
104+
@generate_ri = generate_ri
105+
106+
@rdoc_dir = spec.doc_dir 'rdoc'
107+
@ri_dir = spec.doc_dir 'ri'
108+
end
109+
110+
##
111+
# Removes legacy rdoc arguments from +args+
112+
#--
113+
# TODO move to RDoc::Options
114+
115+
def delete_legacy_args args
116+
args.delete '--inline-source'
117+
args.delete '--promiscuous'
118+
args.delete '-p'
119+
args.delete '--one-file'
120+
end
121+
122+
##
123+
# Generates documentation using the named +generator+ ("darkfish" or "ri")
124+
# and following the given +options+.
125+
#
126+
# Documentation will be generated into +destination+
127+
128+
def document generator, options, destination
129+
generator_name = generator
130+
131+
options = options.dup
132+
options.exclude ||= [] # TODO maybe move to RDoc::Options#finish
133+
options.setup_generator generator
134+
options.op_dir = destination
135+
Dir.chdir @spec.full_gem_path do
136+
options.finish
137+
end
138+
139+
generator = options.generator.new @rdoc.store, options
140+
141+
@rdoc.options = options
142+
@rdoc.generator = generator
143+
144+
say "Installing #{generator_name} documentation for #{@spec.full_name}"
145+
146+
FileUtils.mkdir_p options.op_dir
147+
148+
Dir.chdir options.op_dir do
149+
begin
150+
@rdoc.class.current = @rdoc
151+
@rdoc.generator.generate
152+
ensure
153+
@rdoc.class.current = nil
154+
end
155+
end
156+
end
157+
158+
##
159+
# Generates RDoc and ri data
160+
161+
def generate
162+
return if @spec.default_gem?
163+
return unless @generate_ri or @generate_rdoc
164+
165+
setup
166+
167+
options = nil
168+
169+
args = @spec.rdoc_options
170+
args.concat @spec.source_paths
171+
args.concat @spec.extra_rdoc_files
172+
173+
case config_args = Gem.configuration[:rdoc]
174+
when String then
175+
args = args.concat config_args.split(' ')
176+
when Array then
177+
args = args.concat config_args
178+
end
179+
180+
delete_legacy_args args
181+
182+
Dir.chdir @spec.full_gem_path do
183+
options = ::RDoc::Options.new
184+
options.default_title = "#{@spec.full_name} Documentation"
185+
options.parse args
186+
end
187+
188+
options.quiet = !Gem.configuration.really_verbose
189+
190+
@rdoc = new_rdoc
191+
@rdoc.options = options
192+
193+
store = RDoc::Store.new
194+
store.encoding = options.encoding
195+
store.dry_run = options.dry_run
196+
store.main = options.main_page
197+
store.title = options.title
198+
199+
@rdoc.store = store
200+
201+
say "Parsing documentation for #{@spec.full_name}"
202+
203+
Dir.chdir @spec.full_gem_path do
204+
@rdoc.parse_files options.files
205+
end
206+
207+
document 'ri', options, @ri_dir if
208+
@generate_ri and (@force or not File.exist? @ri_dir)
209+
210+
document 'darkfish', options, @rdoc_dir if
211+
@generate_rdoc and (@force or not File.exist? @rdoc_dir)
212+
end
213+
214+
##
215+
# #new_rdoc creates a new RDoc instance. This method is provided only to
216+
# make testing easier.
217+
218+
def new_rdoc # :nodoc:
219+
::RDoc::RDoc.new
220+
end
221+
222+
##
223+
# Is rdoc documentation installed?
224+
225+
def rdoc_installed?
226+
File.exist? @rdoc_dir
227+
end
228+
229+
##
230+
# Removes generated RDoc and ri data
231+
232+
def remove
233+
base_dir = @spec.base_dir
234+
235+
raise Gem::FilePermissionError, base_dir unless File.writable? base_dir
236+
237+
FileUtils.rm_rf @rdoc_dir
238+
FileUtils.rm_rf @ri_dir
239+
end
240+
241+
##
242+
# Is ri data installed?
243+
244+
def ri_installed?
245+
File.exist? @ri_dir
246+
end
247+
248+
##
249+
# Prepares the spec for documentation generation
250+
251+
def setup
252+
self.class.load_rdoc
253+
254+
raise Gem::FilePermissionError, @doc_dir if
255+
File.exist?(@doc_dir) and not File.writable?(@doc_dir)
256+
257+
FileUtils.mkdir_p @doc_dir unless File.exist? @doc_dir
258+
end
259+
260+
end
261+
2262
# This class is referenced by RubyGems to create documents.
3-
# Now, methods are moved to rubygems_plugin.rb.
263+
# All implementations are moved to the above RubyGemsHook.
264+
#
265+
# This class does nothing when this RDoc is installed as a normal gem
266+
# or a bundled gem.
4267
#
5-
# When old version RDoc is not used,
6-
# this class is not used from RubyGems too.
7-
# Then, remove this class.
268+
# This class does generate/remove documents for compatibility when
269+
# this RDoc is installed as a default gem.
8270
#
271+
# We can remove this when all maintained RubyGems remove
272+
# `rubygems/rdoc.rb`.
9273
module RDoc
10274
class RubygemsHook
11-
def initialize(spec); end
275+
def self.default_gem?
276+
!File.exist?(File.join(__dir__, "..", "rubygems_plugin.rb"))
277+
end
278+
279+
def initialize(spec)
280+
@spec = spec
281+
end
282+
283+
def remove
284+
# Do nothing if this is NOT a default gem.
285+
return unless self.class.default_gem?
286+
287+
# Remove generate document for compatibility if this is a
288+
# default gem.
289+
RubyGemsHook.new(@spec).remove
290+
end
12291

13-
def remove; end
292+
def self.generation_hook installer, specs
293+
# Do nothing if this is NOT a default gem.
294+
return unless default_gem?
14295

15-
def self.generation_hook installer, specs; end
296+
# Generate document for compatibility if this is a default gem.
297+
RubyGemsHook.generate(installer, specs)
298+
end
16299
end
17300
end

0 commit comments

Comments
 (0)