Object
$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $
Michael Granger (ged@FaerieMUD.org)
Mahlon E. Smith (mahlon@martini.nu)
Eric Hodel (drbrain@segment7.net)
Copyright © 2007, 2008, Michael Granger. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the author/s, nor the names of the project’s contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Subversion rev
Subversion ID
Path to this file’s parent directory. Used to find templates and other resources.
Release Version
Directory where generated classes live relative to the root
Directory where generated files live relative to the root
%q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $“
Standard generator factory method
# File lib/rdoc/generator/darkfish.rb, line 84
84: def self::for( options )
85: new( options )
86: end
Initialize a few instance variables before we start
# File lib/rdoc/generator/darkfish.rb, line 94
94: def initialize( options )
95: @options = options
96:
97: template = @options.template || 'darkfish'
98:
99: template_dir = $LOAD_PATH.map do |path|
100: File.join File.expand_path(path), GENERATOR_DIR, 'template', template
101: end.find do |dir|
102: File.directory? dir
103: end
104:
105: raise RDoc::Error, "could not find template #{template.inspect}" unless
106: template_dir
107:
108: @template_dir = Pathname.new File.expand_path(template_dir)
109:
110: @files = nil
111: @classes = nil
112:
113: @basedir = Pathname.pwd.expand_path
114: end
# File lib/rdoc/generator/darkfish.rb, line 130
130: def class_dir
131: CLASS_DIR
132: end
Output progress information if debugging is enabled
# File lib/rdoc/generator/darkfish.rb, line 125
125: def debug_msg( *msg )
126: return unless $DEBUG_RDOC
127: $stderr.puts( *msg )
128: end
# File lib/rdoc/generator/darkfish.rb, line 134
134: def file_dir
135: FILE_DIR
136: end
Create the directories the generated docs will live in if they don’t already exist.
# File lib/rdoc/generator/darkfish.rb, line 140
140: def gen_sub_directories
141: @outputdir.mkpath
142: end
Build the initial indices and output objects based on an array of TopLevel objects containing the extracted information.
# File lib/rdoc/generator/darkfish.rb, line 169
169: def generate( top_levels )
170: @outputdir = Pathname.new( @options.op_dir ).expand_path( @basedir )
171:
172: @files = top_levels.sort
173: @classes = RDoc::TopLevel.all_classes_and_modules.sort
174: @methods = @classes.map { |m| m.method_list }.flatten.sort
175: @modsort = get_sorted_module_list( @classes )
176:
177: # Now actually write the output
178: write_style_sheet
179: generate_index
180: generate_class_files
181: generate_file_files
182:
183: rescue StandardError => err
184: debug_msg "%s: %s\n %s" % [ err.class.name, err.message, err.backtrace.join("\n ") ]
185: raise
186: end
Copy over the stylesheet into the appropriate place in the output directory.
# File lib/rdoc/generator/darkfish.rb, line 146
146: def write_style_sheet
147: debug_msg "Copying static files"
148: options = { :verbose => $DEBUG_RDOC, :noop => $DARKFISH_DRYRUN }
149:
150: FileUtils.cp @template_dir + 'rdoc.css', '.', options
151:
152: Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path|
153: next if File.directory? path
154: next if File.basename(path) =~ /^\./
155:
156: dst = Pathname.new(path).relative_path_from @template_dir
157:
158: # I suck at glob
159: dst_dir = dst.dirname
160: FileUtils.mkdir_p dst_dir, options unless File.exist? dst_dir
161:
162: FileUtils.cp @template_dir + path, dst, options
163: end
164: end
Generate a documentation file for each class
# File lib/rdoc/generator/darkfish.rb, line 254
254: def generate_class_files
255: template_file = @template_dir + 'classpage.rhtml'
256: return unless template_file.exist?
257: debug_msg "Generating class documentation in #@outputdir"
258:
259: @classes.each do |klass|
260: debug_msg " working on %s (%s)" % [ klass.full_name, klass.path ]
261: outfile = @outputdir + klass.path
262: rel_prefix = @outputdir.relative_path_from( outfile.dirname )
263: svninfo = self.get_svninfo( klass )
264:
265: debug_msg " rendering #{outfile}"
266: self.render_template( template_file, binding(), outfile )
267: end
268: end
Generate a documentation file for each file
# File lib/rdoc/generator/darkfish.rb, line 271
271: def generate_file_files
272: template_file = @template_dir + 'filepage.rhtml'
273: return unless template_file.exist?
274: debug_msg "Generating file documentation in #@outputdir"
275:
276: @files.each do |file|
277: outfile = @outputdir + file.path
278: debug_msg " working on %s (%s)" % [ file.full_name, outfile ]
279: rel_prefix = @outputdir.relative_path_from( outfile.dirname )
280: context = binding()
281:
282: debug_msg " rendering #{outfile}"
283: self.render_template( template_file, binding(), outfile )
284: end
285: end
Generate an index page which lists all the classes which are documented.
# File lib/rdoc/generator/darkfish.rb, line 219
219: def generate_index
220: template_file = @template_dir + 'index.rhtml'
221: return unless template_file.exist?
222:
223: debug_msg "Rendering the index page..."
224:
225: template_src = template_file.read
226: template = ERB.new( template_src, nil, '<>' )
227: template.filename = template_file.to_s
228: context = binding()
229:
230: output = nil
231:
232: begin
233: output = template.result( context )
234: rescue NoMethodError => err
235: raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [
236: template_file,
237: err.message,
238: eval( "_erbout[-50,50]", context )
239: ], err.backtrace
240: end
241:
242: outfile = @basedir + @options.op_dir + 'index.html'
243: unless $DARKFISH_DRYRUN
244: debug_msg "Outputting to %s" % [outfile.expand_path]
245: outfile.open( 'w', 0644 ) do |fh|
246: fh.print( output )
247: end
248: else
249: debug_msg "Would have output to %s" % [outfile.expand_path]
250: end
251: end
Return a list of the documented modules sorted by salience first, then by name.
# File lib/rdoc/generator/darkfish.rb, line 194
194: def get_sorted_module_list( classes )
195: nscounts = classes.inject({}) do |counthash, klass|
196: top_level = klass.full_name.gsub( /::.*/, '' )
197: counthash[top_level] ||= 0
198: counthash[top_level] += 1
199:
200: counthash
201: end
202:
203: # Sort based on how often the top level namespace occurs, and then on the
204: # name of the module -- this works for projects that put their stuff into
205: # a namespace, of course, but doesn't hurt if they don't.
206: classes.sort_by do |klass|
207: top_level = klass.full_name.gsub( /::.*/, '' )
208: [
209: nscounts[ top_level ] * 1,
210: klass.full_name
211: ]
212: end.select do |klass|
213: klass.document_self
214: end
215: end
Try to extract Subversion information out of the first constant whose value looks like a subversion Id tag. If no matching constant is found, and empty hash is returned.
# File lib/rdoc/generator/darkfish.rb, line 318
318: def get_svninfo( klass )
319: constants = klass.constants or return {}
320:
321: constants.find {|c| c.value =~ SVNID_PATTERN } or return {}
322:
323: filename, rev, date, time, committer = $~.captures
324: commitdate = Time.parse( date + ' ' + time )
325:
326: return {
327: :filename => filename,
328: :rev => Integer( rev ),
329: :commitdate => commitdate,
330: :commitdelta => time_delta_string( Time.now.to_i - commitdate.to_i ),
331: :committer => committer,
332: }
333: end
Load and render the erb template in the given template_file within the specified context (a Binding object) and write it out to outfile. Both template_file and outfile should be Pathname-like objects.
# File lib/rdoc/generator/darkfish.rb, line 340
340: def render_template( template_file, context, outfile )
341: template_src = template_file.read
342: template = ERB.new( template_src, nil, '<>' )
343: template.filename = template_file.to_s
344:
345: output = begin
346: template.result( context )
347: rescue NoMethodError => err
348: raise RDoc::Error, "Error while evaluating %s: %s (at %p)" % [
349: template_file.to_s,
350: err.message,
351: eval( "_erbout[-50,50]", context )
352: ], err.backtrace
353: end
354:
355: unless $DARKFISH_DRYRUN
356: outfile.dirname.mkpath
357: outfile.open( 'w', 0644 ) do |ofh|
358: ofh.print( output )
359: end
360: else
361: debug_msg " would have written %d bytes to %s" %
362: [ output.length, outfile ]
363: end
364: end
Return a string describing the amount of time in the given number of seconds in terms a human can understand easily.
# File lib/rdoc/generator/darkfish.rb, line 290
290: def time_delta_string( seconds )
291: return 'less than a minute' if seconds < 1.minute
292: return (seconds / 1.minute).to_s + ' minute' + (seconds/60 == 1 ? '' : 's') if seconds < 50.minutes
293: return 'about one hour' if seconds < 90.minutes
294: return (seconds / 1.hour).to_s + ' hours' if seconds < 18.hours
295: return 'one day' if seconds < 1.day
296: return 'about one day' if seconds < 2.days
297: return (seconds / 1.day).to_s + ' days' if seconds < 1.week
298: return 'about one week' if seconds < 2.week
299: return (seconds / 1.week).to_s + ' weeks' if seconds < 3.months
300: return (seconds / 1.month).to_s + ' months' if seconds < 1.year
301: return (seconds / 1.year).to_s + ' years'
302: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.