notroff 0.2.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/bin/notroff +47 -0
- data/lib/notroff/code_scrubber.rb +9 -0
- data/lib/notroff/code_typer.rb +37 -0
- data/lib/notroff/command_processor.rb +28 -0
- data/lib/notroff/composite_processor.rb +52 -0
- data/lib/notroff/content.xml.erb +110 -0
- data/lib/notroff/docbook_renderer.rb +155 -0
- data/lib/notroff/embedded.rb +132 -0
- data/lib/notroff/filter.rb +15 -0
- data/lib/notroff/formatter.rb +54 -0
- data/lib/notroff/html_renderer.rb +92 -0
- data/lib/notroff/io.rb +18 -0
- data/lib/notroff/logger.rb +13 -0
- data/lib/notroff/odt_renderer.rb +154 -0
- data/lib/notroff/odt_replacer.rb +22 -0
- data/lib/notroff/paragraph_joiner.rb +53 -0
- data/lib/notroff/processor.rb +192 -0
- data/lib/notroff/skel.odt +0 -0
- data/lib/notroff/string_extensions.rb +6 -0
- data/lib/notroff/template_expander.rb +15 -0
- data/lib/notroff/text.rb +67 -0
- data/lib/notroff/text_replacer.rb +65 -0
- data/lib/notroff/tokenize.rb +64 -0
- data/lib/notroff/type_assigner.rb +25 -0
- data/lib/notroff.rb +23 -0
- data/readme.nr +58 -0
- data/spec/command_processor_spec.rb +15 -0
- data/spec/composite_processor_spec.rb +35 -0
- data/spec/filter_spec.rb +16 -0
- data/spec/formatter_spec.rb +22 -0
- data/spec/hello.rb +1 -0
- data/spec/hello.rb.out +1 -0
- data/spec/paragraph_joiner_spec.rb +26 -0
- data/spec/simple.nr +3 -0
- data/spec/string_extensions_spec.rb +22 -0
- data/spec/text_spec.rb +55 -0
- data/spec/type_assigner_spec.rb +39 -0
- data/spec/with_commands.nr +6 -0
- metadata +83 -0
data/bin/notroff
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'pp'
|
3
|
+
require "notroff"
|
4
|
+
|
5
|
+
options={}
|
6
|
+
formatter_class = HtmlFormatter
|
7
|
+
|
8
|
+
while true
|
9
|
+
if ARGV.first == '-o'
|
10
|
+
formatter_class = OdtFormatter
|
11
|
+
ARGV.shift
|
12
|
+
elsif ARGV.first == '-d'
|
13
|
+
formatter_class = DocbookFormatter
|
14
|
+
ARGV.shift
|
15
|
+
elsif ARGV.first == '-v'
|
16
|
+
Logger.verbose = true
|
17
|
+
ARGV.shift
|
18
|
+
else
|
19
|
+
break
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
unless ARGV.size == 2
|
24
|
+
raise "Usage: notroff [-d] <nr file> <output file>"
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
f = formatter_class.new( ARGV[0], ARGV[1] )
|
29
|
+
f.process
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class CodeTypeRefiner
|
2
|
+
def process( paragraphs )
|
3
|
+
processed_paragraphs = []
|
4
|
+
|
5
|
+
previous_type = nil
|
6
|
+
|
7
|
+
paragraphs.each_with_index do |paragraph, i|
|
8
|
+
type = paragraph[:type]
|
9
|
+
previous_type = ( paragraphs.first == paragraph) ? nil : paragraphs[i-1][:type]
|
10
|
+
next_type = ( paragraphs.last == paragraph) ? nil : paragraphs[i+1][:type]
|
11
|
+
new_type = code_type_for( previous_type, type, next_type )
|
12
|
+
paragraph[:type] = new_type
|
13
|
+
processed_paragraphs << paragraph
|
14
|
+
end
|
15
|
+
processed_paragraphs
|
16
|
+
end
|
17
|
+
|
18
|
+
def code_type_for( previous_type, type, next_type )
|
19
|
+
if type != :code
|
20
|
+
new_type = type
|
21
|
+
|
22
|
+
elsif previous_type == :code and next_type == :code
|
23
|
+
new_type = :middle_code
|
24
|
+
|
25
|
+
elsif previous_type == :code
|
26
|
+
new_type = :end_code
|
27
|
+
|
28
|
+
elsif next_type == :code
|
29
|
+
new_type = :first_code
|
30
|
+
|
31
|
+
else
|
32
|
+
new_type = :single_code
|
33
|
+
end
|
34
|
+
|
35
|
+
new_type
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class CommandProcessor
|
2
|
+
def process( lines )
|
3
|
+
paragraphs = []
|
4
|
+
lines.each do |line|
|
5
|
+
cmd, text = parse_line( line )
|
6
|
+
if cmd.empty?
|
7
|
+
cmd = :text
|
8
|
+
else
|
9
|
+
cmd = cmd.sub(/^./, '').to_sym
|
10
|
+
end
|
11
|
+
para = Text.new(text, :type => cmd, :original_text => line.to_s)
|
12
|
+
paragraphs << para
|
13
|
+
end
|
14
|
+
paragraphs
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_line( line )
|
18
|
+
match_data = /^(\.\w+ ?)(.*)/.match(line)
|
19
|
+
if match_data
|
20
|
+
cmd = match_data[1].strip
|
21
|
+
text = match_data[2]
|
22
|
+
else
|
23
|
+
cmd = ''
|
24
|
+
text = line
|
25
|
+
end
|
26
|
+
[ cmd.strip, text ]
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class CompositeProcessor
|
2
|
+
def initialize(*args)
|
3
|
+
@processors = args
|
4
|
+
end
|
5
|
+
|
6
|
+
def add_processor(p)
|
7
|
+
@processors << p
|
8
|
+
end
|
9
|
+
|
10
|
+
def prepend_processor(p)
|
11
|
+
@processors = [p] + @processors
|
12
|
+
end
|
13
|
+
|
14
|
+
def process(paras=[])
|
15
|
+
@processors.each do |processor|
|
16
|
+
Logger.log "Applying processor #{processor.class} to #{paras.size} paragraphs"
|
17
|
+
dump(paras)
|
18
|
+
Logger.log
|
19
|
+
paras = processor.process( paras )
|
20
|
+
Logger.log "After processor #{processor.class}"
|
21
|
+
Logger.log
|
22
|
+
end
|
23
|
+
paras
|
24
|
+
end
|
25
|
+
|
26
|
+
def dump(data)
|
27
|
+
return unless Verbose
|
28
|
+
Logger.log "======="
|
29
|
+
if data.nil?
|
30
|
+
Logger.log "data: nil"
|
31
|
+
elsif data.kind_of?(Array)
|
32
|
+
Logger.log "data with #{data.size} items:"
|
33
|
+
data.each_with_index {|item, i| Logger.log "[#{i}] - #{item.inspect}" }
|
34
|
+
else
|
35
|
+
Logger.log data
|
36
|
+
end
|
37
|
+
Logger.log "======="
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
3
|
+
xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
4
|
+
xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
|
5
|
+
xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
|
6
|
+
xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
|
7
|
+
xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
|
8
|
+
xmlns:xlink="http://www.w3.org/1999/xlink"
|
9
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
10
|
+
xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
|
11
|
+
xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
|
12
|
+
xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
|
13
|
+
xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
|
14
|
+
xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
|
15
|
+
xmlns:math="http://www.w3.org/1998/Math/MathML"
|
16
|
+
xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
|
17
|
+
xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"
|
18
|
+
xmlns:ooo="http://openoffice.org/2004/office"
|
19
|
+
xmlns:ooow="http://openoffice.org/2004/writer"
|
20
|
+
xmlns:oooc="http://openoffice.org/2004/calc"
|
21
|
+
xmlns:dom="http://www.w3.org/2001/xml-events"
|
22
|
+
xmlns:xforms="http://www.w3.org/2002/xforms"
|
23
|
+
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
24
|
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
25
|
+
xmlns:field="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:field:1.0"
|
26
|
+
office:version="1.1">
|
27
|
+
<office:scripts />
|
28
|
+
<office:font-face-decls>
|
29
|
+
<style:font-face style:name="Wingdings"
|
30
|
+
svg:font-family="Wingdings" style:font-pitch="variable"
|
31
|
+
style:font-charset="x-symbol" />
|
32
|
+
<style:font-face style:name="Symbol" svg:font-family="Symbol"
|
33
|
+
style:font-family-generic="roman" style:font-pitch="variable"
|
34
|
+
style:font-charset="x-symbol" />
|
35
|
+
<style:font-face style:name="Courier New"
|
36
|
+
svg:font-family="'Courier New'"
|
37
|
+
style:font-family-generic="modern" />
|
38
|
+
<style:font-face style:name="Courier"
|
39
|
+
svg:font-family="Courier, 'Courier New'"
|
40
|
+
style:font-family-generic="modern" />
|
41
|
+
<style:font-face style:name="Nimbus Mono L"
|
42
|
+
svg:font-family="'Nimbus Mono L', 'Courier New'"
|
43
|
+
style:font-family-generic="modern" />
|
44
|
+
<style:font-face style:name="Nimbus Roman No9 L"
|
45
|
+
svg:font-family="'Nimbus Roman No9 L'"
|
46
|
+
style:font-family-generic="roman"
|
47
|
+
style:font-pitch="variable" />
|
48
|
+
<style:font-face style:name="Times" svg:font-family="Times"
|
49
|
+
style:font-family-generic="roman"
|
50
|
+
style:font-pitch="variable" />
|
51
|
+
<style:font-face style:name="Times New Roman"
|
52
|
+
svg:font-family="'Times New Roman'"
|
53
|
+
style:font-family-generic="roman"
|
54
|
+
style:font-pitch="variable" />
|
55
|
+
<style:font-face style:name="Arial" svg:font-family="Arial"
|
56
|
+
style:font-family-generic="swiss"
|
57
|
+
style:font-pitch="variable" />
|
58
|
+
<style:font-face style:name="Arial Unicode MS"
|
59
|
+
svg:font-family="'Arial Unicode MS'"
|
60
|
+
style:font-family-generic="swiss"
|
61
|
+
style:font-pitch="variable" />
|
62
|
+
<style:font-face style:name="Helvetica"
|
63
|
+
svg:font-family="Helvetica" style:font-family-generic="swiss"
|
64
|
+
style:font-pitch="variable" />
|
65
|
+
<style:font-face style:name="Tahoma" svg:font-family="Tahoma"
|
66
|
+
style:font-family-generic="swiss"
|
67
|
+
style:font-pitch="variable" />
|
68
|
+
<style:font-face style:name="Verdana" svg:font-family="Verdana"
|
69
|
+
style:font-family-generic="swiss"
|
70
|
+
style:font-pitch="variable" />
|
71
|
+
<style:font-face style:name="DejaVu Sans"
|
72
|
+
svg:font-family="'DejaVu Sans'"
|
73
|
+
style:font-family-generic="system"
|
74
|
+
style:font-pitch="variable" />
|
75
|
+
</office:font-face-decls>
|
76
|
+
<office:automatic-styles>
|
77
|
+
<style:style style:name="P1" style:family="paragraph"
|
78
|
+
style:parent-style-name="Standard">
|
79
|
+
<style:paragraph-properties fo:text-align="end"
|
80
|
+
style:justify-single-word="false" />
|
81
|
+
</style:style>
|
82
|
+
<style:style style:name="P2" style:family="paragraph"
|
83
|
+
style:parent-style-name="HA" style:master-page-name="Standard">
|
84
|
+
<style:paragraph-properties style:page-number="1" />
|
85
|
+
</style:style>
|
86
|
+
<style:style style:name="P3" style:family="paragraph"
|
87
|
+
style:parent-style-name="FTN">
|
88
|
+
<style:paragraph-properties fo:margin-left="0.1598in"
|
89
|
+
fo:margin-right="0in" fo:margin-top="0.0417in"
|
90
|
+
fo:margin-bottom="0.0417in"
|
91
|
+
style:line-height-at-least="0.1807in"
|
92
|
+
fo:text-indent="-0.1598in" style:auto-text-indent="false" />
|
93
|
+
</style:style>
|
94
|
+
<style:style style:name="T1" style:family="text">
|
95
|
+
<style:text-properties fo:font-style="italic"
|
96
|
+
style:font-style-asian="italic"
|
97
|
+
style:font-style-complex="italic" />
|
98
|
+
</style:style>
|
99
|
+
<style:style style:name="T2" style:family="text">
|
100
|
+
<style:text-properties fo:font-weight="bold"
|
101
|
+
style:font-weight-asian="bold"
|
102
|
+
style:font-weight-complex="bold" />
|
103
|
+
</style:style>
|
104
|
+
</office:automatic-styles>
|
105
|
+
<office:body>
|
106
|
+
<office:text>
|
107
|
+
<%=content%>
|
108
|
+
</office:text>
|
109
|
+
</office:body>
|
110
|
+
</office:document-content>
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
class DocbookRenderer < Processor
|
5
|
+
include Tokenize
|
6
|
+
include REXML
|
7
|
+
|
8
|
+
def process( paragraphs )
|
9
|
+
@author = 'John Smith'
|
10
|
+
@title = 'Wealth of Nations'
|
11
|
+
@chapters = []
|
12
|
+
@chapter = nil
|
13
|
+
@section = nil
|
14
|
+
|
15
|
+
paragraphs.each do |paragraph|
|
16
|
+
format( paragraph )
|
17
|
+
end
|
18
|
+
@book = Element.new('book')
|
19
|
+
@book.add_namespace('http://docbook.org/ns/docbook')
|
20
|
+
@book.add_attribute('version', '5.0')
|
21
|
+
@book.add_element element_for('title', @title)
|
22
|
+
@book.add_element element_for('author', @author)
|
23
|
+
@chapters.each {|ch| @book << ch}
|
24
|
+
doc = Document.new
|
25
|
+
decl = XMLDecl.new
|
26
|
+
decl.version = '1.0'
|
27
|
+
doc << decl
|
28
|
+
doc << @book
|
29
|
+
doc
|
30
|
+
end
|
31
|
+
|
32
|
+
def element_for(type, text)
|
33
|
+
result = Element.new(type)
|
34
|
+
result.add_text(text)
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
def format( p )
|
39
|
+
type = p[:type]
|
40
|
+
text = p.string
|
41
|
+
|
42
|
+
return nil if text.empty? and :type != :code
|
43
|
+
|
44
|
+
case type
|
45
|
+
when :title
|
46
|
+
@title = text
|
47
|
+
when :author
|
48
|
+
@author = text
|
49
|
+
when :chapter
|
50
|
+
Logger.log "adding chapter #{text}"
|
51
|
+
@chapter = Element.new('chapter')
|
52
|
+
@chapters << @chapter
|
53
|
+
@section = nil
|
54
|
+
title_element = Element.new('title')
|
55
|
+
add_body_text(title_element, text)
|
56
|
+
@chapter.add_element(title_element)
|
57
|
+
when :section
|
58
|
+
Logger.log "adding section #{text}"
|
59
|
+
@section = Element.new('section')
|
60
|
+
@chapter.add(@section)
|
61
|
+
title_element = Element.new('title')
|
62
|
+
add_body_text(title_element, text)
|
63
|
+
@section.add_element(title_element)
|
64
|
+
when :body
|
65
|
+
Logger.log "adding body #{text[0..5]}"
|
66
|
+
paragraph = Element.new('para')
|
67
|
+
add_body_text(paragraph, text)
|
68
|
+
add_content_element(paragraph)
|
69
|
+
when :code
|
70
|
+
add_content_element(code_element(type, text))
|
71
|
+
else
|
72
|
+
raise "#{type}???"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_content_element(el)
|
77
|
+
if @section
|
78
|
+
@section.add_element(el)
|
79
|
+
elsif @chapter
|
80
|
+
@chapter.add_element(el)
|
81
|
+
else
|
82
|
+
raise "No chapter to add #{el} to"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def text_element(type, text)
|
87
|
+
element = [ tag_for(type) ]
|
88
|
+
add_body_text(element, text)
|
89
|
+
element
|
90
|
+
end
|
91
|
+
|
92
|
+
def tag_for(type)
|
93
|
+
case type
|
94
|
+
when :body
|
95
|
+
'para'
|
96
|
+
when :text
|
97
|
+
'p'
|
98
|
+
when :author
|
99
|
+
'h3'
|
100
|
+
when :section
|
101
|
+
'h3'
|
102
|
+
when :chapter
|
103
|
+
'chapter'
|
104
|
+
when :sec
|
105
|
+
'h3'
|
106
|
+
when :title
|
107
|
+
'h2'
|
108
|
+
else
|
109
|
+
raise "Dont know what to do with #{type}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def add_body_text( element, text )
|
114
|
+
tokens = tokenize_body_text( text )
|
115
|
+
tokens.each {|token| add_span( token, element ) }
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_span( token, element )
|
119
|
+
Logger.log "Add span: token: #{token} element: #{element}"
|
120
|
+
case token[:type]
|
121
|
+
when :italic
|
122
|
+
element.add( span_for( token.string, "emphasis" ))
|
123
|
+
when :code
|
124
|
+
element.add( span_for( token.string, "code" ))
|
125
|
+
when :bold
|
126
|
+
element.add( span_for( token.string, "emphasis" ))
|
127
|
+
when :normal
|
128
|
+
element.add_text( token.string )
|
129
|
+
when :footnote
|
130
|
+
element.add(footnote_for(token.string))
|
131
|
+
else
|
132
|
+
raise "Dont know what to do with #{token}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def footnote_for( text )
|
137
|
+
fn = Element.new('footnote')
|
138
|
+
fn.add_element(element_for('para', text))
|
139
|
+
fn
|
140
|
+
end
|
141
|
+
|
142
|
+
def code_element(type, text)
|
143
|
+
element = Element.new('informalexample')
|
144
|
+
prog_element = element_for('programlisting', text)
|
145
|
+
prog_element.add_attribute('xml:space', 'preserve')
|
146
|
+
element.add_element(prog_element)
|
147
|
+
element
|
148
|
+
end
|
149
|
+
|
150
|
+
def span_for( text, style )
|
151
|
+
span = Element.new(style)
|
152
|
+
span.text = remove_escapes(text)
|
153
|
+
span
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
class BetweenFilter
|
2
|
+
def initialize(re1, re2=re1)
|
3
|
+
@re1 = re1
|
4
|
+
@re2 = re2
|
5
|
+
end
|
6
|
+
|
7
|
+
def process(paras)
|
8
|
+
state = :before_first
|
9
|
+
paras.each do |para|
|
10
|
+
if state == :before_first and @re1 =~ para
|
11
|
+
para[:included] = true
|
12
|
+
state = :after_first
|
13
|
+
break if para =~ @re2
|
14
|
+
elsif state == :after_first
|
15
|
+
para[:included] = true
|
16
|
+
break if para =~ @re2
|
17
|
+
end
|
18
|
+
end
|
19
|
+
paras
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class DefinitionFilter
|
24
|
+
def initialize(def_re, include_body=true)
|
25
|
+
@def_re = def_re
|
26
|
+
@include_body = include_body
|
27
|
+
end
|
28
|
+
|
29
|
+
def process(paras)
|
30
|
+
state = :before_def
|
31
|
+
end_re = nil
|
32
|
+
paras.each do |para|
|
33
|
+
Logger.log para, (@def_re =~ para)
|
34
|
+
if state == :before_def and @def_re =~ para
|
35
|
+
para[:included] = true
|
36
|
+
end_re = Regexp.new( "^#{' ' * para.string.indent_depth}end" )
|
37
|
+
state = :after_def
|
38
|
+
elsif state == :after_def and end_re =~ para.string
|
39
|
+
para[:included] = true
|
40
|
+
break
|
41
|
+
elsif state == :after_def and @include_body
|
42
|
+
para[:included] = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
paras
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class MethodFilter < DefinitionFilter
|
50
|
+
def initialize(method_name, include_body)
|
51
|
+
super /^ *def +#{method_name}(\(|$| )/, include_body
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class ClassFilter < DefinitionFilter
|
56
|
+
def initialize(class_name, include_body)
|
57
|
+
super /^ *class +#{class_name}(\(|$| )/, include_body
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class ModuleFilter < DefinitionFilter
|
62
|
+
def initialize(module_name, include_body)
|
63
|
+
super /^ *module +#{module_name}(\(|$| )/, include_body
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class EmbeddedRubyProcessor
|
68
|
+
def process(paragraphs)
|
69
|
+
new_paragraphs = []
|
70
|
+
paragraphs.each do |p|
|
71
|
+
if p[:type] == :x
|
72
|
+
Logger.log p
|
73
|
+
results = process_command(p.string)
|
74
|
+
new_paragraphs << results if results
|
75
|
+
else
|
76
|
+
new_paragraphs << p
|
77
|
+
end
|
78
|
+
end
|
79
|
+
new_paragraphs.flatten
|
80
|
+
end
|
81
|
+
|
82
|
+
def process_command(ruby_expression)
|
83
|
+
Logger.log "Ruby expression: #{ruby_expression}"
|
84
|
+
lines = eval(ruby_expression, binding)
|
85
|
+
end
|
86
|
+
|
87
|
+
def embed(*filters, &block)
|
88
|
+
paras = block.call.map {|line| line.rstrip}
|
89
|
+
paras.map! {|p| Text.new(p, :type => :code)}
|
90
|
+
Logger.log "EMBED: #{paras}"
|
91
|
+
unless filters.empty?
|
92
|
+
filters.each {|f| paras = f.process(paras)}
|
93
|
+
paras = paras.find_all {|p| p[:included]}
|
94
|
+
end
|
95
|
+
paras
|
96
|
+
end
|
97
|
+
|
98
|
+
def inc(path, *filters)
|
99
|
+
embed(*filters) {File.readlines(path)}
|
100
|
+
end
|
101
|
+
|
102
|
+
def run(command, *filters)
|
103
|
+
embed(*filters) {File.popen(command).readlines}
|
104
|
+
end
|
105
|
+
|
106
|
+
def matches(re1, re2=re1)
|
107
|
+
BetweenFilter.new(re1, re2)
|
108
|
+
end
|
109
|
+
|
110
|
+
def method(name, include_body=true)
|
111
|
+
MethodFilter.new(name, include_body)
|
112
|
+
end
|
113
|
+
|
114
|
+
def clazz(name, include_body=true)
|
115
|
+
ClassFilter.new(name, include_body)
|
116
|
+
end
|
117
|
+
|
118
|
+
def mod(name, include_body=true)
|
119
|
+
ModuleFilter.new(name, include_body)
|
120
|
+
end
|
121
|
+
|
122
|
+
def indent(delta_indent, paragraphs)
|
123
|
+
paragraphs.map do |p|
|
124
|
+
if delta_indent > 0
|
125
|
+
p.string = (" " * delta_indent) + p.string
|
126
|
+
elsif delta_indent < 0
|
127
|
+
p.string.sub!( ' ' * delta_indent.abs, '' )
|
128
|
+
end
|
129
|
+
end
|
130
|
+
paragraphs
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class Formatter < CompositeProcessor
|
2
|
+
def initialize()
|
3
|
+
super
|
4
|
+
add_processor CommandProcessor.new
|
5
|
+
add_processor TypeAssigner.new
|
6
|
+
add_processor EmbeddedRubyProcessor.new
|
7
|
+
add_processor CodeScrubber.new
|
8
|
+
add_processor BodyParagraphJoiner.new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class HtmlFormatter < Formatter
|
13
|
+
def initialize(input, output)
|
14
|
+
super()
|
15
|
+
prepend_processor FileReader.new(input)
|
16
|
+
add_processor CodeParagraphJoiner.new
|
17
|
+
add_processor HtmlRenderer.new
|
18
|
+
add_processor FileWriter.new(output)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class DocbookFormatter < Formatter
|
23
|
+
def initialize(input, output)
|
24
|
+
super()
|
25
|
+
prepend_processor FileReader.new(input)
|
26
|
+
add_processor CodeParagraphJoiner.new
|
27
|
+
add_processor DocbookRenderer.new
|
28
|
+
add_processor FileWriter.new(output)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class OdtFormatter < Formatter
|
33
|
+
def initialize(input, output)
|
34
|
+
super()
|
35
|
+
prepend_processor FileReader.new(input)
|
36
|
+
add_processor CodeTypeRefiner.new
|
37
|
+
add_processor OdtRenderer.new
|
38
|
+
add_processor TemplateExpander.new
|
39
|
+
add_processor OdtReplacer.new(output)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|