Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the case that RDoc is installed as a default gem #1

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
297 changes: 290 additions & 7 deletions lib/rdoc/rubygems_hook.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,300 @@
# 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
end

options.quiet = !Gem.configuration.really_verbose

@rdoc = new_rdoc
@rdoc.options = options

store = RDoc::Store.new
store.encoding = options.encoding
store.dry_run = options.dry_run
store.main = options.main_page
store.title = options.title

@rdoc.store = store

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

Dir.chdir @spec.full_gem_path do
@rdoc.parse_files 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.
# Now, methods are moved to rubygems_plugin.rb.
# 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.
#
# When old version RDoc is not used,
# this class is not used from RubyGems too.
# Then, remove this class.
# 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
def initialize(spec); end
def self.default_gem?
!File.exist?(File.join(__dir__, "..", "rubygems_plugin.rb"))
end

def initialize(spec)
@spec = spec
end

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

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

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

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