# encoding: utf-8 # Copyright (c) 2008-2013 Hongli Lai # # 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. require 'nokogiri' require 'mizuho' require 'mizuho/source_highlight' require 'mizuho/id_map' require 'mizuho/utils' module Mizuho class GenerationError < StandardError end class Generator def initialize(input, options = {}) @options = options @input_file = input @output_file = options[:output] || default_output_filename(input) @id_map_file = options[:id_map] || default_id_map_filename(input) @icons_dir = options[:icons_dir] @conf_file = options[:conf_file] @attributes = options[:attributes] || [] @enable_topbar = options[:topbar] @no_run = options[:no_run] @commenting_system = options[:commenting_system] @index = options[:index] @index_filename = options[:index_filename] || default_index_filename(input) if @commenting_system == 'juvia' require_options(options, :juvia_url, :juvia_site_key) end end def start if @commenting_system @id_map = IdMap.new if File.exist?(@id_map_file) @id_map.load(@id_map_file) else warn "No ID map file, generating one (#{@id_map_file})..." end end if !@no_run self.class.run_asciidoc(@input_file, @output_file, @icons_dir, @conf_file, @attributes) end transform(@output_file) if @commenting_system @id_map.save(@id_map_file) stats = @id_map.stats if stats[:fuzzy] > 0 warn "Warning: #{stats[:fuzzy]} fuzzy ID(s)" end if stats[:orphaned] > 0 warn "Warning: #{stats[:orphaned]} unused ID(s)" end end end def self.run_asciidoc(input, output, icons_dir = nil, conf_file = nil, attributes = []) args = [ ASCIIDOC, "-b", "html5", "-a", "theme=flask", "-a", "icons", "-n" ].flatten if icons_dir args << "-a" args << "iconsdir=#{icons_dir}" end attributes.each do |attribute| args << "-a" args << attribute end if conf_file # With the splat operator we support a string and an array of strings. [*conf_file].each do |cf| args << "-f" args << cf end end args += ["-o", output, input] if !system(*args) raise GenerationError, "Asciidoc failed." end end private def default_output_filename(input) return File.dirname(input) + "/" + File.basename(input, File.extname(input)) + ".html" end def default_id_map_filename(input) return File.dirname(input) + "/" + File.basename(input, File.extname(input)) + ".idmap.txt" end def default_index_filename(input) return File.dirname(input) + "/" + File.basename(input, File.extname(input)) + ".index.sqlite3" end def warn(message) STDERR.puts(message) end def transform(filename) File.open(filename, 'r+') do |f| doc = Nokogiri.HTML(f) head = (doc / "head")[0] body = (doc / "body")[0] title = (doc / "title")[0].text header_div = (doc / "#header")[0] headers = (doc / "#content" / "h1, h2, h3, h4") head.add_child(make_node(stylesheet_tag, doc)) # Remove footer with generation timestamp. (doc / "#footer-text").remove # Add commenting balloons. if @commenting_system titles = [] headers.each do |header| if header['class'] !~ /float/ titles << header.text end end @id_map.generate_associations(titles) headers.each do |header| if header['class'] !~ /float/ titles << header.text header['data-comment-topic'] = @id_map.associations[header.text] header.add_previous_sibling(make_node(create_comment_balloon, doc)) end end end # Add top bar. if @enable_topbar body.children.first.add_previous_sibling(make_node(topbar(title), doc)) end # Add Mizuho Javascript. body.add_child(javascript_tag(doc)) # Move preamble from content area to header area. if preamble = (doc / "#preamble")[0] preamble.remove header_div.add_child(make_node(preamble, doc)) end # Create a TOC after the preamble. toc_div = add_child_and_get(header_div, %Q{
}) if @commenting_system # Add a commenting balloon to the TOC title. toc_div.add_child(make_node(create_comment_balloon, doc)) end toc_div.add_child(make_node(%Q{