File: rubygems_hook.rb

package info (click to toggle)
ruby3.4 3.4.5-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 154,784 kB
  • sloc: ruby: 1,259,653; ansic: 829,955; yacc: 28,233; pascal: 7,359; sh: 3,864; python: 1,799; cpp: 1,158; asm: 808; makefile: 801; javascript: 414; lisp: 109; perl: 62; awk: 36; sed: 4; xml: 4
file content (327 lines) | stat: -rw-r--r-- 7,624 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# frozen_string_literal: true
require 'rubygems/user_interaction'
require 'fileutils'
require_relative '../rdoc'

# We define the following two similar name classes in this file:
#
# - RDoc::RubyGemsHook
# - RDoc::RubygemsHook
#
# RDoc::RubyGemsHook is the main class that has real logic.
#
# RDoc::RubygemsHook is a class that is only for
# compatibility. RDoc::RubygemsHook is used by RubyGems directly. We
# can remove this when all maintained RubyGems remove
# `rubygems/rdoc.rb`.

class RDoc::RubyGemsHook

  include Gem::UserInteraction
  extend  Gem::UserInteraction

  @rdoc_version = nil
  @specs = []

  ##
  # Force installation of documentation?

  attr_accessor :force

  ##
  # Generate rdoc?

  attr_accessor :generate_rdoc

  ##
  # Generate ri data?

  attr_accessor :generate_ri

  class << self

    ##
    # Loaded version of RDoc.  Set by ::load_rdoc

    attr_reader :rdoc_version

  end

  ##
  # Post installs hook that generates documentation for each specification in
  # +specs+

  def self.generate(installer, specs)
    start = Time.now
    types = installer.document

    generate_rdoc = types.include? 'rdoc'
    generate_ri   = types.include? 'ri'

    specs.each do |spec|
      new(spec, generate_rdoc, generate_ri).generate
    end

    return unless generate_rdoc or generate_ri

    duration = (Time.now - start).to_i
    names    = specs.map(&:name).join ', '

    say "Done installing documentation for #{names} after #{duration} seconds"
  end

  def self.remove(uninstaller)
    new(uninstaller.spec).remove
  end

  ##
  # Loads the RDoc generator

  def self.load_rdoc
    return if @rdoc_version

    require_relative 'rdoc'

    @rdoc_version = Gem::Version.new ::RDoc::VERSION
  end

  ##
  # Creates a new documentation generator for +spec+.  RDoc and ri data
  # generation can be enabled or disabled through +generate_rdoc+ and
  # +generate_ri+ respectively.
  #
  # Only +generate_ri+ is enabled by default.

  def initialize(spec, generate_rdoc = false, generate_ri = true)
    @doc_dir   = spec.doc_dir
    @force     = false
    @rdoc      = nil
    @spec      = spec

    @generate_rdoc = generate_rdoc
    @generate_ri   = generate_ri

    @rdoc_dir = spec.doc_dir 'rdoc'
    @ri_dir   = spec.doc_dir 'ri'
  end

  ##
  # Removes legacy rdoc arguments from +args+
  #--
  # TODO move to RDoc::Options

  def delete_legacy_args(args)
    args.delete '--inline-source'
    args.delete '--promiscuous'
    args.delete '-p'
    args.delete '--one-file'
  end

  ##
  # Generates documentation using the named +generator+ ("darkfish" or "ri")
  # and following the given +options+.
  #
  # Documentation will be generated into +destination+

  def document(generator, options, destination)
    generator_name = generator

    options = options.dup
    options.exclude ||= [] # TODO maybe move to RDoc::Options#finish
    options.setup_generator generator
    options.op_dir = destination
    Dir.chdir @spec.full_gem_path do
      options.finish
    end

    generator = options.generator.new @rdoc.store, options

    @rdoc.options = options
    @rdoc.generator = generator

    say "Installing #{generator_name} documentation for #{@spec.full_name}"

    FileUtils.mkdir_p options.op_dir

    Dir.chdir options.op_dir do
      begin
        @rdoc.class.current = @rdoc
        @rdoc.generator.generate
      ensure
        @rdoc.class.current = nil
      end
    end
  end

  ##
  # Generates RDoc and ri data

  def generate
    return if @spec.default_gem?
    return unless @generate_ri or @generate_rdoc

    setup

    options = nil

    args = @spec.rdoc_options
    args.concat @spec.source_paths
    args.concat @spec.extra_rdoc_files

    case config_args = Gem.configuration[:rdoc]
    when String then
      args = args.concat config_args.split(' ')
    when Array then
      args = args.concat config_args
    end

    delete_legacy_args args

    Dir.chdir @spec.full_gem_path do
      options = ::RDoc::Options.new
      options.default_title = "#{@spec.full_name} Documentation"
      options.parse args
      options.quiet = !Gem.configuration.really_verbose
    end

    @rdoc = new_rdoc

    say "Parsing documentation for #{@spec.full_name}"

    Dir.chdir @spec.full_gem_path do
      # RDoc::Options#finish must be called before parse_files.
      # RDoc::Options#finish is also called after ri/darkfish generator setup.
      # We need to dup the options to avoid modifying it after finish is called.
      parse_options = options.dup
      parse_options.finish
      @rdoc.options = parse_options
      @rdoc.store = RDoc::Store.new(parse_options)
      @rdoc.parse_files parse_options.files
    end

    document 'ri',       options, @ri_dir if
      @generate_ri   and (@force or not File.exist? @ri_dir)

    document 'darkfish', options, @rdoc_dir if
      @generate_rdoc and (@force or not File.exist? @rdoc_dir)
  end

  ##
  # #new_rdoc creates a new RDoc instance.  This method is provided only to
  # make testing easier.

  def new_rdoc # :nodoc:
    ::RDoc::RDoc.new
  end

  ##
  # Is rdoc documentation installed?

  def rdoc_installed?
    File.exist? @rdoc_dir
  end

  ##
  # Removes generated RDoc and ri data

  def remove
    base_dir = @spec.base_dir

    raise Gem::FilePermissionError, base_dir unless File.writable? base_dir

    FileUtils.rm_rf @rdoc_dir
    FileUtils.rm_rf @ri_dir
  end

  ##
  # Is ri data installed?

  def ri_installed?
    File.exist? @ri_dir
  end

  ##
  # Prepares the spec for documentation generation

  def setup
    self.class.load_rdoc

    raise Gem::FilePermissionError, @doc_dir if
      File.exist?(@doc_dir) and not File.writable?(@doc_dir)

    FileUtils.mkdir_p @doc_dir unless File.exist? @doc_dir
  end

end

# This class is referenced by RubyGems to create documents.
# All implementations are moved to the above RubyGemsHook.
#
# This class does nothing when this RDoc is installed as a normal gem
# or a bundled gem.
#
# This class does generate/remove documents for compatibility when
# this RDoc is installed as a default gem.
#
# We can remove this when all maintained RubyGems remove
# `rubygems/rdoc.rb`.
module RDoc
  class RubygemsHook

    attr_accessor :generate_rdoc, :generate_ri, :force

    def self.default_gem?
      !File.exist?(File.join(__dir__, "..", "rubygems_plugin.rb"))
    end

    def initialize(spec, generate_rdoc = false, generate_ri = true)
      @spec = spec
      @generate_rdoc = generate_rdoc
      @generate_ri   = generate_ri
      @force = false
    end

    def generate
      # Do nothing if this is NOT a default gem.
      return unless self.class.default_gem?

      # Generate document for compatibility if this is a default gem.
      hook = RubyGemsHook.new(@spec, @generate_rdoc, @generate_ri)
      hook.force = @force
      hook.generate
    end

    def remove
      # Do nothing if this is NOT a default gem.
      return unless self.class.default_gem?

      # Remove generated document for compatibility if this is a
      # default gem.
      RubyGemsHook.new(@spec).remove
    end

    def self.generation_hook(installer, specs)
      # Do nothing if this is NOT a default gem.
      return unless default_gem?

      # Generate document for compatibility if this is a default gem.
      RubyGemsHook.generate(installer, specs)
    end

    def self.load_rdoc
      RubyGemsHook.load_rdoc
    end

    def self.rdoc_version
      RubyGemsHook.rdoc_version
    end

    def rdoc_installed?
      RubyGemsHook.new(@spec).rdoc_installed?
    end

    def ri_installed?
      RubyGemsHook.new(@spec).ri_installed?
    end
  end
end