=begin = rd2html-lib.rb =end require "cgi" require "rd/rdvisitor" require "rd/version" module RD class RD2HTMLVisitor < RDVisitor include MethodParse SYSTEM_NAME = "RDtool -- RD2HTMLVisitor" SYSTEM_VERSION = "$Version: "+ RD::VERSION+"$" VERSION = Version.new_from_version_string(SYSTEM_NAME, SYSTEM_VERSION) def self.version VERSION end # must-have constants OUTPUT_SUFFIX = "html" INCLUDE_SUFFIX = ["html"] METACHAR = { "<" => "<", ">" => ">", "&" => "&" } attr_accessor :css attr_accessor :charset alias charcode charset alias charcode= charset= attr_accessor :lang attr_accessor :title attr_reader :html_link_rel attr_reader :html_link_rev attr_accessor :use_old_anchor # output external Label file. attr_accessor :output_rbl attr_reader :footnotes attr_reader :foottexts def initialize @css = nil @charset = nil @lang = nil @title = nil @html_link_rel = {} @html_link_rev = {} @footnotes = [] @index = {} # @use_old_anchor = nil @use_old_anchor = true # MUST -> nil @output_rbl = nil super end def visit(tree) prepare_labels(tree, "label-") prepare_footnotes(tree) tmp = super(tree) make_rbl_file(@filename) if @output_rbl and @filename tmp end def apply_to_DocumentElement(element, content) ret = "" ret << xml_decl + "\n" ret << doctype_decl + "\n" ret << html_open_tag + "\n" ret << html_head + "\n" ret << html_body(content) + "\n" ret << "\n" ret end def document_title return @title if @title return @filename if @filename return ARGF.filename if ARGF.filename != "-" "Untitled" end private :document_title def xml_decl encoding = %[encoding="#{@charset}" ] if @charset %|| end private :xml_decl def doctype_decl %|| end private :doctype_decl def html_open_tag lang_attr = %[ lang="#{@lang}" xml:lang="#{@lang}"] if @lang %|| end private :html_open_tag def html_head ret = %|\n| ret << html_title + "\n" ret << html_content_type + "\n" if html_content_type ret << link_to_css + "\n" if link_to_css ret << forward_links + "\n" if forward_links ret << backward_links + "\n" if backward_links ret << %Q[] end private :html_head def html_title "#{document_title}" end private :html_title def html_content_type if @charset %Q[" end end private :html_content_type def link_to_css if @css %|" # for ruby-mode.el fontlock, it is separated into 2 lines. end end private :link_to_css def forward_links return nil if @html_link_rel.empty? rels = @html_link_rel.sort{|i, j| i[0] <=> j[0] } (rels.collect do |rel, href| %Q[] end).join("\n") end private :forward_links def backward_links return nil if @html_link_rev.empty? revs = @html_link_rev.sort{|i, j| i[0] <=> j[0] } (revs.collect do |rev, href| %Q[] end).join("\n") end private :backward_links def html_body(contents) content = contents.join("\n") foottext = make_foottext %Q|\n#{content}\n#{foottext}\n| end private :html_body def apply_to_Headline(element, title) anchor = get_anchor(element) label = hyphen_escape(element.label) title = title.join("") %Q[#{title}] + %Q[] end # RDVisitor#apply_to_Include def apply_to_TextBlock(element, content) content = content.join("") if (is_this_textblock_only_one_block_of_parent_listitem?(element) or is_this_textblock_only_one_block_other_than_sublists_in_parent_listitem?(element)) content.chomp else %Q[

#{content.chomp}

] end end def is_this_textblock_only_one_block_of_parent_listitem?(element) parent = element.parent (parent.is_a?(ItemListItem) or parent.is_a?(EnumListItem) or parent.is_a?(DescListItem) or parent.is_a?(MethodListItem)) and consist_of_one_textblock?(parent) end def is_this_textblock_only_one_block_other_than_sublists_in_parent_listitem?(element) parent = element.parent (parent.is_a?(ItemListItem) or parent.is_a?(EnumListItem) or parent.is_a?(DescListItem) or parent.is_a?(MethodListItem)) and consist_of_one_textblock_and_sublists(element.parent) end def consist_of_one_textblock_and_sublists(element) i = 0 element.each_child do |child| if i == 0 return false unless child.is_a?(TextBlock) else return false unless child.is_a?(List) end i += 1 end return true end def apply_to_Verbatim(element) content = [] element.each_line do |i| content.push(apply_to_String(i)) end %Q[
#{content.join("").chomp}
] end def apply_to_ItemList(element, items) %Q[] end def apply_to_EnumList(element, items) %Q[
    \n#{items.join("\n").chomp}\n
] end def apply_to_DescList(element, items) %Q[
\n#{items.join("\n").chomp}\n
] end def apply_to_MethodList(element, items) %Q[
\n#{items.join("\n").chomp}\n
] end def apply_to_ItemListItem(element, content) %Q[
  • #{content.join("\n").chomp}
  • ] end def apply_to_EnumListItem(element, content) %Q[
  • #{content.join("\n").chomp}
  • ] end def consist_of_one_textblock?(listitem) listitem.children.size == 1 and listitem.children[0].is_a?(TextBlock) end private :consist_of_one_textblock? def apply_to_DescListItem(element, term, description) anchor = get_anchor(element.term) label = hyphen_escape(element.label) term = term.join("") if description.empty? %Q[
    #{term}
    ] + %Q[] else %Q[
    #{term}
    ] + %Q[\n] + %Q[
    \n#{description.join("\n").chomp}\n
    ] end end def apply_to_MethodListItem(element, term, description) term = parse_method(term) # maybe: term -> element.term anchor = get_anchor(element.term) label = hyphen_escape(element.label) if description.empty? %Q[
    #{term}] + %Q[
    ] else %Q[
    #{term}] + %Q[
    \n] + %Q[
    \n#{description.join("\n")}
    ] end end def apply_to_StringElement(element) apply_to_String(element.content) end def apply_to_Emphasis(element, content) %Q[#{content.join("")}] end def apply_to_Code(element, content) %Q[#{content.join("")}] end def apply_to_Var(element, content) %Q[#{content.join("")}] end def apply_to_Keyboard(element, content) %Q[#{content.join("")}] end def apply_to_Index(element, content) tmp = [] element.each do |i| tmp.push(i) if i.is_a?(String) end key = meta_char_escape(tmp.join("")) if @index.has_key?(key) # warning? %Q[#{content.join("")}] else num = @index[key] = @index.size anchor = a_name("index", num) %Q[#{content.join("")}] end end def apply_to_Reference_with_RDLabel(element, content) if element.label.filename apply_to_RefToOtherFile(element, content) else apply_to_RefToElement(element, content) end end def apply_to_Reference_with_URL(element, content) %Q[] + %Q[#{content.join("")}] end def apply_to_RefToElement(element, content) content = content.join("") if anchor = refer(element) content = content.sub(/^function#/, "") %Q[#{content}] else # warning? label = hyphen_escape(element.to_label) %Q[] + %Q[#{content}] #' end end def apply_to_RefToOtherFile(element, content) content = content.join("") filename = element.label.filename.sub(/\.(rd|rb)(\.\w+)?$/, "." + OUTPUT_SUFFIX) anchor = refer_external(element) if anchor %Q[#{content}] else %Q[#{content}] end end def apply_to_Footnote(element, content) num = get_footnote_num(element) raise ArgumentError, "[BUG?] #{element} is not registered." unless num add_foottext(num, content) anchor = a_name("footmark", num) href = a_name("foottext", num) %Q|| + %Q|*#{num}| end def get_footnote_num(fn) raise ArgumentError, "#{fn} must be Footnote." unless fn.is_a? Footnote i = @footnotes.index(fn) if i i + 1 else nil end end def prepare_footnotes(tree) @footnotes = tree.find_all{|i| i.is_a? Footnote } @foottexts = [] end private :prepare_footnotes def apply_to_Foottext(element, content) num = get_footnote_num(element) raise ArgumentError, "[BUG] #{element} isn't registered." unless num anchor = a_name("foottext", num) href = a_name("footmark", num) content = content.join("") %||+ %|*#{num}| + %|#{content}
    | end def add_foottext(num, foottext) raise ArgumentError, "[BUG] footnote ##{num} isn't here." unless footnotes[num - 1] @foottexts[num - 1] = foottext end def apply_to_Verb(element) content = apply_to_String(element.content) %Q[#{content}] end def sp2nbsp(str) str.gsub(/\s/, " ") end private :sp2nbsp def apply_to_String(element) meta_char_escape(element) end def parse_method(method) klass, kind, method, args = MethodParse.analize_method(method) if kind == :function klass = kind = nil else kind = MethodParse.kind2str(kind) end args.gsub!(/&?\w+;?/){ |m| if /&\w+;/ =~ m then m else ''+m+'' end } case method when "self" klass, kind, method, args = MethodParse.analize_method(args) "#{klass}#{kind}self #{method}#{args}" when "[]" args.strip! args.sub!(/^\((.*)\)$/, '\\1') "#{klass}#{kind}[#{args}]" when "[]=" args.tr!(' ', '') args.sub!(/^\((.*)\)$/, '\\1') ary = args.split(/,/) case ary.length when 1 val = 'val' when 2 args, val = *ary when 3 args, val = ary[0, 2].join(', '), ary[2] end "#{klass}#{kind}[#{args}] = #{val}" else "#{klass}#{kind}#{method}#{args}" end end private :parse_method def meta_char_escape(str) str.gsub(/[<>&]/) { METACHAR[$&] } end private :meta_char_escape def hyphen_escape(str) str.gsub(/--/, "­­") end def make_foottext return nil if foottexts.empty? content = [] foottexts.each_with_index do |ft, num| content.push(apply_to_Foottext(footnotes[num], ft)) end %|
    \n

    \n#{content.join("\n")}\n

    | end private :make_foottext def a_name(prefix, num) "#{prefix}-#{num}" end private :a_name end # RD2HTMLVisitor end # RD $Visitor_Class = RD::RD2HTMLVisitor $RD2_Sub_OptionParser = "rd/rd2html-opt" =begin == script info. RD to HTML translate library for rdfmt.rb $Id: rd2html-lib.rb,v 1.53 2003/03/08 12:45:08 tosh Exp $ =end