class Mizuho::Generator

Public Class Methods

new(input, options = {}) click to toggle source
# File lib/mizuho/generator.rb, line 34
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
run_asciidoc(input, output, icons_dir = nil, conf_file = nil, attributes = []) click to toggle source
# File lib/mizuho/generator.rb, line 78
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

Public Instance Methods

start() click to toggle source
# File lib/mizuho/generator.rb, line 52
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

Private Instance Methods

add_child_and_get(node, html) click to toggle source

For Nokogiri 1.4.0 compatibility

# File lib/mizuho/generator.rb, line 316
def add_child_and_get(node, html)
        result = node.add_child(make_node(html, node.document))
        result = result[0] if result.is_a?(Array)
        return result
end
add_previous_sibling_and_get(node, html) click to toggle source

For Nokogiri 1.4.0 compatibility

# File lib/mizuho/generator.rb, line 323
def add_previous_sibling_and_get(node, html)
        result = node.add_previous_sibling(make_node(html, node.document))
        result = result[0] if result.is_a?(Array)
        return result
end
create_comment_balloon() click to toggle source
# File lib/mizuho/generator.rb, line 279
def create_comment_balloon
        return %Q{<a href="javascript:void(0)" class="comments empty" title="Add a comment"><span class="count"></span></a>}
end
create_search_index(headers, filename) click to toggle source
# File lib/mizuho/generator.rb, line 347
def create_search_index(headers, filename)
        require 'sqlite3'
        db = SQLite3::Database.new("#{filename}.tmp")
        db.transaction do
                db.execute(%q{
                        CREATE VIRTUAL TABLE book USING fts4(
                                title TEXT NOT NULL,
                                content TEXT NOT NULL,
                                content="",
                                tokenize=porter
                        )
                })
                db.execute(%q{
                        CREATE TABLE version(
                                version INTEGER NOT NULL
                        )
                })
                db.execute("INSERT INTO version VALUES(1)")
                db.prepare("INSERT INTO book(docid, title, content) VALUES(?, ?, ?)") do |stmt|
                        headers.each do |header|
                                next if header['class'] =~ /float/
                                title = header.text.strip
                                docid = Utils.title_to_docid(title)
                                content = gather_content(header)
                                stmt.execute(docid, title, content)
                        end
                end
        end
        db.execute("INSERT INTO book(book) VALUES('optimize')")
        db.execute("VACUUM")
        db.close
        File.rename("#{filename}.tmp", filename)
rescue Exception => e
        File.unlink("#{filename}.tmp") rescue nil
        raise e
end
default_id_map_filename(input) click to toggle source
# File lib/mizuho/generator.rb, line 115
def default_id_map_filename(input)
        return File.dirname(input) +
                "/" +
                File.basename(input, File.extname(input)) +
                ".idmap.txt"
end
default_index_filename(input) click to toggle source
# File lib/mizuho/generator.rb, line 122
def default_index_filename(input)
        return File.dirname(input) +
                "/" +
                File.basename(input, File.extname(input)) +
                ".index.sqlite3"
end
default_output_filename(input) click to toggle source
# File lib/mizuho/generator.rb, line 108
def default_output_filename(input)
        return File.dirname(input) +
                "/" +
                File.basename(input, File.extname(input)) +
                ".html"
end
gather_content(header) click to toggle source
# File lib/mizuho/generator.rb, line 329
def gather_content(header)
        result = []
        elem = header
        while true
                elem = elem.next_sibling
                if !elem || elem.name =~ /^h/i
                        break
                else
                        text = elem.text.strip
                        if !text.empty?
                                text.gsub!(/\r?\n/, " ")
                                result << text
                        end
                end
        end
        return result.join(" ")
end
javascript_tag(doc) click to toggle source
# File lib/mizuho/generator.rb, line 259
def javascript_tag(doc)
        node = Nokogiri::XML::Node.new('script', doc)
        content = ""
        content << File.read("#{TEMPLATES_DIR}/jquery-1.7.1.min.js") << "\n"
        content << File.read("#{TEMPLATES_DIR}/jquery.hashchange-1.0.0.js") << "\n"
        content << File.read("#{TEMPLATES_DIR}/mizuho.js") << "\n"
        if @enable_topbar
                content << File.read("#{TEMPLATES_DIR}/topbar.js") << "\n"
        end
        if @commenting_system == 'juvia'
                content << %Q{
                        var JUVIA_URL = '#{@options[:juvia_url]}';
                        var JUVIA_SITE_KEY = '#{@options[:juvia_site_key]}';
                }
                content << File.read("#{TEMPLATES_DIR}/juvia.js") << "\n"
        end
        node.content = content
        return node
end
make_node(html, doc) click to toggle source

For Nokogiri 1.4.0 compatibility

# File lib/mizuho/generator.rb, line 309
def make_node(html, doc)
        result = Nokogiri::XML::Node.new('div', doc)
        result.inner_html = html
        return result.children[0]
end
render_template(name) click to toggle source
# File lib/mizuho/generator.rb, line 283
def render_template(name)
        content = File.read("#{TEMPLATES_DIR}/#{name}")
        content.gsub!(/\{INLINE_IMAGE:(.*?)\.png\}/) do
                data = File.open("#{TEMPLATES_DIR}/#{$1}.png", "rb") do |f|
                        f.read
                end
                data = [data].pack('m')
                data.gsub!("\n", "")
                "data:image/png;base64,#{data}"
        end
        return content
end
require_options(options, *required_keys) click to toggle source
# File lib/mizuho/generator.rb, line 296
def require_options(options, *required_keys)
        fail = false
        required_keys.each do |key|
                if !options.has_key?(key)
                        fail = true
                        argument_name = '--' + key.to_s.gsub('_', '-')
                        STDERR.puts "You must also specify #{argument_name}!"
                end
        end
        exit 1 if fail
end
stylesheet_tag() click to toggle source
# File lib/mizuho/generator.rb, line 225
def stylesheet_tag
        content = %Q{<style type="text/css">\n}
        
        css = File.read("#{TEMPLATES_DIR}/mizuho.css")
        css.gsub!(/url\('(.*?)\.png'\)/) do
                data = File.open("#{TEMPLATES_DIR}/#{$1}.png", "rb") do |f|
                        f.read
                end
                data = [data].pack('m')
                data.gsub!("\n", "")
                "url('data:image/png;base64,#{data}')"
        end
        content << css << "\n"
        
        if @enable_topbar
                content << File.read("#{TEMPLATES_DIR}/topbar.css") << "\n"
        end
        
        if @commenting_system == 'disqus'
                content << File.read("#{TEMPLATES_DIR}/disqus.css") << "\n"
        elsif @commenting_system == 'intensedebate'
                content << File.read("#{TEMPLATES_DIR}/intensedebate.css") << "\n"
        end
        
        content << %Q{</style>\n}
        return content
end
topbar(title) click to toggle source
# File lib/mizuho/generator.rb, line 253
def topbar(title)
        content = render_template("topbar.html")
        content.gsub!(/\{TITLE\}/, title)
        return content
end
transform(filename) click to toggle source
# File lib/mizuho/generator.rb, line 133
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{<div id="toc"></div>})
                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{<div id="toctitle">Table of Contents</div>}, doc))
                headers.each do |header|
                        if header['class'] !~ /float/
                                level = header.name.scan(/\d+/).first
                                div  = add_child_and_get(toc_div, "<div class=\"foo toclevel#{level}\"></div>")
                                link = add_child_and_get(div, "<a></a>")
                                link['href'] = '#' + header['id']
                                link.content = header.text
                        end
                end

                if @enable_topbar
                        # Add invisible spans before each header so that anchor jumps
                        # don't hide the header behind the top bar.
                        # http://nicolasgallagher.com/jump-links-and-viewport-positioning/
                        headers.each do |header|
                                span = add_previous_sibling_and_get(header, '<span class="anchor_helper"></span>')
                                span['id'] = header['data-anchor'] = header['id']
                                header.remove_attribute('id')
                        end
                end

                if @index
                        # Add docid attributes to headers.
                        headers.each do |header|
                                next if header['class'] =~ /float/
                                docid = Utils.title_to_docid(header.text)
                                header['data-docid'] = docid.to_s
                                header['class'] = "#{header['class']} docid-#{docid}".strip
                        end

                        create_search_index(headers, @index_filename)
                end
                
                f.rewind
                f.truncate(0)
                f.puts(doc.to_html)
        end
end
warn(message) click to toggle source
# File lib/mizuho/generator.rb, line 129
def warn(message)
        STDERR.puts(message)
end