rdoc-f95 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/Manifest.txt +79 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +147 -0
- data/Rakefile +28 -0
- data/bin/rdoc-f95 +70 -0
- data/lib/rdoc-f95.rb +306 -0
- data/lib/rdoc-f95/code_objects.rb +776 -0
- data/lib/rdoc-f95/diagram.rb +342 -0
- data/lib/rdoc-f95/dot.rb +249 -0
- data/lib/rdoc-f95/generator.rb +1088 -0
- data/lib/rdoc-f95/generator/chm.rb +113 -0
- data/lib/rdoc-f95/generator/chm/chm.rb +98 -0
- data/lib/rdoc-f95/generator/html.rb +370 -0
- data/lib/rdoc-f95/generator/html/hefss.rb +414 -0
- data/lib/rdoc-f95/generator/html/html.rb +708 -0
- data/lib/rdoc-f95/generator/html/kilmer.rb +418 -0
- data/lib/rdoc-f95/generator/html/one_page_html.rb +121 -0
- data/lib/rdoc-f95/generator/ri.rb +229 -0
- data/lib/rdoc-f95/generator/xhtml.rb +106 -0
- data/lib/rdoc-f95/generator/xhtml/ctop.xsl +1318 -0
- data/lib/rdoc-f95/generator/xhtml/mathml.xsl +42 -0
- data/lib/rdoc-f95/generator/xhtml/pmathml.xsl +612 -0
- data/lib/rdoc-f95/generator/xhtml/pmathmlcss.xsl +872 -0
- data/lib/rdoc-f95/generator/xhtml/xhtml.rb +732 -0
- data/lib/rdoc-f95/generator/xml.rb +120 -0
- data/lib/rdoc-f95/generator/xml/rdf.rb +113 -0
- data/lib/rdoc-f95/generator/xml/xml.rb +111 -0
- data/lib/rdoc-f95/install.rb +166 -0
- data/lib/rdoc-f95/markup.rb +506 -0
- data/lib/rdoc-f95/markup/formatter.rb +14 -0
- data/lib/rdoc-f95/markup/fragments.rb +337 -0
- data/lib/rdoc-f95/markup/inline.rb +361 -0
- data/lib/rdoc-f95/markup/install.rb +57 -0
- data/lib/rdoc-f95/markup/lines.rb +152 -0
- data/lib/rdoc-f95/markup/mathml_wrapper.rb +91 -0
- data/lib/rdoc-f95/markup/preprocess.rb +71 -0
- data/lib/rdoc-f95/markup/sample/rdoc2latex.rb +16 -0
- data/lib/rdoc-f95/markup/sample/sample.rb +42 -0
- data/lib/rdoc-f95/markup/to_flow.rb +185 -0
- data/lib/rdoc-f95/markup/to_html.rb +357 -0
- data/lib/rdoc-f95/markup/to_html_crossref.rb +123 -0
- data/lib/rdoc-f95/markup/to_latex.rb +328 -0
- data/lib/rdoc-f95/markup/to_test.rb +50 -0
- data/lib/rdoc-f95/markup/to_xhtml_texparser.rb +234 -0
- data/lib/rdoc-f95/options.rb +745 -0
- data/lib/rdoc-f95/parsers/parse_c.rb +775 -0
- data/lib/rdoc-f95/parsers/parse_f95.rb +2499 -0
- data/lib/rdoc-f95/parsers/parse_rb.rb +2587 -0
- data/lib/rdoc-f95/parsers/parse_simple.rb +39 -0
- data/lib/rdoc-f95/parsers/parserfactory.rb +99 -0
- data/lib/rdoc-f95/ri.rb +2 -0
- data/lib/rdoc-f95/ri/cache.rb +188 -0
- data/lib/rdoc-f95/ri/descriptions.rb +147 -0
- data/lib/rdoc-f95/ri/display.rb +244 -0
- data/lib/rdoc-f95/ri/driver.rb +435 -0
- data/lib/rdoc-f95/ri/formatter.rb +603 -0
- data/lib/rdoc-f95/ri/paths.rb +105 -0
- data/lib/rdoc-f95/ri/reader.rb +106 -0
- data/lib/rdoc-f95/ri/util.rb +81 -0
- data/lib/rdoc-f95/ri/writer.rb +64 -0
- data/lib/rdoc-f95/stats.rb +23 -0
- data/lib/rdoc-f95/template.rb +64 -0
- data/lib/rdoc-f95/tokenstream.rb +33 -0
- data/lib/rdoc-f95/usage.rb +210 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test/test_helper.rb +3 -0
- data/test/test_rdoc-f95.rb +11 -0
- metadata +156 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'find'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
include Config
|
7
|
+
|
8
|
+
opt = OptionParser.new
|
9
|
+
libdir = nil
|
10
|
+
opt.on('--libdir=VAL') {|v| libdir = v}
|
11
|
+
opt.parse!(ARGV)
|
12
|
+
|
13
|
+
libdir = File.expand_path(libdir) if libdir
|
14
|
+
|
15
|
+
if libdir
|
16
|
+
sitedir = libdir
|
17
|
+
else
|
18
|
+
sitedir = CONFIG["sitelibdir"]
|
19
|
+
unless sitedir
|
20
|
+
version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
|
21
|
+
libdir = File.join(CONFIG["libdir"], "ruby", version)
|
22
|
+
sitedir = $:.find {|x| x =~ /site_ruby/}
|
23
|
+
if !sitedir
|
24
|
+
sitedir = File.join(libdir, "site_ruby")
|
25
|
+
elsif sitedir !~ Regexp.quote(version)
|
26
|
+
sitedir = File.join(sitedir, version)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
unless /^\// =~ sitedir.strip
|
32
|
+
sitedir = File.join("..", sitedir)
|
33
|
+
end
|
34
|
+
|
35
|
+
if !File.directory?(sitedir)
|
36
|
+
$stderr.puts "Cannot find sitedir #{sitedir}"
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
rdoc_dest = File.join(sitedir, "rdoc")
|
41
|
+
|
42
|
+
dest = File.join(rdoc_dest, "markup")
|
43
|
+
|
44
|
+
FileUtils::makedirs(dest, {:verbose => true})
|
45
|
+
|
46
|
+
Find.find("./",
|
47
|
+
"sample") do |fname|
|
48
|
+
if File.directory?(fname)
|
49
|
+
next if fname =~ /CVS/
|
50
|
+
FileUtils::makedirs(File.join(dest, fname), {:verbose => true})
|
51
|
+
else
|
52
|
+
next unless fname =~ /\.rb$/
|
53
|
+
next if fname =~ /install.rb$/
|
54
|
+
FileUtils::install(fname, File.join(dest, fname),
|
55
|
+
{:mode => 0444, :verbose => true})
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
class RDocF95::Markup
|
2
|
+
|
3
|
+
##
|
4
|
+
# We store the lines we're working on as objects of class Line. These
|
5
|
+
# contain the text of the line, along with a flag indicating the line type,
|
6
|
+
# and an indentation level.
|
7
|
+
|
8
|
+
class Line
|
9
|
+
INFINITY = 9999
|
10
|
+
|
11
|
+
LINE_TYPES = [
|
12
|
+
:BLANK,
|
13
|
+
:HEADING,
|
14
|
+
:LIST,
|
15
|
+
:PARAGRAPH,
|
16
|
+
:RULE,
|
17
|
+
:VERBATIM,
|
18
|
+
]
|
19
|
+
|
20
|
+
# line type
|
21
|
+
attr_accessor :type
|
22
|
+
|
23
|
+
# The indentation nesting level
|
24
|
+
attr_accessor :level
|
25
|
+
|
26
|
+
# The contents
|
27
|
+
attr_accessor :text
|
28
|
+
|
29
|
+
# A prefix or parameter. For LIST lines, this is
|
30
|
+
# the text that introduced the list item (the label)
|
31
|
+
attr_accessor :param
|
32
|
+
|
33
|
+
# A flag. For list lines, this is the type of the list
|
34
|
+
attr_accessor :flag
|
35
|
+
|
36
|
+
# the number of leading spaces
|
37
|
+
attr_accessor :leading_spaces
|
38
|
+
|
39
|
+
# true if this line has been deleted from the list of lines
|
40
|
+
attr_accessor :deleted
|
41
|
+
|
42
|
+
def initialize(text)
|
43
|
+
@text = text.dup
|
44
|
+
@deleted = false
|
45
|
+
|
46
|
+
# expand tabs
|
47
|
+
1 while @text.gsub!(/\t+/) { ' ' * (8*$&.length - $`.length % 8)} && $~ #`
|
48
|
+
|
49
|
+
# Strip trailing whitespace
|
50
|
+
@text.sub!(/\s+$/, '')
|
51
|
+
|
52
|
+
# and look for leading whitespace
|
53
|
+
if @text.length > 0
|
54
|
+
@text =~ /^(\s*)/
|
55
|
+
@leading_spaces = $1.length
|
56
|
+
else
|
57
|
+
@leading_spaces = INFINITY
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return true if this line is blank
|
62
|
+
def blank?
|
63
|
+
@text.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
# stamp a line with a type, a level, a prefix, and a flag
|
67
|
+
def stamp(type, level, param="", flag=nil)
|
68
|
+
@type, @level, @param, @flag = type, level, param, flag
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Strip off the leading margin
|
73
|
+
|
74
|
+
def strip_leading(size)
|
75
|
+
if @text.size > size
|
76
|
+
@text[0,size] = ""
|
77
|
+
else
|
78
|
+
@text = ""
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_s
|
83
|
+
"#@type#@level: #@text"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# A container for all the lines.
|
89
|
+
|
90
|
+
class Lines
|
91
|
+
|
92
|
+
include Enumerable
|
93
|
+
|
94
|
+
attr_reader :lines # :nodoc:
|
95
|
+
|
96
|
+
def initialize(lines)
|
97
|
+
@lines = lines
|
98
|
+
rewind
|
99
|
+
end
|
100
|
+
|
101
|
+
def empty?
|
102
|
+
@lines.size.zero?
|
103
|
+
end
|
104
|
+
|
105
|
+
def each
|
106
|
+
@lines.each do |line|
|
107
|
+
yield line unless line.deleted
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# def [](index)
|
112
|
+
# @lines[index]
|
113
|
+
# end
|
114
|
+
|
115
|
+
def rewind
|
116
|
+
@nextline = 0
|
117
|
+
end
|
118
|
+
|
119
|
+
def next
|
120
|
+
begin
|
121
|
+
res = @lines[@nextline]
|
122
|
+
@nextline += 1 if @nextline < @lines.size
|
123
|
+
end while res and res.deleted and @nextline < @lines.size
|
124
|
+
res
|
125
|
+
end
|
126
|
+
|
127
|
+
def unget
|
128
|
+
@nextline -= 1
|
129
|
+
end
|
130
|
+
|
131
|
+
def delete(a_line)
|
132
|
+
a_line.deleted = true
|
133
|
+
end
|
134
|
+
|
135
|
+
def normalize
|
136
|
+
margin = @lines.collect{|l| l.leading_spaces}.min
|
137
|
+
margin = 0 if margin == :INFINITY
|
138
|
+
@lines.each {|line| line.strip_leading(margin) } if margin > 0
|
139
|
+
end
|
140
|
+
|
141
|
+
def as_text
|
142
|
+
@lines.map {|l| l.text}.join("\n")
|
143
|
+
end
|
144
|
+
|
145
|
+
def line_types
|
146
|
+
@lines.map {|l| l.type }
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# This class is MathML module wrapper.
|
2
|
+
# If MathML module can not be loaded, methods in this module return
|
3
|
+
# raw argument without modification.
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
class MathMLWrapper
|
7
|
+
|
8
|
+
# Mathml library name
|
9
|
+
MATHML_NAME = [ "mathml", "math_ml" ]
|
10
|
+
|
11
|
+
# $LOAD_PATH/MATHML_NAME/MACRO_REL_PATH/* files are parsed as TeX macro
|
12
|
+
MACRO_REL_PATH = "macro"
|
13
|
+
|
14
|
+
@@mathml_required = false
|
15
|
+
@@macro_input_flag = false
|
16
|
+
@@macro_path = ''
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
|
20
|
+
err_count = 0
|
21
|
+
if !@@mathml_required
|
22
|
+
MATHML_NAME.each{ |ml|
|
23
|
+
begin
|
24
|
+
require ml
|
25
|
+
@@macro_path = File.join(ml, MACRO_REL_PATH)
|
26
|
+
rescue LoadError
|
27
|
+
err_count = err_count + 1
|
28
|
+
end
|
29
|
+
}
|
30
|
+
if err_count < MATHML_NAME.size
|
31
|
+
@@mathml_required = true
|
32
|
+
else
|
33
|
+
raise LoadError,
|
34
|
+
" Error: \"#{MATHML_NAME.join('" or "')}\" library is not found\n" +
|
35
|
+
" in $LOAD_PATH=[#{$LOAD_PATH.join(',')}]\n\n"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if (@@mathml_required && !@@macro_input_flag)
|
40
|
+
@@mathml_formula_macro = MathML::LaTeX::Parser.new
|
41
|
+
@@macro_input_flag = true
|
42
|
+
$LOAD_PATH.each{ |lpath|
|
43
|
+
macro_files = Dir::glob(File.join(lpath, @@macro_path, "*"))
|
44
|
+
macro_files.each{ |mfile|
|
45
|
+
if File.file?(mfile)
|
46
|
+
File.open(mfile, "r" ) { |io|
|
47
|
+
if $DEBUG_RDOC
|
48
|
+
puts \
|
49
|
+
"\n##### Debug messages about \"#{__FILE__}\" #####",
|
50
|
+
" \"#{mfile}\" is loading as a TeX macro file.",
|
51
|
+
" Following macros have been included."
|
52
|
+
end
|
53
|
+
io.each{ |line|
|
54
|
+
line.chomp!
|
55
|
+
macroerrormsg = nil
|
56
|
+
begin
|
57
|
+
@@mathml_formula_macro.macro.parse(line)
|
58
|
+
rescue MathML::LaTeX::ParseError
|
59
|
+
macroerrormsg = $!.to_s
|
60
|
+
rescue
|
61
|
+
macroerrormsg = $!.to_s
|
62
|
+
end
|
63
|
+
if macroerrormsg
|
64
|
+
$stderr.puts "Warning: in #{mfile}, following TeX macro causes #{macroerrormsg.to_s}\n\n",
|
65
|
+
" #{line}\n\n"
|
66
|
+
else
|
67
|
+
if $DEBUG_RDOC && !(line.empty?) && !(line =~ /\s*\%/)
|
68
|
+
puts " #{line}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
}
|
72
|
+
}
|
73
|
+
end
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
def parse(formula, block=false)
|
80
|
+
return formula if !@@mathml_required
|
81
|
+
mathml_formula = @@mathml_formula_macro
|
82
|
+
begin
|
83
|
+
mathml_formula_str = mathml_formula.parse(formula, block).to_s
|
84
|
+
rescue MathML::LaTeX::ParseError
|
85
|
+
return formula, 1
|
86
|
+
rescue
|
87
|
+
return formula, 1
|
88
|
+
end
|
89
|
+
return mathml_formula_str, 0
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rdoc-f95/markup'
|
2
|
+
|
3
|
+
##
|
4
|
+
# Handle common directives that can occur in a block of text:
|
5
|
+
#
|
6
|
+
# : include : filename
|
7
|
+
|
8
|
+
class RDocF95::Markup::PreProcess
|
9
|
+
|
10
|
+
def initialize(input_file_name, include_path)
|
11
|
+
@input_file_name = input_file_name
|
12
|
+
@include_path = include_path
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Look for common options in a chunk of text. Options that we don't handle
|
17
|
+
# are passed back to our caller as |directive, param|
|
18
|
+
|
19
|
+
def handle(text)
|
20
|
+
text.gsub!(/^([ \t#]*):(\w+):\s*(.+)?\n/) do
|
21
|
+
prefix = $1
|
22
|
+
directive = $2.downcase
|
23
|
+
param = $3
|
24
|
+
|
25
|
+
case directive
|
26
|
+
when "include"
|
27
|
+
filename = param.split[0]
|
28
|
+
include_file(filename, prefix)
|
29
|
+
|
30
|
+
else
|
31
|
+
yield(directive, param)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
##
|
39
|
+
# Include a file, indenting it correctly.
|
40
|
+
|
41
|
+
def include_file(name, indent)
|
42
|
+
if full_name = find_include_file(name) then
|
43
|
+
content = File.open(full_name) {|f| f.read}
|
44
|
+
# strip leading '#'s, but only if all lines start with them
|
45
|
+
if content =~ /^[^#]/
|
46
|
+
content.gsub(/^/, indent)
|
47
|
+
else
|
48
|
+
content.gsub(/^#?/, indent)
|
49
|
+
end
|
50
|
+
else
|
51
|
+
$stderr.puts "Couldn't find file to include: '#{name}'"
|
52
|
+
''
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Look for the given file in the directory containing the current file,
|
58
|
+
# and then in each of the directories specified in the RDOC_INCLUDE path
|
59
|
+
|
60
|
+
def find_include_file(name)
|
61
|
+
to_search = [ File.dirname(@input_file_name) ].concat @include_path
|
62
|
+
to_search.each do |dir|
|
63
|
+
full_name = File.join(dir, name)
|
64
|
+
stat = File.stat(full_name) rescue next
|
65
|
+
return full_name if stat.readable?
|
66
|
+
end
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
# Illustration of a script to convert an RDoc-style file to a LaTeX
|
3
|
+
# document
|
4
|
+
|
5
|
+
require 'rdoc-f95/markup/simple_markup'
|
6
|
+
require 'rdoc-f95/markup/simple_markup/to_latex'
|
7
|
+
|
8
|
+
p = SM::SimpleMarkup.new
|
9
|
+
h = SM::ToLaTeX.new
|
10
|
+
|
11
|
+
#puts "\\documentclass{report}"
|
12
|
+
#puts "\\usepackage{tabularx}"
|
13
|
+
#puts "\\usepackage{parskip}"
|
14
|
+
#puts "\\begin{document}"
|
15
|
+
puts p.convert(ARGF.read, h)
|
16
|
+
#puts "\\end{document}"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# This program illustrates the basic use of the SimpleMarkup
|
2
|
+
# class. It extracts the first comment block from the
|
3
|
+
# simple_markup.rb file and converts it into HTML on
|
4
|
+
# standard output. Run it using
|
5
|
+
#
|
6
|
+
# % ruby sample.rb
|
7
|
+
#
|
8
|
+
# You should be in the sample/ directory when you do this,
|
9
|
+
# as it hardwires the path to the files it needs to require.
|
10
|
+
# This isn't necessary in the code you write once you've
|
11
|
+
# installed the package.
|
12
|
+
#
|
13
|
+
# For a better way of formatting code comment blocks (and more)
|
14
|
+
# see the rdoc package.
|
15
|
+
#
|
16
|
+
|
17
|
+
$:.unshift "../../.."
|
18
|
+
|
19
|
+
require 'rdoc-f95/markup/simple_markup'
|
20
|
+
require 'rdoc-f95/markup/simple_markup/to_html'
|
21
|
+
|
22
|
+
# Extract the comment block from the source file
|
23
|
+
|
24
|
+
input_string = ""
|
25
|
+
|
26
|
+
File.foreach("../simple_markup.rb") do |line|
|
27
|
+
break unless line.gsub!(/^\# ?/, '')
|
28
|
+
input_string << line
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create a markup object
|
32
|
+
markup = SM::SimpleMarkup.new
|
33
|
+
|
34
|
+
# Attach it to an HTML formatter
|
35
|
+
h = SM::ToHtml.new
|
36
|
+
|
37
|
+
# And convert out comment block to html. Wrap it a body
|
38
|
+
# tag pair to let browsers view it
|
39
|
+
|
40
|
+
puts "<html><body>"
|
41
|
+
puts markup.convert(input_string, h)
|
42
|
+
puts "</body></html>"
|
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'rdoc-f95/markup/formatter'
|
2
|
+
require 'rdoc-f95/markup/fragments'
|
3
|
+
require 'rdoc-f95/markup/inline'
|
4
|
+
require 'cgi'
|
5
|
+
|
6
|
+
class RDocF95::Markup
|
7
|
+
|
8
|
+
module Flow
|
9
|
+
P = Struct.new(:body)
|
10
|
+
VERB = Struct.new(:body)
|
11
|
+
RULE = Struct.new(:width)
|
12
|
+
class LIST
|
13
|
+
attr_reader :type, :contents
|
14
|
+
def initialize(type)
|
15
|
+
@type = type
|
16
|
+
@contents = []
|
17
|
+
end
|
18
|
+
def <<(stuff)
|
19
|
+
@contents << stuff
|
20
|
+
end
|
21
|
+
end
|
22
|
+
LI = Struct.new(:label, :body)
|
23
|
+
H = Struct.new(:level, :text)
|
24
|
+
end
|
25
|
+
|
26
|
+
class ToFlow < RDocF95::Markup::Formatter
|
27
|
+
LIST_TYPE_TO_HTML = {
|
28
|
+
:BULLET => [ "<ul>", "</ul>" ],
|
29
|
+
:NUMBER => [ "<ol>", "</ol>" ],
|
30
|
+
:UPPERALPHA => [ "<ol>", "</ol>" ],
|
31
|
+
:LOWERALPHA => [ "<ol>", "</ol>" ],
|
32
|
+
:LABELED => [ "<dl>", "</dl>" ],
|
33
|
+
:NOTE => [ "<table>", "</table>" ],
|
34
|
+
}
|
35
|
+
|
36
|
+
InlineTag = Struct.new(:bit, :on, :off)
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
super
|
40
|
+
|
41
|
+
init_tags
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Set up the standard mapping of attributes to HTML tags
|
46
|
+
|
47
|
+
def init_tags
|
48
|
+
@attr_tags = [
|
49
|
+
InlineTag.new(RDocF95::Markup::Attribute.bitmap_for(:BOLD), "<b>", "</b>"),
|
50
|
+
InlineTag.new(RDocF95::Markup::Attribute.bitmap_for(:TT), "<tt>", "</tt>"),
|
51
|
+
InlineTag.new(RDocF95::Markup::Attribute.bitmap_for(:EM), "<em>", "</em>"),
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Add a new set of HTML tags for an attribute. We allow separate start and
|
57
|
+
# end tags for flexibility
|
58
|
+
|
59
|
+
def add_tag(name, start, stop)
|
60
|
+
@attr_tags << InlineTag.new(RDocF95::Markup::Attribute.bitmap_for(name), start, stop)
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Given an HTML tag, decorate it with class information and the like if
|
65
|
+
# required. This is a no-op in the base class, but is overridden in HTML
|
66
|
+
# output classes that implement style sheets
|
67
|
+
|
68
|
+
def annotate(tag)
|
69
|
+
tag
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Here's the client side of the visitor pattern
|
74
|
+
|
75
|
+
def start_accepting
|
76
|
+
@res = []
|
77
|
+
@list_stack = []
|
78
|
+
end
|
79
|
+
|
80
|
+
def end_accepting
|
81
|
+
@res
|
82
|
+
end
|
83
|
+
|
84
|
+
def accept_paragraph(am, fragment)
|
85
|
+
@res << Flow::P.new((convert_flow(am.flow(fragment.txt))))
|
86
|
+
end
|
87
|
+
|
88
|
+
def accept_verbatim(am, fragment)
|
89
|
+
@res << Flow::VERB.new((convert_flow(am.flow(fragment.txt))))
|
90
|
+
end
|
91
|
+
|
92
|
+
def accept_rule(am, fragment)
|
93
|
+
size = fragment.param
|
94
|
+
size = 10 if size > 10
|
95
|
+
@res << Flow::RULE.new(size)
|
96
|
+
end
|
97
|
+
|
98
|
+
def accept_list_start(am, fragment)
|
99
|
+
@list_stack.push(@res)
|
100
|
+
list = Flow::LIST.new(fragment.type)
|
101
|
+
@res << list
|
102
|
+
@res = list
|
103
|
+
end
|
104
|
+
|
105
|
+
def accept_list_end(am, fragment)
|
106
|
+
@res = @list_stack.pop
|
107
|
+
end
|
108
|
+
|
109
|
+
def accept_list_item(am, fragment)
|
110
|
+
@res << Flow::LI.new(fragment.param, convert_flow(am.flow(fragment.txt)))
|
111
|
+
end
|
112
|
+
|
113
|
+
def accept_blank_line(am, fragment)
|
114
|
+
# @res << annotate("<p />") << "\n"
|
115
|
+
end
|
116
|
+
|
117
|
+
def accept_heading(am, fragment)
|
118
|
+
@res << Flow::H.new(fragment.head_level, convert_flow(am.flow(fragment.txt)))
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
def on_tags(res, item)
|
124
|
+
attr_mask = item.turn_on
|
125
|
+
return if attr_mask.zero?
|
126
|
+
|
127
|
+
@attr_tags.each do |tag|
|
128
|
+
if attr_mask & tag.bit != 0
|
129
|
+
res << annotate(tag.on)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def off_tags(res, item)
|
135
|
+
attr_mask = item.turn_off
|
136
|
+
return if attr_mask.zero?
|
137
|
+
|
138
|
+
@attr_tags.reverse_each do |tag|
|
139
|
+
if attr_mask & tag.bit != 0
|
140
|
+
res << annotate(tag.off)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def convert_flow(flow)
|
146
|
+
res = ""
|
147
|
+
flow.each do |item|
|
148
|
+
case item
|
149
|
+
when String
|
150
|
+
res << convert_string(item)
|
151
|
+
when AttrChanger
|
152
|
+
off_tags(res, item)
|
153
|
+
on_tags(res, item)
|
154
|
+
when Special
|
155
|
+
res << convert_special(item)
|
156
|
+
else
|
157
|
+
raise "Unknown flow element: #{item.inspect}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
res
|
161
|
+
end
|
162
|
+
|
163
|
+
def convert_string(item)
|
164
|
+
CGI.escapeHTML(item)
|
165
|
+
end
|
166
|
+
|
167
|
+
def convert_special(special)
|
168
|
+
handled = false
|
169
|
+
Attribute.each_name_of(special.type) do |name|
|
170
|
+
method_name = "handle_special_#{name}"
|
171
|
+
if self.respond_to? method_name
|
172
|
+
special.text = send(method_name, special)
|
173
|
+
handled = true
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
raise "Unhandled special: #{special}" unless handled
|
178
|
+
|
179
|
+
special.text
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|