Class: RDoc::RDoc

Inherits:
Object
  • Object
show all
Defined in:
lib/rdoc/rdoc.rb

Overview

Encapsulate the production of rdoc documentation. Basically you can use this as you would invoke rdoc from the command line:

rdoc = RDoc::RDoc.new
rdoc.document(args)

where args is an array of strings, each corresponding to an argument you’d give rdoc on the command line. See rdoc/rdoc.rb for details.

Defined Under Namespace

Classes: Generator

Constant Summary collapse

GENERATORS =

This is the list of output generator that we support

{}

Instance Method Summary collapse

Constructor Details

#initializeRDoc

Returns a new instance of RDoc.



56
57
58
# File 'lib/rdoc/rdoc.rb', line 56

def initialize
  @stats = Stats.new
end

Instance Method Details

#document(argv) ⇒ Object

Format up one or more files according to the given arguments.

For simplicity, argv is an array of strings, equivalent to the strings that would be passed on the command line. (This isn’t a coincidence, as we do pass in ARGV when running interactively). For a list of options, see rdoc/rdoc.rb. By default, output will be stored in a directory called doc below the current directory, so make sure you’re somewhere writable before invoking.

Throws: RDoc::Error on error



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
# File 'lib/rdoc/rdoc.rb', line 228

def document(argv)
  TopLevel::reset

  @options = Options.new GENERATORS
  @options.parse argv

  @last_created = nil

  unless @options.all_one_file then
    @last_created = setup_output_dir @options.op_dir, @options.force_update
  end

  start_time = Time.now

  file_info = parse_files @options

  if file_info.empty?
    $stderr.puts "\nNo newer files." unless @options.quiet
  else
    @gen = @options.generator

    $stderr.puts "\nGenerating #{@gen.key.upcase}..." unless @options.quiet

    require @gen.file_name

    gen_class = ::RDoc::Generator.const_get @gen.class_name
    @gen = gen_class.for @options

    pwd = Dir.pwd

    Dir.chdir @options.op_dir unless @options.all_one_file

    begin
      Diagram.new(file_info, @options).draw if @options.diagram
      @gen.generate(file_info)
      update_output_dir(".", start_time)
    ensure
      Dir.chdir(pwd)
    end
  end

  unless @options.quiet
    puts
    @stats.print
  end
end

#error(msg) ⇒ Object

Report an error message and exit

Raises:



63
64
65
# File 'lib/rdoc/rdoc.rb', line 63

def error(msg)
  raise ::RDoc::Error, msg
end

#list_files_in_directory(dir, options) ⇒ Object

Return a list of the files to be processed in a directory. We know that this directory doesn’t have a .document file, so we’re looking for real files. However we may well contain subdirectories which must be tested for .document files.



172
173
174
175
176
# File 'lib/rdoc/rdoc.rb', line 172

def list_files_in_directory(dir, options)
  files = Dir.glob File.join(dir, "*")

  normalized_file_list options, files, false, options.exclude
end

#normalized_file_list(options, relative_files, force_doc = false, exclude_pattern = nil) ⇒ Object

Given a list of files and directories, create a list of all the Ruby files they contain.

If force_doc is true we always add the given files, if false, only add files that we guarantee we can parse. It is true when looking at files given on the command line, false when recursing through subdirectories.

The effect of this is that if you want a file with a non-standard extension parsed, you must name it explicity.



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
# File 'lib/rdoc/rdoc.rb', line 139

def normalized_file_list(options, relative_files, force_doc = false,
                         exclude_pattern = nil)
  file_list = []

  relative_files.each do |rel_file_name|
    next if exclude_pattern && exclude_pattern =~ rel_file_name
    stat = File.stat(rel_file_name)
    case type = stat.ftype
    when "file"
      next if @last_created and stat.mtime < @last_created
      file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
    when "directory"
      next if rel_file_name == "CVS" || rel_file_name == ".svn"
      dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
      if File.file?(dot_doc)
        file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options))
      else
        file_list.concat(list_files_in_directory(rel_file_name, options))
      end
    else
      raise RDoc::Error, "I can't deal with a #{type} #{rel_file_name}"
    end
  end

  file_list
end

#output_flag_file(op_dir) ⇒ Object

Return the path name of the flag file in an output directory.



105
106
107
# File 'lib/rdoc/rdoc.rb', line 105

def output_flag_file(op_dir)
  File.join(op_dir, "created.rid")
end

#parse_dot_doc_file(in_dir, filename, options) ⇒ Object

The .document file contains a list of file and directory name patterns, representing candidates for documentation. It may also contain comments (starting with ‘#’)



114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/rdoc/rdoc.rb', line 114

def parse_dot_doc_file(in_dir, filename, options)
  # read and strip comments
  patterns = File.read(filename).gsub(/#.*/, '')

  result = []

  patterns.split.each do |patt|
    candidates = Dir.glob(File.join(in_dir, patt))
    result.concat(normalized_file_list(options,  candidates))
  end
  result
end

#parse_files(options) ⇒ Object

Parse each file on the command line, recursively entering directories.



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
# File 'lib/rdoc/rdoc.rb', line 181

def parse_files(options)
  files = options.files
  files = ["."] if files.empty?

  file_list = normalized_file_list(options, files, true)

  return [] if file_list.empty?

  file_info = []
  width = file_list.map { |name| name.length }.max + 1

  file_list.each do |fn|
    $stderr.printf("\n%*s: ", width, fn) unless options.quiet

    content = if RUBY_VERSION >= '1.9' then
                File.open(fn, "r:ascii-8bit") { |f| f.read }
              else
                File.read fn
              end

    if / coding:\s*(\S+)/ =~ content[/\A(?:.*\n){0,2}/]
      if enc = Encoding.find($1)
        content.force_encoding(enc)
      end
    end

    top_level = TopLevel.new(fn)
    parser = ParserFactory.parser_for(top_level, fn, content, options, @stats)
    file_info << parser.scan
    @stats.num_files += 1
  end

  file_info
end

#setup_output_dir(op_dir, force) ⇒ Object

Create an output dir if it doesn’t exist. If it does exist, but doesn’t contain the flag file created.rid then we refuse to use it, as we may clobber some manually generated documentation



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rdoc/rdoc.rb', line 72

def setup_output_dir(op_dir, force)
  flag_file = output_flag_file(op_dir)
  if File.exist?(op_dir)
    unless File.directory?(op_dir)
      error "'#{op_dir}' exists, and is not a directory"
    end
    begin
      created = File.read(flag_file)
    rescue SystemCallError
      error "\nDirectory #{op_dir} already exists, but it looks like it\n" +
        "isn't an RDoc directory. Because RDoc doesn't want to risk\n" +
        "destroying any of your existing files, you'll need to\n" +
        "specify a different output directory name (using the\n" +
        "--op <dir> option).\n\n"
    else
      last = (Time.parse(created) unless force rescue nil)
    end
  else
    FileUtils.mkdir_p(op_dir)
  end
  last
end

#update_output_dir(op_dir, time) ⇒ Object

Update the flag file in an output directory.



98
99
100
# File 'lib/rdoc/rdoc.rb', line 98

def update_output_dir(op_dir, time)
  File.open(output_flag_file(op_dir), "w") {|f| f.puts time.rfc2822 }
end