ronn 0.6.6 → 0.7.0
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/CHANGES +34 -0
- data/INSTALLING +18 -0
- data/README.md +43 -69
- data/Rakefile +9 -10
- data/bin/ronn +66 -49
- data/config.ru +1 -1
- data/lib/ronn.rb +35 -9
- data/lib/ronn/document.rb +239 -135
- data/lib/ronn/index.rb +183 -0
- data/lib/ronn/roff.rb +48 -28
- data/lib/ronn/template.rb +22 -8
- data/lib/ronn/template/dark.css +1 -4
- data/lib/ronn/template/default.html +0 -2
- data/lib/ronn/template/man.css +12 -12
- data/lib/ronn/utils.rb +8 -0
- data/man/index.html +78 -0
- data/man/index.txt +15 -0
- data/man/{ronn.5 → ronn-format.7} +26 -30
- data/man/{ronn.5.ronn → ronn-format.7.ronn} +39 -39
- data/man/ronn.1 +47 -15
- data/man/ronn.1.ronn +53 -23
- data/ronn.gemspec +14 -8
- data/test/angle_bracket_syntax.html +4 -2
- data/test/basic_document.html +4 -2
- data/test/custom_title_document.html +1 -2
- data/test/definition_list_syntax.html +4 -2
- data/test/dots_at_line_start_test.roff +10 -0
- data/test/dots_at_line_start_test.ronn +4 -0
- data/test/entity_encoding_test.html +24 -2
- data/test/entity_encoding_test.roff +41 -1
- data/test/entity_encoding_test.ronn +17 -0
- data/test/index.txt +8 -0
- data/test/markdown_syntax.html +5 -3
- data/test/markdown_syntax.roff +4 -4
- data/test/middle_paragraph.html +4 -2
- data/test/missing_spaces.roff +3 -0
- data/test/section_reference_links.html +4 -2
- data/test/{ronn_test.rb → test_ronn.rb} +18 -5
- data/test/{document_test.rb → test_ronn_document.rb} +59 -8
- data/test/test_ronn_index.rb +73 -0
- data/test/titleless_document.html +7 -2
- data/test/titleless_document.ronn +3 -2
- data/test/underline_spacing_test.roff +5 -0
- metadata +30 -14
- data/man/ronn.7 +0 -168
- data/man/ronn.7.ronn +0 -120
data/lib/ronn/index.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'ronn'
|
2
|
+
|
3
|
+
module Ronn
|
4
|
+
|
5
|
+
# Maintains a list of links / references to manuals and other resources.
|
6
|
+
class Index
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
attr_reader :path
|
10
|
+
attr_reader :references
|
11
|
+
|
12
|
+
# Retrieve an Index for <path>, where <path> is a directory or normal
|
13
|
+
# file. The index is loaded from the corresponding index.txt file if
|
14
|
+
# one exists.
|
15
|
+
def self.[](path)
|
16
|
+
(@indexes ||= {})[index_path_for_file(path)] ||=
|
17
|
+
Index.new(index_path_for_file(path))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.index_path_for_file(file)
|
21
|
+
File.expand_path(
|
22
|
+
if File.directory?(file)
|
23
|
+
File.join(file, 'index.txt')
|
24
|
+
else
|
25
|
+
File.join(File.dirname(file), 'index.txt')
|
26
|
+
end
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(path, &bk)
|
31
|
+
@path = path
|
32
|
+
@references = []
|
33
|
+
@manuals = {}
|
34
|
+
|
35
|
+
if block_given?
|
36
|
+
read! yield
|
37
|
+
elsif exist?
|
38
|
+
read! File.read(path)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Determine whether the index file exists.
|
43
|
+
def exist?
|
44
|
+
File.exist?(path)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Load index data from a string.
|
48
|
+
def read!(data)
|
49
|
+
data.each_line do |line|
|
50
|
+
line = line.strip.gsub(/\s*#.*$/, '')
|
51
|
+
if !line.empty?
|
52
|
+
name, url = line.split(/ +/, 2)
|
53
|
+
@references << reference(name, url)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Enumerable and friends
|
60
|
+
|
61
|
+
def each(&bk)
|
62
|
+
references.each(&bk)
|
63
|
+
end
|
64
|
+
|
65
|
+
def size
|
66
|
+
references.size
|
67
|
+
end
|
68
|
+
|
69
|
+
def first
|
70
|
+
references.first
|
71
|
+
end
|
72
|
+
|
73
|
+
def last
|
74
|
+
references.last
|
75
|
+
end
|
76
|
+
|
77
|
+
def empty?
|
78
|
+
references.empty?
|
79
|
+
end
|
80
|
+
|
81
|
+
def [](name)
|
82
|
+
references.find { |ref| ref.name == name }
|
83
|
+
end
|
84
|
+
|
85
|
+
def reference(name, path)
|
86
|
+
Reference.new(self, name, path)
|
87
|
+
end
|
88
|
+
|
89
|
+
def <<(path)
|
90
|
+
raise ArgumentError, "local paths only" if path =~ /(https?|mailto):/
|
91
|
+
return self if any? { |ref| ref.path == File.expand_path(path) }
|
92
|
+
relative_path = relative_to_index(path)
|
93
|
+
@references << \
|
94
|
+
if path =~ /\.ronn?$/
|
95
|
+
reference manual(path).reference_name, relative_path
|
96
|
+
else
|
97
|
+
reference File.basename(path), relative_path
|
98
|
+
end
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def add_manual(manual)
|
103
|
+
@manuals[File.expand_path(manual.path)] = manual
|
104
|
+
self << manual.path
|
105
|
+
end
|
106
|
+
|
107
|
+
def manual(path)
|
108
|
+
@manuals[File.expand_path(path)] ||= Document.new(path)
|
109
|
+
end
|
110
|
+
|
111
|
+
def manuals
|
112
|
+
select { |ref| ref.relative? && ref.ronn? }.
|
113
|
+
map { |ref| manual(ref.path) }
|
114
|
+
end
|
115
|
+
|
116
|
+
##
|
117
|
+
# Converting
|
118
|
+
|
119
|
+
def to_text
|
120
|
+
map { |ref| [ref.name, ref.location].join(' ') }.join("\n")
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_a
|
124
|
+
references
|
125
|
+
end
|
126
|
+
|
127
|
+
def to_h
|
128
|
+
to_a.map { |doc| doc.to_hash }
|
129
|
+
end
|
130
|
+
|
131
|
+
def relative_to_index(path)
|
132
|
+
path = File.expand_path(path)
|
133
|
+
index_dir = File.dirname(File.expand_path(self.path))
|
134
|
+
path.sub(/^#{index_dir}\//, '')
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# An individual index reference. A reference can point to one of a few types
|
139
|
+
# of locations:
|
140
|
+
#
|
141
|
+
# - URLs: "http://man.cx/crontab(5)"
|
142
|
+
# - Relative paths to ronn manuals: "crontab.5.ronn"
|
143
|
+
#
|
144
|
+
# The #url method should be used to obtain the href value for HTML.
|
145
|
+
class Reference
|
146
|
+
attr_reader :name
|
147
|
+
attr_reader :location
|
148
|
+
|
149
|
+
def initialize(index, name, location)
|
150
|
+
@index = index
|
151
|
+
@name = name
|
152
|
+
@location = location
|
153
|
+
end
|
154
|
+
|
155
|
+
def manual?
|
156
|
+
name =~ /\([0-9]\w*\)$/
|
157
|
+
end
|
158
|
+
|
159
|
+
def ronn?
|
160
|
+
location =~ /\.ronn?$/
|
161
|
+
end
|
162
|
+
|
163
|
+
def remote?
|
164
|
+
location =~ /^(?:https?|mailto):/
|
165
|
+
end
|
166
|
+
|
167
|
+
def relative?
|
168
|
+
!remote?
|
169
|
+
end
|
170
|
+
|
171
|
+
def url
|
172
|
+
if remote?
|
173
|
+
location
|
174
|
+
else
|
175
|
+
location.chomp('.ronn') + '.html'
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def path
|
180
|
+
File.expand_path(location, File.dirname(@index.path)) if relative?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
data/lib/ronn/roff.rb
CHANGED
@@ -29,20 +29,9 @@ module Ronn
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def child_of?(node, tag)
|
33
|
-
while node
|
34
|
-
if node.name && node.name.downcase == tag
|
35
|
-
return true
|
36
|
-
else
|
37
|
-
node = node.parent
|
38
|
-
end
|
39
|
-
end
|
40
|
-
false
|
41
|
-
end
|
42
|
-
|
43
32
|
def title_heading(name, section, tagline, manual, version, date)
|
44
|
-
comment "generated with Ronn/v#{Ronn
|
45
|
-
comment "http://github.com/rtomayko/ronn/"
|
33
|
+
comment "generated with Ronn/v#{Ronn.version}"
|
34
|
+
comment "http://github.com/rtomayko/ronn/tree/#{Ronn.revision}"
|
46
35
|
return if name.nil?
|
47
36
|
macro "TH", %["#{escape(name.upcase)}" "#{section}" "#{date.strftime('%B %Y')}" "#{version}" "#{manual}"]
|
48
37
|
end
|
@@ -50,7 +39,6 @@ module Ronn
|
|
50
39
|
def remove_extraneous_elements!(doc)
|
51
40
|
doc.traverse_all_element do |node|
|
52
41
|
if node.comment? || node.procins? || node.doctype? || node.xmldecl?
|
53
|
-
warn 'removing: %p' % [node]
|
54
42
|
node.parent.children.delete(node)
|
55
43
|
end
|
56
44
|
end
|
@@ -85,7 +73,7 @@ module Ronn
|
|
85
73
|
when node.doc?
|
86
74
|
normalize_whitespace! node.children
|
87
75
|
else
|
88
|
-
warn "unexpected node during whitespace normalization: %p", node
|
76
|
+
warn "unexpected node during whitespace normalization: %p", node
|
89
77
|
end
|
90
78
|
end
|
91
79
|
|
@@ -101,6 +89,10 @@ module Ronn
|
|
101
89
|
|
102
90
|
elsif node.elem?
|
103
91
|
case node.name
|
92
|
+
when 'div'
|
93
|
+
block_filter(node.children)
|
94
|
+
when 'h1'
|
95
|
+
# discard
|
104
96
|
when 'h2'
|
105
97
|
macro "SH", quote(escape(node.html))
|
106
98
|
when 'h3'
|
@@ -134,7 +126,7 @@ module Ronn
|
|
134
126
|
inline_filter(node.children)
|
135
127
|
write "\n"
|
136
128
|
when 'dd'
|
137
|
-
if node.
|
129
|
+
if node.at('p')
|
138
130
|
block_filter(node.children)
|
139
131
|
else
|
140
132
|
inline_filter(node.children)
|
@@ -151,7 +143,7 @@ module Ronn
|
|
151
143
|
when 'ul'
|
152
144
|
macro "IP", %w["\(bu" 4]
|
153
145
|
end
|
154
|
-
if node.
|
146
|
+
if node.at('p|ol|ul|dl|div')
|
155
147
|
block_filter(node.children)
|
156
148
|
else
|
157
149
|
inline_filter(node.children)
|
@@ -174,12 +166,13 @@ module Ronn
|
|
174
166
|
node.each { |ch| inline_filter(ch) }
|
175
167
|
|
176
168
|
elsif node.text?
|
177
|
-
prev = previous(node)
|
178
169
|
text = node.to_html.dup
|
179
170
|
write escape(text)
|
180
171
|
|
181
172
|
elsif node.elem?
|
182
173
|
case node.name
|
174
|
+
when 'span'
|
175
|
+
inline_filter(node.children)
|
183
176
|
when 'code'
|
184
177
|
if child_of?(node, 'pre')
|
185
178
|
inline_filter(node.children)
|
@@ -201,8 +194,11 @@ module Ronn
|
|
201
194
|
|
202
195
|
when 'br'
|
203
196
|
macro 'br'
|
197
|
+
|
204
198
|
when 'a'
|
205
|
-
if node.
|
199
|
+
if node.classes.include?('man-ref')
|
200
|
+
inline_filter(node.children)
|
201
|
+
elsif node.has_attribute?('data-bare-link')
|
206
202
|
write '\fI'
|
207
203
|
inline_filter(node.children)
|
208
204
|
write '\fR'
|
@@ -226,15 +222,33 @@ module Ronn
|
|
226
222
|
writeln ".\n.#{[name, value].compact.join(' ')}"
|
227
223
|
end
|
228
224
|
|
225
|
+
HTML_ROFF_ENTITIES = {
|
226
|
+
'•' => '\(bu',
|
227
|
+
'<' => '<',
|
228
|
+
'>' => '>',
|
229
|
+
' ' => '\~',
|
230
|
+
'©' => '\(co',
|
231
|
+
'”' => '\(rs',
|
232
|
+
'—' => '\(em',
|
233
|
+
'®' => '\(rg',
|
234
|
+
'&sec;' => '\(sc',
|
235
|
+
'≥' => '\(>=',
|
236
|
+
'≤' => '\(<=',
|
237
|
+
'≠' => '\(!=',
|
238
|
+
'≡' => '\(=='
|
239
|
+
}
|
240
|
+
|
229
241
|
def escape(text)
|
230
|
-
text.
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
242
|
+
return text.to_s if text.nil? || text.empty?
|
243
|
+
ent = HTML_ROFF_ENTITIES
|
244
|
+
text = text.dup
|
245
|
+
text.gsub!(/&#x([0-9A-Fa-f]+);/) { $1.to_i(16).chr } # hex entities
|
246
|
+
text.gsub!(/&#(\d+);/) { $1.to_i.chr } # dec entities
|
247
|
+
text.gsub!('\\', '\e') # backslash
|
248
|
+
text.gsub!(/['".-]/) { |m| "\\#{m}" } # control chars
|
249
|
+
text.gsub!(/(&[A-Za-z]+;)/) { ent[$1] || $1 } # named entities
|
250
|
+
text.gsub!('&', '&') # amps
|
251
|
+
text
|
238
252
|
end
|
239
253
|
|
240
254
|
def quote(text)
|
@@ -243,7 +257,13 @@ module Ronn
|
|
243
257
|
|
244
258
|
# write text to output buffer
|
245
259
|
def write(text)
|
246
|
-
|
260
|
+
return if text.nil? || text.empty?
|
261
|
+
# lines cannot start with a '.'. insert zero-width character before.
|
262
|
+
if text[0,2] == '\.' &&
|
263
|
+
(@buf.last && @buf.last[-1] == ?\n)
|
264
|
+
@buf << '\&'
|
265
|
+
end
|
266
|
+
@buf << text
|
247
267
|
end
|
248
268
|
|
249
269
|
# write text to output buffer on a new line.
|
data/lib/ronn/template.rb
CHANGED
@@ -28,9 +28,22 @@ module Ronn
|
|
28
28
|
def tagline
|
29
29
|
@document.tagline
|
30
30
|
end
|
31
|
+
alias tagline? tagline
|
32
|
+
|
33
|
+
def name_and_section?
|
34
|
+
name && section
|
35
|
+
end
|
31
36
|
|
32
37
|
def title
|
33
|
-
|
38
|
+
if !name_and_section? && tagline
|
39
|
+
tagline
|
40
|
+
else
|
41
|
+
[page_name, tagline].compact.join(' - ')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def custom_title?
|
46
|
+
!name_and_section? && tagline
|
34
47
|
end
|
35
48
|
|
36
49
|
def page_name
|
@@ -42,7 +55,7 @@ module Ronn
|
|
42
55
|
end
|
43
56
|
|
44
57
|
def generator
|
45
|
-
"Ronn/v#{Ronn
|
58
|
+
"Ronn/v#{Ronn.version} (http://github.com/rtomayko/ronn/tree/#{Ronn.revision})"
|
46
59
|
end
|
47
60
|
|
48
61
|
def manual
|
@@ -57,8 +70,8 @@ module Ronn
|
|
57
70
|
@document.date.strftime('%B %Y')
|
58
71
|
end
|
59
72
|
|
60
|
-
def
|
61
|
-
|
73
|
+
def wrap_class_name
|
74
|
+
'mp'
|
62
75
|
end
|
63
76
|
|
64
77
|
##
|
@@ -130,12 +143,13 @@ module Ronn
|
|
130
143
|
|
131
144
|
def inline_stylesheet(path, media='all')
|
132
145
|
data = File.read(path)
|
133
|
-
data.gsub!(/([;{]) *\n/m, '\1') # end-of-line whitespace
|
134
|
-
data.gsub!(/([;{]) +/m, '\1') # coalescing whitespace elsewhere
|
135
|
-
data.gsub!(/[; ]+\}/, '}') # remove superfluous trailing semi-colons
|
136
146
|
data.gsub!(%r|/\*.+?\*/|m, '') # comments
|
147
|
+
data.gsub!(/([;{,]) *\n/m, '\1') # end-of-line whitespace
|
137
148
|
data.gsub!(/\n{2,}/m, "\n") # collapse lines
|
138
|
-
data.gsub!(
|
149
|
+
data.gsub!(/[; ]+\}/, '}') # superfluous trailing semi-colons
|
150
|
+
data.gsub!(/([{;,+])[ ]+/, '\1') # whitespace around things
|
151
|
+
data.gsub!(/[ \t]+/m, ' ') # coalescing whitespace elsewhere
|
152
|
+
data.gsub!(/^/, ' ') # indent
|
139
153
|
data.strip!
|
140
154
|
[
|
141
155
|
"<style type='text/css' media='#{media}'>",
|
data/lib/ronn/template/dark.css
CHANGED
data/lib/ronn/template/man.css
CHANGED
@@ -55,33 +55,33 @@ body#manpage { margin:0 }
|
|
55
55
|
.mp pre code, .mp tt, .mp kbd,
|
56
56
|
.mp samp { color:#131211 }
|
57
57
|
.mp h1, .mp h2, .mp h3, .mp h4 { color:#030201 }
|
58
|
-
.mp
|
58
|
+
.mp u { text-decoration:underline; }
|
59
59
|
|
60
60
|
.mp code, .mp strong, .mp b {
|
61
61
|
font-weight:bold;
|
62
62
|
color:#131211;
|
63
63
|
}
|
64
64
|
|
65
|
-
.mp em, .mp var
|
65
|
+
.mp em, .mp var {
|
66
66
|
font-style:italic;
|
67
|
-
color:#
|
67
|
+
color:#232221;
|
68
68
|
text-decoration:none;
|
69
69
|
}
|
70
70
|
|
71
|
-
|
72
|
-
background:#edeceb;
|
73
|
-
padding:5px 1ex;
|
74
|
-
border-left:1ex solid #ddd;
|
75
|
-
}
|
76
|
-
.mp pre code {
|
77
|
-
font-weight:normal;
|
78
|
-
background:inherit;
|
79
|
-
}
|
71
|
+
/* LINKS */
|
80
72
|
|
81
73
|
.mp a, .mp a:link, .mp a:hover,
|
82
74
|
.mp a code, .mp a pre, .mp a tt,
|
83
75
|
.mp a kbd, .mp a samp { color:#0000ff }
|
84
76
|
|
77
|
+
.mp b.man-ref { font-weight:normal;color:#434241 }
|
78
|
+
|
79
|
+
/* PREFORMATTED BLOCKS */
|
80
|
+
|
81
|
+
.mp pre { padding:0 4ex }
|
82
|
+
.mp pre code { font-weight:normal;color:#434241 }
|
83
|
+
.mp h2+pre, h3+pre { padding-left:0 }
|
84
|
+
|
85
85
|
/* DOCUMENT HEADER AND FOOTER AREAS */
|
86
86
|
|
87
87
|
ol.man-decor, ol.man-decor li {
|