eaiovnaovbqoebvqoeavibavo PK J8jZoJ J darkfish.rbnu [ # -*- mode: ruby; ruby-indent-level: 2; tab-width: 2 -*- require 'erb' require 'fileutils' require 'pathname' require 'rdoc/generator/markup' ## # Darkfish RDoc HTML Generator # # $Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $ # # == Author/s # * Michael Granger (ged@FaerieMUD.org) # # == Contributors # * Mahlon E. Smith (mahlon@martini.nu) # * Eric Hodel (drbrain@segment7.net) # # == License # # Copyright (c) 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. # # == Attributions # # Darkfish uses the {Silk Icons}[http://www.famfamfam.com/lab/icons/silk/] set # by Mark James. class RDoc::Generator::Darkfish RDoc::RDoc.add_generator self include ERB::Util ## # Path to this file's parent directory. Used to find templates and other # resources. GENERATOR_DIR = File.join 'rdoc', 'generator' ## # Release Version VERSION = '3' ## # Description of this generator DESCRIPTION = 'HTML generator, written by Michael Granger' ## # The relative path to style sheets and javascript. By default this is set # the same as the rel_prefix. attr_accessor :asset_rel_path ## # The path to generate files into, combined with --op from the # options for a full path. attr_reader :base_dir ## # Classes and modules to be used by this generator, not necessarily # displayed. See also #modsort attr_reader :classes ## # No files will be written when dry_run is true. attr_accessor :dry_run ## # When false the generate methods return a String instead of writing to a # file. The default is true. attr_accessor :file_output ## # Files to be displayed by this generator attr_reader :files ## # The JSON index generator for this Darkfish generator attr_reader :json_index ## # Methods to be displayed by this generator attr_reader :methods ## # Sorted list of classes and modules to be displayed by this generator attr_reader :modsort ## # The RDoc::Store that is the source of the generated content attr_reader :store ## # The output directory attr_reader :outputdir ## # Initialize a few instance variables before we start def initialize store, options @store = store @options = options @asset_rel_path = '' @base_dir = Pathname.pwd.expand_path @dry_run = @options.dry_run @file_output = true @template_dir = Pathname.new options.template_dir @template_cache = {} @classes = nil @context = nil @files = nil @methods = nil @modsort = nil @json_index = RDoc::Generator::JsonIndex.new self, options end ## # Output progress information if debugging is enabled def debug_msg *msg return unless $DEBUG_RDOC $stderr.puts(*msg) end ## # Directory where generated class HTML files live relative to the output # dir. def class_dir nil end ## # Directory where generated class HTML files live relative to the output # dir. def file_dir nil end ## # Create the directories the generated docs will live in if they don't # already exist. def gen_sub_directories @outputdir.mkpath end ## # Copy over the stylesheet into the appropriate place in the output # directory. def write_style_sheet debug_msg "Copying static files" options = { :verbose => $DEBUG_RDOC, :noop => @dry_run } FileUtils.cp @template_dir + 'rdoc.css', '.', options Dir[(@template_dir + "{js,images}/**/*").to_s].each do |path| next if File.directory? path next if File.basename(path) =~ /^\./ dst = Pathname.new(path).relative_path_from @template_dir # I suck at glob dst_dir = dst.dirname FileUtils.mkdir_p dst_dir, options unless File.exist? dst_dir FileUtils.cp @template_dir + path, dst, options end end ## # Build the initial indices and output objects based on an array of TopLevel # objects containing the extracted information. def generate setup write_style_sheet generate_index generate_class_files generate_file_files generate_table_of_contents @json_index.generate copy_static rescue => e debug_msg "%s: %s\n %s" % [ e.class.name, e.message, e.backtrace.join("\n ") ] raise end ## # Copies static files from the static_path into the output directory def copy_static return if @options.static_path.empty? fu_options = { :verbose => $DEBUG_RDOC, :noop => @dry_run } @options.static_path.each do |path| unless File.directory? path then FileUtils.install path, @outputdir, fu_options.merge(:mode => 0644) next end Dir.chdir path do Dir[File.join('**', '*')].each do |entry| dest_file = @outputdir + entry if File.directory? entry then FileUtils.mkdir_p entry, fu_options else FileUtils.install entry, dest_file, fu_options.merge(:mode => 0644) end end end end end ## # Return a list of the documented modules sorted by salience first, then # by name. def get_sorted_module_list classes classes.select do |klass| klass.display? end.sort end ## # Generate an index page which lists all the classes which are documented. def generate_index setup template_file = @template_dir + 'index.rhtml' return unless template_file.exist? debug_msg "Rendering the index page..." out_file = @base_dir + @options.op_dir + 'index.html' rel_prefix = @outputdir.relative_path_from out_file.dirname search_index_rel_prefix = rel_prefix search_index_rel_prefix += @asset_rel_path if @file_output # suppress 1.9.3 warning asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path @title = @options.title render_template template_file, out_file do |io| binding end rescue => e error = RDoc::Error.new \ "error generating index.html: #{e.message} (#{e.class})" error.set_backtrace e.backtrace raise error end ## # Generates a class file for +klass+ def generate_class klass, template_file = nil setup current = klass template_file ||= @template_dir + 'class.rhtml' debug_msg " working on %s (%s)" % [klass.full_name, klass.path] out_file = @outputdir + klass.path rel_prefix = @outputdir.relative_path_from out_file.dirname search_index_rel_prefix = rel_prefix search_index_rel_prefix += @asset_rel_path if @file_output # suppress 1.9.3 warning asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path svninfo = svninfo = get_svninfo(current) @title = "#{klass.type} #{klass.full_name} - #{@options.title}" debug_msg " rendering #{out_file}" render_template template_file, out_file do |io| binding end end ## # Generate a documentation file for each class and module def generate_class_files setup template_file = @template_dir + 'class.rhtml' template_file = @template_dir + 'classpage.rhtml' unless template_file.exist? return unless template_file.exist? debug_msg "Generating class documentation in #{@outputdir}" current = nil @classes.each do |klass| current = klass generate_class klass, template_file end rescue => e error = RDoc::Error.new \ "error generating #{current.path}: #{e.message} (#{e.class})" error.set_backtrace e.backtrace raise error end ## # Generate a documentation file for each file def generate_file_files setup page_file = @template_dir + 'page.rhtml' fileinfo_file = @template_dir + 'fileinfo.rhtml' # for legacy templates filepage_file = @template_dir + 'filepage.rhtml' unless page_file.exist? or fileinfo_file.exist? return unless page_file.exist? or fileinfo_file.exist? or filepage_file.exist? debug_msg "Generating file documentation in #{@outputdir}" out_file = nil current = nil @files.each do |file| current = file if file.text? and page_file.exist? then generate_page file next end template_file = nil out_file = @outputdir + file.path debug_msg " working on %s (%s)" % [file.full_name, out_file] rel_prefix = @outputdir.relative_path_from out_file.dirname search_index_rel_prefix = rel_prefix search_index_rel_prefix += @asset_rel_path if @file_output # suppress 1.9.3 warning asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path unless filepage_file then if file.text? then next unless page_file.exist? template_file = page_file @title = file.page_name else next unless fileinfo_file.exist? template_file = fileinfo_file @title = "File: #{file.base_name}" end end @title += " - #{@options.title}" template_file ||= filepage_file render_template template_file, out_file do |io| binding end end rescue => e error = RDoc::Error.new "error generating #{out_file}: #{e.message} (#{e.class})" error.set_backtrace e.backtrace raise error end ## # Generate a page file for +file+ def generate_page file setup template_file = @template_dir + 'page.rhtml' out_file = @outputdir + file.path debug_msg " working on %s (%s)" % [file.full_name, out_file] rel_prefix = @outputdir.relative_path_from out_file.dirname search_index_rel_prefix = rel_prefix search_index_rel_prefix += @asset_rel_path if @file_output # suppress 1.9.3 warning current = current = file asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path @title = "#{file.page_name} - #{@options.title}" debug_msg " rendering #{out_file}" render_template template_file, out_file do |io| binding end end ## # Generates the 404 page for the RDoc servlet def generate_servlet_not_found path setup template_file = @template_dir + 'servlet_not_found.rhtml' return unless template_file.exist? debug_msg "Rendering the servlet 404 Not Found page..." rel_prefix = rel_prefix = '' search_index_rel_prefix = rel_prefix search_index_rel_prefix += @asset_rel_path if @file_output # suppress 1.9.3 warning asset_rel_prefix = asset_rel_prefix = '' @title = 'Not Found' render_template template_file do |io| binding end rescue => e error = RDoc::Error.new \ "error generating servlet_not_found: #{e.message} (#{e.class})" error.set_backtrace e.backtrace raise error end ## # Generates the servlet root page for the RDoc servlet def generate_servlet_root installed setup template_file = @template_dir + 'servlet_root.rhtml' return unless template_file.exist? debug_msg 'Rendering the servlet root page...' rel_prefix = '.' asset_rel_prefix = rel_prefix search_index_rel_prefix = asset_rel_prefix search_index_rel_prefix += @asset_rel_path if @file_output @title = 'Local RDoc Documentation' render_template template_file do |io| binding end rescue => e error = RDoc::Error.new \ "error generating servlet_root: #{e.message} (#{e.class})" error.set_backtrace e.backtrace raise error end ## # Generate an index page which lists all the classes which are documented. def generate_table_of_contents setup template_file = @template_dir + 'table_of_contents.rhtml' return unless template_file.exist? debug_msg "Rendering the Table of Contents..." out_file = @outputdir + 'table_of_contents.html' rel_prefix = @outputdir.relative_path_from out_file.dirname search_index_rel_prefix = rel_prefix search_index_rel_prefix += @asset_rel_path if @file_output # suppress 1.9.3 warning asset_rel_prefix = asset_rel_prefix = rel_prefix + @asset_rel_path @title = "Table of Contents - #{@options.title}" render_template template_file, out_file do |io| binding end rescue => e error = RDoc::Error.new \ "error generating table_of_contents.html: #{e.message} (#{e.class})" error.set_backtrace e.backtrace raise error end ## # Prepares for generation of output from the current directory def setup return if instance_variable_defined? :@outputdir @outputdir = Pathname.new(@options.op_dir).expand_path @base_dir return unless @store @classes = @store.all_classes_and_modules.sort @files = @store.all_files.sort @methods = @classes.map { |m| m.method_list }.flatten.sort @modsort = get_sorted_module_list @classes end ## # Return a string describing the amount of time in the given number of # seconds in terms a human can understand easily. def time_delta_string seconds return 'less than a minute' if seconds < 60 return "#{seconds / 60} minute#{seconds / 60 == 1 ? '' : 's'}" if seconds < 3000 # 50 minutes return 'about one hour' if seconds < 5400 # 90 minutes return "#{seconds / 3600} hours" if seconds < 64800 # 18 hours return 'one day' if seconds < 86400 # 1 day return 'about one day' if seconds < 172800 # 2 days return "#{seconds / 86400} days" if seconds < 604800 # 1 week return 'about one week' if seconds < 1209600 # 2 week return "#{seconds / 604800} weeks" if seconds < 7257600 # 3 months return "#{seconds / 2419200} months" if seconds < 31536000 # 1 year return "#{seconds / 31536000} years" end # %q$Id: darkfish.rb 52 2009-01-07 02:08:11Z deveiant $" SVNID_PATTERN = / \$Id:\s (\S+)\s # filename (\d+)\s # rev (\d{4}-\d{2}-\d{2})\s # Date (YYYY-MM-DD) (\d{2}:\d{2}:\d{2}Z)\s # Time (HH:MM:SSZ) (\w+)\s # committer \$$ /x ## # 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. def get_svninfo klass constants = klass.constants or return {} constants.find { |c| c.value =~ SVNID_PATTERN } or return {} filename, rev, date, time, committer = $~.captures commitdate = Time.parse "#{date} #{time}" return { :filename => filename, :rev => Integer(rev), :commitdate => commitdate, :commitdelta => time_delta_string(Time.now - commitdate), :committer => committer, } end ## # Creates a template from its components and the +body_file+. # # For backwards compatibility, if +body_file+ contains "
#{head_file.read} #{body} #{footer_file.read} TEMPLATE end ## # Renders the ERb contained in +file_name+ relative to the template # directory and returns the result based on the current context. def render file_name template_file = @template_dir + file_name template = template_for template_file, false, RDoc::ERBPartial template.filename = template_file.to_s template.result @context end ## # Load and render the erb template in the given +template_file+ and write # it out to +out_file+. # # Both +template_file+ and +out_file+ should be Pathname-like objects. # # An io will be yielded which must be captured by binding in the caller. def render_template template_file, out_file = nil # :yield: io io_output = out_file && !@dry_run && @file_output erb_klass = io_output ? RDoc::ERBIO : ERB template = template_for template_file, true, erb_klass if io_output then debug_msg "Outputting to %s" % [out_file.expand_path] out_file.dirname.mkpath out_file.open 'w', 0644 do |io| io.set_encoding @options.encoding if Object.const_defined? :Encoding @context = yield io template_result template, @context, template_file end else @context = yield nil output = template_result template, @context, template_file debug_msg " would have written %d characters to %s" % [ output.length, out_file.expand_path ] if @dry_run output end end ## # Creates the result for +template+ with +context+. If an error is raised a # Pathname +template_file+ will indicate the file where the error occurred. def template_result template, context, template_file template.filename = template_file.to_s template.result context rescue NoMethodError => e raise RDoc::Error, "Error while evaluating %s: %s" % [ template_file.expand_path, e.message, ], e.backtrace end ## # Retrieves a cache template for +file+, if present, or fills the cache. def template_for file, page = true, klass = ERB template = @template_cache[file] return template if template if page then template = assemble_template file erbout = 'io' else template = file.read template = template.encode @options.encoding if Object.const_defined? :Encoding file_var = File.basename(file).sub(/\..*/, '') erbout = "_erbout_#{file_var}" end template = klass.new template, nil, '<>', erbout @template_cache[file] = template template end end PK J8jZsox ri.rbnu [ ## # Generates ri data files class RDoc::Generator::RI RDoc::RDoc.add_generator self ## # Description of this generator DESCRIPTION = 'creates ri data files' ## # Set up a new ri generator def initialize store, options #:not-new: @options = options @store = store @store.path = '.' end ## # Writes the parsed data store to disk for use by ri. def generate @store.save end end PK J8jZ 5 json_index.rbnu [ require 'json' ## # The JsonIndex generator is designed to complement an HTML generator and # produces a JSON search index. This generator is derived from sdoc by # Vladimir Kolesnikov and contains verbatim code written by him. # # This generator is designed to be used with a regular HTML generator: # # class RDoc::Generator::Darkfish # def initialize options # # ... # @base_dir = Pathname.pwd.expand_path # # @json_index = RDoc::Generator::JsonIndex.new self, options # end # # def generate # # ... # @json_index.generate # end # end # # == Index Format # # The index is output as a JSON file assigned to the global variable # +search_data+. The structure is: # # var search_data = { # "index": { # "searchIndex": # ["a", "b", ...], # "longSearchIndex": # ["a", "a::b", ...], # "info": [ # ["A", "A", "A.html", "", ""], # ["B", "A::B", "A::B.html", "", ""], # ... # ] # } # } # # The same item is described across the +searchIndex+, +longSearchIndex+ and # +info+ fields. The +searchIndex+ field contains the item's short name, the # +longSearchIndex+ field contains the full_name (when appropriate) and the # +info+ field contains the item's name, full_name, path, parameters and a # snippet of the item's comment. # # == LICENSE # # Copyright (c) 2009 Vladimir Kolesnikov # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. class RDoc::Generator::JsonIndex include RDoc::Text ## # Where the search index lives in the generated output SEARCH_INDEX_FILE = File.join 'js', 'search_index.js' attr_reader :index # :nodoc: ## # Creates a new generator. +parent_generator+ is used to determine the # class_dir and file_dir of links in the output index. # # +options+ are the same options passed to the parent generator. def initialize parent_generator, options @parent_generator = parent_generator @store = parent_generator.store @options = options @template_dir = File.expand_path '../template/json_index', __FILE__ @base_dir = @parent_generator.base_dir @classes = nil @files = nil @index = nil end ## # Builds the JSON index as a Hash. def build_index reset @store.all_files.sort, @store.all_classes_and_modules.sort index_classes index_methods index_pages { :index => @index } end ## # Output progress information if debugging is enabled def debug_msg *msg return unless $DEBUG_RDOC $stderr.puts(*msg) end ## # Writes the JSON index to disk def generate debug_msg "Generating JSON index" debug_msg " writing search index to %s" % SEARCH_INDEX_FILE data = build_index return if @options.dry_run out_dir = @base_dir + @options.op_dir index_file = out_dir + SEARCH_INDEX_FILE FileUtils.mkdir_p index_file.dirname, :verbose => $DEBUG_RDOC index_file.open 'w', 0644 do |io| io.set_encoding Encoding::UTF_8 if Object.const_defined? :Encoding io.write 'var search_data = ' JSON.dump data, io, 0 end Dir.chdir @template_dir do Dir['**/*.js'].each do |source| dest = File.join out_dir, source FileUtils.install source, dest, :mode => 0644, :verbose => $DEBUG_RDOC end end end ## # Adds classes and modules to the index def index_classes debug_msg " generating class search index" documented = @classes.uniq.select do |klass| klass.document_self_or_methods end documented.each do |klass| debug_msg " #{klass.full_name}" record = klass.search_record @index[:searchIndex] << search_string(record.shift) @index[:longSearchIndex] << search_string(record.shift) @index[:info] << record end end ## # Adds methods to the index def index_methods debug_msg " generating method search index" list = @classes.uniq.map do |klass| klass.method_list end.flatten.sort_by do |method| [method.name, method.parent.full_name] end list.each do |method| debug_msg " #{method.full_name}" record = method.search_record @index[:searchIndex] << "#{search_string record.shift}()" @index[:longSearchIndex] << "#{search_string record.shift}()" @index[:info] << record end end ## # Adds pages to the index def index_pages debug_msg " generating pages search index" pages = @files.select do |file| file.text? end pages.each do |page| debug_msg " #{page.page_name}" record = page.search_record @index[:searchIndex] << search_string(record.shift) @index[:longSearchIndex] << '' record.shift @index[:info] << record end end ## # The directory classes are written to def class_dir @parent_generator.class_dir end ## # The directory files are written to def file_dir @parent_generator.file_dir end def reset files, classes # :nodoc: @files = files @classes = classes @index = { :searchIndex => [], :longSearchIndex => [], :info => [] } end ## # Removes whitespace and downcases +string+ def search_string string string.downcase.gsub(/\s/, '') end end PK J8jZ9YB B template/darkfish/js/search.jsnu [ Search = function(data, input, result) { this.data = data; this.$input = $(input); this.$result = $(result); this.$current = null; this.$view = this.$result.parent(); this.searcher = new Searcher(data.index); this.init(); } Search.prototype = $.extend({}, Navigation, new function() { var suid = 1; this.init = function() { var _this = this; var observer = function() { _this.search(_this.$input[0].value); }; this.$input.keyup(observer); this.$input.click(observer); // mac's clear field this.searcher.ready(function(results, isLast) { _this.addResults(results, isLast); }) this.initNavigation(); this.setNavigationActive(false); } this.search = function(value, selectFirstMatch) { value = jQuery.trim(value).toLowerCase(); if (value) { this.setNavigationActive(true); } else { this.setNavigationActive(false); } if (value == '') { this.lastQuery = value; this.$result.empty(); this.setNavigationActive(false); } else if (value != this.lastQuery) { this.lastQuery = value; this.firstRun = true; this.searcher.find(value); } } this.addResults = function(results, isLast) { var target = this.$result.get(0); if (this.firstRun && (results.length > 0 || isLast)) { this.$current = null; this.$result.empty(); } for (var i=0, l = results.length; i < l; i++) { target.appendChild(this.renderItem.call(this, results[i])); }; if (this.firstRun && results.length > 0) { this.firstRun = false; this.$current = $(target.firstChild); this.$current.addClass('current'); } if (jQuery.browser.msie) this.$element[0].className += ''; } this.move = function(isDown) { if (!this.$current) return; var $next = this.$current[isDown ? 'next' : 'prev'](); if ($next.length) { this.$current.removeClass('current'); $next.addClass('current'); this.scrollIntoView($next[0], this.$view[0]); this.$current = $next; } return true; } this.hlt = function(html) { return this.escapeHTML(html). replace(/\u0001/g, ''). replace(/\u0002/g, ''); } this.escapeHTML = function(html) { return html.replace(/[&<>]/g, function(c) { return '' + c.charCodeAt(0) + ';'; }); } }); PK J8jZY, template/darkfish/js/darkfish.jsnu [ /** * * Darkfish Page Functions * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $ * * Author: Michael Granger(Not documented) <% end %>
(Not documented) <% end %> <% if method.calls_super then %>
<%= method.markup_code %>
The page <%=h path %> was not found