1require 'rubygems' 2require 'rubygems/user_interaction' 3require 'fileutils' 4require 'rdoc' 5 6## 7# Gem::RDoc provides methods to generate RDoc and ri data for installed gems 8# upon gem installation. 9# 10# This file is automatically required by RubyGems 1.9 and newer. 11 12class RDoc::RubygemsHook 13 14 include Gem::UserInteraction 15 16 @rdoc_version = nil 17 @specs = [] 18 19 ## 20 # Force installation of documentation? 21 22 attr_accessor :force 23 24 ## 25 # Generate rdoc? 26 27 attr_accessor :generate_rdoc 28 29 ## 30 # Generate ri data? 31 32 attr_accessor :generate_ri 33 34 class << self 35 36 ## 37 # Loaded version of RDoc. Set by ::load_rdoc 38 39 attr_reader :rdoc_version 40 41 end 42 43 ## 44 # Post installs hook that generates documentation for each specification in 45 # +specs+ 46 47 def self.generation_hook installer, specs 48 types = installer.document 49 50 generate_rdoc = types.include? 'rdoc' 51 generate_ri = types.include? 'ri' 52 53 specs.each do |spec| 54 new(spec, generate_rdoc, generate_ri).generate 55 end 56 end 57 58 ## 59 # Loads the RDoc generator 60 61 def self.load_rdoc 62 return if @rdoc_version 63 64 require 'rdoc/rdoc' 65 66 @rdoc_version = Gem::Version.new ::RDoc::VERSION 67 end 68 69 ## 70 # Creates a new documentation generator for +spec+. RDoc and ri data 71 # generation can be enabled or disabled through +generate_rdoc+ and 72 # +generate_ri+ respectively. 73 # 74 # Only +generate_ri+ is enabled by default. 75 76 def initialize spec, generate_rdoc = false, generate_ri = true 77 @doc_dir = spec.doc_dir 78 @force = false 79 @rdoc = nil 80 @spec = spec 81 82 @generate_rdoc = generate_rdoc 83 @generate_ri = generate_ri 84 85 @rdoc_dir = spec.doc_dir 'rdoc' 86 @ri_dir = spec.doc_dir 'ri' 87 end 88 89 ## 90 # Removes legacy rdoc arguments from +args+ 91 #-- 92 # TODO move to RDoc::Options 93 94 def delete_legacy_args args 95 args.delete '--inline-source' 96 args.delete '--promiscuous' 97 args.delete '-p' 98 args.delete '--one-file' 99 end 100 101 ## 102 # Generates documentation using the named +generator+ ("darkfish" or "ri") 103 # and following the given +options+. 104 # 105 # Documentation will be generated into +destination+ 106 107 def document generator, options, destination 108 generator_name = generator 109 110 options = options.dup 111 options.exclude ||= [] # TODO maybe move to RDoc::Options#finish 112 options.setup_generator generator 113 options.op_dir = destination 114 options.finish 115 116 generator = options.generator.new @rdoc.store, options 117 118 @rdoc.options = options 119 @rdoc.generator = generator 120 121 say "Installing #{generator_name} documentation for #{@spec.full_name}" 122 123 FileUtils.mkdir_p options.op_dir 124 125 Dir.chdir options.op_dir do 126 begin 127 @rdoc.class.current = @rdoc 128 @rdoc.generator.generate 129 ensure 130 @rdoc.class.current = nil 131 end 132 end 133 end 134 135 ## 136 # Generates RDoc and ri data 137 138 def generate 139 return if @spec.default_gem? 140 return unless @generate_ri or @generate_rdoc 141 142 setup 143 144 options = nil 145 146 args = @spec.rdoc_options 147 args.concat @spec.require_paths 148 args.concat @spec.extra_rdoc_files 149 150 case config_args = Gem.configuration[:rdoc] 151 when String then 152 args = args.concat config_args.split 153 when Array then 154 args = args.concat config_args 155 end 156 157 delete_legacy_args args 158 159 Dir.chdir @spec.full_gem_path do 160 options = ::RDoc::Options.new 161 options.default_title = "#{@spec.full_name} Documentation" 162 options.parse args 163 end 164 165 options.quiet = !Gem.configuration.really_verbose 166 167 @rdoc = new_rdoc 168 @rdoc.options = options 169 170 store = RDoc::Store.new 171 store.encoding = options.encoding if options.respond_to? :encoding 172 store.dry_run = options.dry_run 173 store.main = options.main_page 174 store.title = options.title 175 176 @rdoc.store = store 177 178 say "Parsing documentation for #{@spec.full_name}" 179 180 Dir.chdir @spec.full_gem_path do 181 @rdoc.parse_files options.files 182 end 183 184 document 'ri', options, @ri_dir if 185 @generate_ri and (@force or not File.exist? @ri_dir) 186 187 document 'darkfish', options, @rdoc_dir if 188 @generate_rdoc and (@force or not File.exist? @rdoc_dir) 189 end 190 191 ## 192 # #new_rdoc creates a new RDoc instance. This method is provided only to 193 # make testing easier. 194 195 def new_rdoc # :nodoc: 196 ::RDoc::RDoc.new 197 end 198 199 ## 200 # Is rdoc documentation installed? 201 202 def rdoc_installed? 203 File.exist? @rdoc_dir 204 end 205 206 ## 207 # Removes generated RDoc and ri data 208 209 def remove 210 base_dir = @spec.base_dir 211 212 raise Gem::FilePermissionError, base_dir unless File.writable? base_dir 213 214 FileUtils.rm_rf @rdoc_dir 215 FileUtils.rm_rf @ri_dir 216 end 217 218 ## 219 # Is ri data installed? 220 221 def ri_installed? 222 File.exist? @ri_dir 223 end 224 225 ## 226 # Prepares the spec for documentation generation 227 228 def setup 229 self.class.load_rdoc 230 231 raise Gem::FilePermissionError, @doc_dir if 232 File.exist?(@doc_dir) and not File.writable?(@doc_dir) 233 234 FileUtils.mkdir_p @doc_dir unless File.exist? @doc_dir 235 end 236 237end 238 239