source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/rdoc/rdoc.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 8.4 KB
Line 
1# See README.
2#
3
4
5VERSION_STRING = %{RDoc V1.0.1 - 20041108}
6
7
8require 'rdoc/parsers/parse_rb.rb'
9require 'rdoc/parsers/parse_c.rb'
10require 'rdoc/parsers/parse_f95.rb'
11
12require 'rdoc/parsers/parse_simple.rb'
13require 'rdoc/options'
14
15require 'rdoc/diagram'
16
17require 'find'
18require 'ftools'
19require 'time'
20
21# We put rdoc stuff in the RDoc module to avoid namespace
22# clutter.
23#
24# ToDo: This isn't universally true.
25#
26# :include: README
27
28module RDoc
29
30 # Name of the dotfile that contains the description of files to be
31 # processed in the current directory
32 DOT_DOC_FILENAME = ".document"
33
34 # Simple stats collector
35 class Stats
36 attr_accessor :num_files, :num_classes, :num_modules, :num_methods
37 def initialize
38 @num_files = @num_classes = @num_modules = @num_methods = 0
39 @start = Time.now
40 end
41 def print
42 puts "Files: #@num_files"
43 puts "Classes: #@num_classes"
44 puts "Modules: #@num_modules"
45 puts "Methods: #@num_methods"
46 puts "Elapsed: " + sprintf("%0.3fs", Time.now - @start)
47 end
48 end
49
50
51 # Exception thrown by any rdoc error. Only the #message part is
52 # of use externally.
53
54 class RDocError < Exception
55 end
56
57 # Encapsulate the production of rdoc documentation. Basically
58 # you can use this as you would invoke rdoc from the command
59 # line:
60 #
61 # rdoc = RDoc::RDoc.new
62 # rdoc.document(args)
63 #
64 # where _args_ is an array of strings, each corresponding to
65 # an argument you'd give rdoc on the command line. See rdoc/rdoc.rb
66 # for details.
67
68 class RDoc
69
70 ##
71 # This is the list of output generators that we
72 # support
73
74 Generator = Struct.new(:file_name, :class_name, :key)
75
76 GENERATORS = {}
77 $:.collect {|d|
78 File::expand_path(d)
79 }.find_all {|d|
80 File::directory?("#{d}/rdoc/generators")
81 }.each {|dir|
82 Dir::entries("#{dir}/rdoc/generators").each {|gen|
83 next unless /(\w+)_generator.rb$/ =~ gen
84 type = $1
85 unless GENERATORS.has_key? type
86 GENERATORS[type] = Generator.new("rdoc/generators/#{gen}",
87 "#{type.upcase}Generator".intern,
88 type)
89 end
90 }
91 }
92
93 #######
94 private
95 #######
96
97 ##
98 # Report an error message and exit
99
100 def error(msg)
101 raise RDocError.new(msg)
102 end
103
104 ##
105 # Create an output dir if it doesn't exist. If it does
106 # exist, but doesn't contain the flag file <tt>created.rid</tt>
107 # then we refuse to use it, as we may clobber some
108 # manually generated documentation
109
110 def setup_output_dir(op_dir, force)
111 flag_file = output_flag_file(op_dir)
112 if File.exist?(op_dir)
113 unless File.directory?(op_dir)
114 error "'#{op_dir}' exists, and is not a directory"
115 end
116 begin
117 created = File.read(flag_file)
118 rescue SystemCallError
119 error "\nDirectory #{op_dir} already exists, but it looks like it\n" +
120 "isn't an RDoc directory. Because RDoc doesn't want to risk\n" +
121 "destroying any of your existing files, you'll need to\n" +
122 "specify a different output directory name (using the\n" +
123 "--op <dir> option).\n\n"
124 else
125 last = (Time.parse(created) unless force rescue nil)
126 end
127 else
128 File.makedirs(op_dir)
129 end
130 last
131 end
132
133 # Update the flag file in an output directory.
134 def update_output_dir(op_dir, time)
135 File.open(output_flag_file(op_dir), "w") {|f| f.puts time.rfc2822 }
136 end
137
138 # Return the path name of the flag file in an output directory.
139 def output_flag_file(op_dir)
140 File.join(op_dir, "created.rid")
141 end
142
143 # The .document file contains a list of file and directory name
144 # patterns, representing candidates for documentation. It may
145 # also contain comments (starting with '#')
146 def parse_dot_doc_file(in_dir, filename, options)
147 # read and strip comments
148 patterns = File.read(filename).gsub(/#.*/, '')
149
150 result = []
151
152 patterns.split.each do |patt|
153 candidates = Dir.glob(File.join(in_dir, patt))
154 result.concat(normalized_file_list(options, candidates))
155 end
156 result
157 end
158
159
160 # Given a list of files and directories, create a list
161 # of all the Ruby files they contain.
162 #
163 # If +force_doc+ is true, we always add the given files.
164 # If false, only add files that we guarantee we can parse
165 # It is true when looking at files given on the command line,
166 # false when recursing through subdirectories.
167 #
168 # The effect of this is that if you want a file with a non-
169 # standard extension parsed, you must name it explicity.
170 #
171
172 def normalized_file_list(options, relative_files, force_doc = false, exclude_pattern=nil)
173 file_list = []
174
175 relative_files.each do |rel_file_name|
176 next if exclude_pattern && exclude_pattern =~ rel_file_name
177 stat = File.stat(rel_file_name)
178 case type = stat.ftype
179 when "file"
180 next if @last_created and stat.mtime < @last_created
181 file_list << rel_file_name.sub(/^\.\//, '') if force_doc || ParserFactory.can_parse(rel_file_name)
182 when "directory"
183 next if rel_file_name == "CVS" || rel_file_name == ".svn"
184 dot_doc = File.join(rel_file_name, DOT_DOC_FILENAME)
185 if File.file?(dot_doc)
186 file_list.concat(parse_dot_doc_file(rel_file_name, dot_doc, options))
187 else
188 file_list.concat(list_files_in_directory(rel_file_name, options))
189 end
190 else
191 raise RDocError.new("I can't deal with a #{type} #{rel_file_name}")
192 end
193 end
194 file_list
195 end
196
197 # Return a list of the files to be processed in
198 # a directory. We know that this directory doesn't have
199 # a .document file, so we're looking for real files. However
200 # we may well contain subdirectories which must
201 # be tested for .document files
202 def list_files_in_directory(dir, options)
203 normalized_file_list(options, Dir.glob(File.join(dir, "*")), false, options.exclude)
204 end
205
206
207 # Parse each file on the command line, recursively entering
208 # directories
209
210 def parse_files(options)
211
212 file_info = []
213
214 files = options.files
215 files = ["."] if files.empty?
216
217 file_list = normalized_file_list(options, files, true)
218
219 file_list.each do |fn|
220 $stderr.printf("\n%35s: ", File.basename(fn)) unless options.quiet
221
222 content = File.open(fn, "r") {|f| f.read}
223
224 top_level = TopLevel.new(fn)
225 parser = ParserFactory.parser_for(top_level, fn, content, options, @stats)
226 file_info << parser.scan
227 @stats.num_files += 1
228 end
229
230 file_info
231 end
232
233
234 public
235
236 ###################################################################
237 #
238 # Format up one or more files according to the given arguments.
239 # For simplicity, _argv_ is an array of strings, equivalent to the
240 # strings that would be passed on the command line. (This isn't a
241 # coincidence, as we _do_ pass in ARGV when running
242 # interactively). For a list of options, see rdoc/rdoc.rb. By
243 # default, output will be stored in a directory called +doc+ below
244 # the current directory, so make sure you're somewhere writable
245 # before invoking.
246 #
247 # Throws: RDocError on error
248
249 def document(argv)
250
251 TopLevel::reset
252
253 @stats = Stats.new
254
255 options = Options.instance
256 options.parse(argv, GENERATORS)
257
258 @last_created = nil
259 unless options.all_one_file
260 @last_created = setup_output_dir(options.op_dir, options.force_update)
261 end
262 start_time = Time.now
263
264 file_info = parse_files(options)
265
266 if file_info.empty?
267 $stderr.puts "\nNo newer files." unless options.quiet
268 else
269 gen = options.generator
270
271 $stderr.puts "\nGenerating #{gen.key.upcase}..." unless options.quiet
272
273 require gen.file_name
274
275 gen_class = Generators.const_get(gen.class_name)
276 gen = gen_class.for(options)
277
278 pwd = Dir.pwd
279
280 Dir.chdir(options.op_dir) unless options.all_one_file
281
282 begin
283 Diagram.new(file_info, options).draw if options.diagram
284 gen.generate(file_info)
285 update_output_dir(".", start_time)
286 ensure
287 Dir.chdir(pwd)
288 end
289 end
290
291 unless options.quiet
292 puts
293 @stats.print
294 end
295 end
296 end
297end
298
Note: See TracBrowser for help on using the repository browser.