# -*- coding: utf-8 -*- # #-- # Copyright (C) 2009-2010 Thomas Leitner # # This file is part of kramdown. # # kramdown is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . #++ # require 'erb' module Kramdown module Converter # == Base class for converters # # This class serves as base class for all converters. It provides methods that can/should be # used by all converters (like #generate_id) as well as common functionality that is # automatically applied to the result (for example, embedding the output into a template). # # == Implementing a converter # # Implementing a new converter is rather easy: just create a new sub class from this class and # put it in the Kramdown::Converter module (the latter is only needed if auto-detection should # work properly). Then you need to implement the #convert(tree) method which takes a document # tree and should return the converted output. # # The document instance is automatically set as @doc in Base#initialize. Furthermore, the # document instance provides a hash called `conversion_infos` that is also automatically cleared # and can be used to store information about the conversion process. # # The actual transformation of the document tree can be done in any way. However, writing one # method per tree element type is a straight forward way to do it - this is how the Html and # Latex converters do the transformation. class Base # Initialize the converter with the given Kramdown document +doc+. def initialize(doc) @doc = doc @doc.conversion_infos.clear end private_class_method(:new, :allocate) # Convert the Kramdown document +doc+ to the output format implemented by a subclass. # # Initializes a new instance of the calling class and then calls the #convert method that must # be implemented by each subclass. If the +template+ option is specified and non-empty, the # result is rendered into the specified template. def self.convert(doc) result = new(doc).convert(doc.tree) result = apply_template(doc, result) if !doc.options[:template].empty? result end # Apply the template specified in the +doc+ options, using +body+ as the body string. def self.apply_template(doc, body) erb = ERB.new(get_template(doc.options[:template])) obj = Object.new obj.instance_variable_set(:@doc, doc) obj.instance_variable_set(:@body, body) erb.result(obj.instance_eval{binding}) end # Return the template specified by +template+. def self.get_template(template) format_ext = '.' + self.name.split(/::/).last.downcase shipped = File.join(::Kramdown.data_dir, template + format_ext) if File.exist?(template) File.read(template) elsif File.exist?(template + format_ext) File.read(template + format_ext) elsif File.exist?(shipped) File.read(shipped) else raise "The specified template file #{template} does not exist" end end # Generate an unique alpha-numeric ID from the the string +str+ for use as header ID. def generate_id(str) gen_id = str.gsub(/[^a-zA-Z0-9 -]/, '').gsub(/^[^a-zA-Z]*/, '').gsub(' ', '-').downcase gen_id = 'section' if gen_id.length == 0 @used_ids ||= {} if @used_ids.has_key?(gen_id) gen_id += '-' + (@used_ids[gen_id] += 1).to_s else @used_ids[gen_id] = 0 end @doc.options[:auto_id_prefix] + gen_id end end end end