module PDoc module Generators module Html unless defined? TEMPLATES_DIRECTORY TEMPLATES_DIRECTORY = File.join(TEMPLATES_DIR, "html") end class Website < AbstractGenerator include Helpers::BaseHelper include Helpers::LinkHelper class << Website attr_accessor :syntax_highlighter attr_accessor :markdown_parser def pretty_urls? !!@pretty_urls end def pretty_urls=(boolean) @pretty_urls = boolean end end attr_reader :templates_directory, :custom_assets, :index_page def initialize(parser_output, options = {}) super @templates_directory = File.expand_path(options[:templates] || TEMPLATES_DIRECTORY) @index_page = options[:index_page] && File.expand_path(options[:index_page]) @custom_assets = @options[:assets] && File.expand_path(@options[:assets]) self.class.syntax_highlighter = SyntaxHighlighter.new(options[:syntax_highlighter]) self.class.pretty_urls = options[:pretty_urls] set_markdown_parser(options[:markdown_parser]) load_custom_helpers end def set_markdown_parser(parser = nil) parser = :rdiscount if parser.nil? case parser.to_sym when :rdiscount require 'rdiscount' self.class.markdown_parser = RDiscount when :bluecloth require 'bluecloth' self.class.markdown_parser = BlueCloth when :maruku require 'maruku' self.class.markdown_parser = Maruku else raise "Requested unsupported Markdown parser: #{parser}." end end def load_custom_helpers begin require File.join(templates_directory, "helpers") rescue LoadError => e return nil end self.class.__send__(:include, Helpers::BaseHelper) Page.__send__(:include, Helpers::BaseHelper) Helpers.constants.map(&Helpers.method(:const_get)).each(&DocPage.method(:include)) end # Generates the website to the specified directory. def render(output) @depth = 0 path = File.expand_path(output) FileUtils.mkdir_p(path) Dir.chdir(path) do render_index copy_assets copy_custom_assets render_children(root) if root.sections? root.sections.each do |section| @depth = 0 render_template('section', { :doc_instance => section }) end end dest = File.join("javascripts", "pdoc", "item_index.js") DocPage.new("item_index.js", false, variables).render_to_file(dest) end end def render_index vars = variables.merge(:index_page_content => index_page_content, :home => true) DocPage.new('index', 'layout', vars).render_to_file('index.html') end def render_template(template, var = {}) @depth += 1 doc = var[:doc_instance] dest = doc.url(File::SEPARATOR) puts " Rendering #{dest}..." FileUtils.mkdir_p(dest) DocPage.new(template, variables.merge(var)).render_to_file(File.join(dest, 'index.html')) render_json("#{dest}.json", doc) if json_api? render_children(doc) @depth -= 1 end def render_json(dest, obj) open(dest, 'w') { |file| file << obj.to_json } end def render_children(obj) [:namespaces, :classes, :mixins].each do |prop| obj.send(prop).each(&method(:render_node)) if obj.respond_to?(prop) end obj.utilities.each(&method(:render_leaf)) if obj.respond_to?(:utilities) render_leaf(obj.constructor) if obj.respond_to?(:constructor) && obj.constructor [:instance_methods, :instance_properties, :class_methods, :class_properties, :constants].each do |prop| obj.send(prop).each(&method(:render_leaf)) if obj.respond_to?(prop) end end # Copies the content of the assets folder to the generated website's # root directory. def copy_assets FileUtils.cp_r(Dir.glob(File.join(templates_directory, "assets", "**")), '.') end def copy_custom_assets if custom_assets FileUtils.cp_r(Dir.glob(File.join(custom_assets, "**")), ".") end end def render_leaf(object) is_proto_prop = is_proto_prop?(object) @depth += 1 if is_proto_prop render_template('leaf', { :doc_instance => object }) @depth -= 1 if is_proto_prop end def render_node(object) render_template('node', { :doc_instance => object }) end private def variables { :root => root, :depth => @depth, :templates_directory => templates_directory, :name => @options[:name], :short_name => @options[:short_name] || @options[:name], :home_url => @options[:home_url], :version => @options[:version], :footer => footer, :index_header => index_header, :header => header, :timestamp => timestamp } end def header @header ||= @options[:header] ? htmlize(@options[:header]) : '' end def index_header @index_header ||= @options[:index_header] ? htmlize(@options[:index_header]) : '' end def footer @footer ||= @options[:footer] ? htmlize(@options[:footer]) : '' end def timestamp @timestamp ||= @options[:timestamp] == false ? nil : Time.now.utc end def json_api? !!options[:json_api] end def is_proto_prop?(object) object.is_a?(Models::InstanceMethod) || object.is_a?(Models::InstanceProperty) end def index_page_content @index_page ? htmlize(File.read(@index_page)) : nil end end end end end