ron 0.1 → 0.2
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/README +10 -6
- data/Rakefile +7 -0
- data/bin/ron +46 -17
- data/lib/ron.rb +5 -4
- data/lib/ron/document.rb +221 -49
- data/lib/ron/layout.html +53 -22
- data/lib/ron/roff.rb +26 -5
- data/man/ron.1.ron +44 -21
- data/man/ron.5.ron +5 -3
- data/man/ron.7.ron +149 -0
- data/ron.gemspec +13 -3
- data/test/angle_bracket_syntax.html +12 -0
- data/test/angle_bracket_syntax.ron +12 -0
- data/test/basic_document.html +3 -0
- data/test/{simple.ron → basic_document.ron} +2 -0
- data/test/custom_title_document.html +3 -0
- data/test/custom_title_document.ron +5 -0
- data/test/definition_list_syntax.html +21 -0
- data/test/definition_list_syntax.ron +18 -0
- data/test/document_test.rb +64 -11
- data/test/ron_test.rb +30 -5
- data/test/titleless_document.html +2 -0
- data/test/titleless_document.ron +2 -0
- metadata +13 -3
data/README
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
|
1
|
+
ron(7) -- the opposite of roff
|
2
|
+
==============================
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
-----------
|
2
6
|
|
3
7
|
Ron is a humane text format and toolchain for
|
4
8
|
creating UNIX man pages -- and things that
|
@@ -19,17 +23,17 @@ format in more detail.
|
|
19
23
|
INSTALL
|
20
24
|
-------
|
21
25
|
|
22
|
-
|
23
|
-
rubygems:
|
26
|
+
Ron can be installed using rubygems:
|
24
27
|
|
25
|
-
$ [sudo] gem install ron
|
28
|
+
$ [sudo] gem install ron
|
26
29
|
|
27
30
|
Or, clone the git repository and install from
|
28
31
|
source:
|
29
32
|
|
30
33
|
$ git clone git://github.com/rtomayko/ron.git
|
31
34
|
$ cd ron
|
32
|
-
$ rake
|
35
|
+
$ rake package
|
36
|
+
$ [sudo] rake install
|
33
37
|
|
34
38
|
EXAMPLES
|
35
39
|
--------
|
@@ -47,7 +51,7 @@ BASIC USAGE
|
|
47
51
|
-----------
|
48
52
|
|
49
53
|
To generate a roff man page from the included
|
50
|
-
markdown.5.ron file and open it in man(1):
|
54
|
+
`markdown.5.ron` file and open it in man(1):
|
51
55
|
|
52
56
|
$ ron -b man/markdown.5.ron
|
53
57
|
building: man/markdown.5
|
data/Rakefile
CHANGED
@@ -11,6 +11,13 @@ Rake::TestTask.new(:test) do |t|
|
|
11
11
|
t.ruby_opts = ['-rubygems'] if defined? Gem
|
12
12
|
end
|
13
13
|
|
14
|
+
# DOCS =================================================================
|
15
|
+
|
16
|
+
desc 'Build the manual'
|
17
|
+
task 'man' do
|
18
|
+
sh "ron -br5 --manual='Ron Manual' --organization='Ryan Tomayko' man/*.ron"
|
19
|
+
end
|
20
|
+
|
14
21
|
# PACKAGING ============================================================
|
15
22
|
|
16
23
|
require 'rubygems/specification'
|
data/bin/ron
CHANGED
@@ -1,24 +1,37 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
## Usage: ron [ OPTIONS ] [ FILE
|
2
|
+
## Usage: ron [ OPTIONS ] [ FILE ]
|
3
3
|
## ron --build FILE ...
|
4
4
|
## ron --install FILE ...
|
5
|
-
## ron --man FILE
|
6
|
-
## Convert ron
|
5
|
+
## ron --man FILE ...
|
6
|
+
## Convert ron FILE to roff man page or HTML and write to standard
|
7
|
+
## output. With no FILE, ron reads from standard input. The build,
|
8
|
+
## install, and man forms accept multiple FILE arguments.
|
7
9
|
##
|
8
|
-
##
|
9
|
-
##
|
10
|
-
## -
|
11
|
-
## -
|
10
|
+
## Modes:
|
11
|
+
## --pipe write to standard output (default behavior)
|
12
|
+
## -b, --build write to files instead of standard output
|
13
|
+
## -i, --install write to file in MAN_HOME or system man path
|
14
|
+
## -m, --man open man page like man(1)
|
12
15
|
##
|
13
|
-
##
|
14
|
-
##
|
16
|
+
## Formats:
|
17
|
+
## --roff generate roff/man text; this is the default behavior
|
18
|
+
## -5, --html generate entire HTML page with layout
|
19
|
+
## -f, --fragment generate HTML fragment instead of entire HTML page
|
15
20
|
##
|
16
|
-
##
|
21
|
+
## Document attributes:
|
22
|
+
## --date=DATE published date in YYYY-MM-DD format;
|
23
|
+
## displayed bottom-center in footer
|
24
|
+
## --manual=NAME name of the manual this document belongs to;
|
25
|
+
## displayed top-center in header
|
26
|
+
## --organization=NAME publishing group, organization, or individual;
|
27
|
+
## displayed bottom-left in footer
|
28
|
+
##
|
29
|
+
## --help show this help message
|
17
30
|
##
|
18
|
-
## See the ron(2)
|
19
31
|
require 'optparse'
|
20
32
|
|
21
33
|
formats = []
|
34
|
+
options = {}
|
22
35
|
build = false
|
23
36
|
install = false
|
24
37
|
man = false
|
@@ -38,12 +51,22 @@ end
|
|
38
51
|
|
39
52
|
# parse command line options
|
40
53
|
ARGV.options do |option|
|
41
|
-
|
42
|
-
option.on("
|
54
|
+
# modes
|
55
|
+
option.on("--pipe") { }
|
43
56
|
option.on("-b", "--build") { build = true }
|
44
57
|
option.on("-i", "--install") { install = true }
|
45
58
|
option.on("-m", "--man") { man = true }
|
46
59
|
|
60
|
+
# format options
|
61
|
+
option.on("-r", "--roff") { formats << 'roff' }
|
62
|
+
option.on("-5", "--html") { formats << 'html' }
|
63
|
+
option.on("-f", "--fragment") { formats << 'html_fragment' }
|
64
|
+
|
65
|
+
# manual attribute options
|
66
|
+
[:name, :section, :manual, :organization, :date].each do |option_attr|
|
67
|
+
option.on("--#{option_attr}=VALUE") { |val| options[option_attr] = val }
|
68
|
+
end
|
69
|
+
|
47
70
|
option.on_tail("--help") { usage ; exit }
|
48
71
|
option.parse!
|
49
72
|
end
|
@@ -55,13 +78,19 @@ elsif ARGV.empty?
|
|
55
78
|
ARGV.push '-'
|
56
79
|
end
|
57
80
|
|
81
|
+
# turn the --date arg into
|
82
|
+
if options[:date]
|
83
|
+
options[:date] = Date.strptime(options[:date], '%Y-%m-%d')
|
84
|
+
end
|
85
|
+
|
58
86
|
formats = ['roff'] if formats.empty?
|
87
|
+
formats.delete('html') if formats.include?('html_fragment')
|
59
88
|
pid = nil
|
60
89
|
|
61
90
|
require 'ron'
|
62
91
|
wr = STDOUT
|
63
92
|
ARGV.each do |file|
|
64
|
-
doc = Ron.new(file) { file == '-' ? STDIN.read : File.read(file) }
|
93
|
+
doc = Ron.new(file, options) { file == '-' ? STDIN.read : File.read(file) }
|
65
94
|
|
66
95
|
# setup the man pipeline if the --man option was specified
|
67
96
|
if man && !build
|
@@ -79,11 +108,11 @@ ARGV.each do |file|
|
|
79
108
|
formats.each do |format|
|
80
109
|
output = doc.convert(format)
|
81
110
|
if build
|
82
|
-
path = doc.
|
111
|
+
path = doc.path_for(format)
|
83
112
|
info "building: #{path}"
|
84
|
-
File.open(path, 'wb') { |f| f.
|
113
|
+
File.open(path, 'wb') { |f| f.puts(output) }
|
85
114
|
else
|
86
|
-
wr.
|
115
|
+
wr.puts(output)
|
87
116
|
end
|
88
117
|
end
|
89
118
|
|
data/lib/ron.rb
CHANGED
@@ -3,13 +3,14 @@
|
|
3
3
|
# install standard UNIX roff(7) formatted manpages or to generate
|
4
4
|
# beautiful HTML manpages.
|
5
5
|
module Ron
|
6
|
-
VERSION = '0.
|
6
|
+
VERSION = '0.2'
|
7
7
|
|
8
8
|
require 'ron/document'
|
9
9
|
require 'ron/roff'
|
10
10
|
|
11
|
-
# Create a new Ron::Document for the given ron file.
|
12
|
-
|
13
|
-
|
11
|
+
# Create a new Ron::Document for the given ron file. See
|
12
|
+
# Ron::Document.new for usage information.
|
13
|
+
def self.new(filename, attributes={}, &block)
|
14
|
+
Document.new(filename, attributes, &block)
|
14
15
|
end
|
15
16
|
end
|
data/lib/ron/document.rb
CHANGED
@@ -1,60 +1,178 @@
|
|
1
|
+
require 'set'
|
1
2
|
require 'nokogiri'
|
2
3
|
require 'rdiscount'
|
3
4
|
require 'ron/roff'
|
4
5
|
|
5
6
|
module Ron
|
7
|
+
# The Document class can be used to load and inspect a ron document
|
8
|
+
# and to convert a ron document into other formats, like roff or
|
9
|
+
# HTML.
|
10
|
+
#
|
11
|
+
# Ron files may optionally follow the naming convention:
|
12
|
+
# "<name>.<section>.ron". The <name> and <section> are used in
|
13
|
+
# generated documentation unless overridden by the information
|
14
|
+
# extracted from the document's name section.
|
6
15
|
class Document
|
7
|
-
|
8
|
-
attr_reader :filename, :data, :basename, :name, :section, :tagline
|
16
|
+
attr_reader :path, :data
|
9
17
|
|
10
|
-
|
11
|
-
|
18
|
+
# The man pages name: usually a single word name of
|
19
|
+
# a program or filename; displayed along with the section in
|
20
|
+
# the left and right portions of the header as well as the bottom
|
21
|
+
# right section of the footer.
|
22
|
+
attr_accessor :name
|
23
|
+
|
24
|
+
# The man page's section: a string whose first character
|
25
|
+
# is numeric; displayed in parenthesis along with the name.
|
26
|
+
attr_accessor :section
|
27
|
+
|
28
|
+
# Single sentence description of the thing being described
|
29
|
+
# by this man page; displayed in the NAME section.
|
30
|
+
attr_accessor :tagline
|
31
|
+
|
32
|
+
# The manual this document belongs to; center displayed in
|
33
|
+
# the header.
|
34
|
+
attr_accessor :manual
|
35
|
+
|
36
|
+
# The name of the group, organization, or individual responsible
|
37
|
+
# for this document; displayed in the left portion of the footer.
|
38
|
+
attr_accessor :organization
|
39
|
+
|
40
|
+
# The date the document was published; center displayed in
|
41
|
+
# the document footer.
|
42
|
+
attr_accessor :date
|
43
|
+
|
44
|
+
# Create a Ron::Document given a path or with the data returned by
|
45
|
+
# calling the block. The document is loaded and preprocessed before
|
46
|
+
# the intialize method returns. The attributes hash may contain values
|
47
|
+
# for any writeable attributes defined on this class.
|
48
|
+
def initialize(path=nil, attributes={}, &block)
|
49
|
+
@path = path
|
50
|
+
@basename = path.to_s =~ /^-?$/ ? nil : File.basename(path)
|
12
51
|
@reader = block || Proc.new { |f| File.read(f) }
|
13
|
-
@data = @reader.call(
|
52
|
+
@data = @reader.call(path)
|
53
|
+
@name, @section, @tagline = nil
|
54
|
+
@manual, @organization, @date = nil
|
55
|
+
@fragment = preprocess
|
56
|
+
attributes.each { |attr_name,value| send("#{attr_name}=", value) }
|
57
|
+
end
|
14
58
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
59
|
+
# Generate a file basename of the form "<name>.<section>.<type>"
|
60
|
+
# for the given file extension. Uses the name and section from
|
61
|
+
# the source file path but falls back on the name and section
|
62
|
+
# defined in the document.
|
63
|
+
def basename(type=nil)
|
64
|
+
type = nil if ['', 'roff'].include?(type.to_s)
|
65
|
+
[path_name || @name, path_section || @section, type].
|
66
|
+
compact.join('.')
|
67
|
+
end
|
68
|
+
|
69
|
+
# Construct a path for a file near the source file. Uses the
|
70
|
+
# Document#basename method to generate the basename part and
|
71
|
+
# appends it to the dirname of the source document.
|
72
|
+
def path_for(type=nil)
|
73
|
+
if @basename
|
74
|
+
File.join(File.dirname(path), basename(type))
|
75
|
+
else
|
76
|
+
basename(type)
|
77
|
+
end
|
22
78
|
end
|
23
79
|
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
File.join(File.dirname(filename), name)
|
80
|
+
# Returns the <name> part of the path, or nil when no path is
|
81
|
+
# available. This is used as the manual page name when the
|
82
|
+
# file contents do not include a name section.
|
83
|
+
def path_name
|
84
|
+
@basename[/^[^.]+/] if @basename
|
30
85
|
end
|
31
86
|
|
32
|
-
#
|
87
|
+
# Returns the <section> part of the path, or nil when
|
88
|
+
# no path is available.
|
89
|
+
def path_section
|
90
|
+
$1 if @basename.to_s =~ /\.(\d\w*)\./
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns the manual page name based first on the document's
|
94
|
+
# contents and then on the path name.
|
95
|
+
def name
|
96
|
+
@name || path_name
|
97
|
+
end
|
98
|
+
|
99
|
+
# Truthful when the name was extracted from the name section
|
100
|
+
# of the document.
|
101
|
+
def name?
|
102
|
+
@name
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns the manual page section based first on the document's
|
106
|
+
# contents and then on the path name.
|
107
|
+
def section
|
108
|
+
@section || path_section
|
109
|
+
end
|
110
|
+
|
111
|
+
# True when the section number was extracted from the name
|
112
|
+
# section of the document.
|
113
|
+
def section?
|
114
|
+
@section
|
115
|
+
end
|
116
|
+
|
117
|
+
# The date the man page was published. If not set explicitly,
|
118
|
+
# this is the file's modified time or, if no file is given,
|
119
|
+
# the current time.
|
120
|
+
def date
|
121
|
+
return @date if @date
|
122
|
+
return File.mtime(path) if File.exist?(path)
|
123
|
+
Time.now
|
124
|
+
end
|
125
|
+
|
126
|
+
# Convert the document to :roff, :html, or :html_fragment and
|
127
|
+
# return the result as a string.
|
33
128
|
def convert(format)
|
34
129
|
send "to_#{format}"
|
35
130
|
end
|
36
131
|
|
37
|
-
# Convert the document to roff.
|
132
|
+
# Convert the document to roff and return the result as a string.
|
38
133
|
def to_roff
|
39
134
|
RoffFilter.new(
|
40
135
|
to_html_fragment,
|
41
136
|
name,
|
42
137
|
section,
|
43
|
-
tagline
|
138
|
+
tagline,
|
139
|
+
manual,
|
140
|
+
organization,
|
141
|
+
date
|
44
142
|
).to_s
|
45
143
|
end
|
46
144
|
|
47
|
-
# Convert the document to HTML and return result
|
48
|
-
# as a string.
|
145
|
+
# Convert the document to HTML and return the result as a string.
|
49
146
|
def to_html
|
50
147
|
layout_filter(to_html_fragment)
|
51
148
|
end
|
52
149
|
|
53
|
-
# Convert the document to HTML and return result
|
150
|
+
# Convert the document to HTML and return the result
|
54
151
|
# as a string. The HTML does not include <html>, <head>,
|
55
152
|
# or <style> tags.
|
56
153
|
def to_html_fragment
|
57
|
-
|
154
|
+
buf = []
|
155
|
+
if name? && section?
|
156
|
+
buf << "<h2 id='NAME'>NAME</h2>"
|
157
|
+
buf << "<p><code>#{name}</code> -- #{tagline}</p>"
|
158
|
+
elsif tagline
|
159
|
+
buf << "<h1>#{[name, tagline].compact.join(' -- ')}</h1>"
|
160
|
+
end
|
161
|
+
buf << @fragment.to_s
|
162
|
+
buf.join("\n")
|
163
|
+
end
|
164
|
+
|
165
|
+
protected
|
166
|
+
# Parse the document and extract the name, section, and tagline
|
167
|
+
# from its contents. This is called while the object is being
|
168
|
+
# initialized.
|
169
|
+
def preprocess
|
170
|
+
[
|
171
|
+
:angle_quote_pre_filter,
|
172
|
+
:markdown_filter,
|
173
|
+
:angle_quote_post_filter,
|
174
|
+
:definition_list_filter
|
175
|
+
].inject(data) { |res,filter| send(filter, res) }
|
58
176
|
end
|
59
177
|
|
60
178
|
# Apply the standard HTML layout template.
|
@@ -64,31 +182,12 @@ module Ron
|
|
64
182
|
eval("%Q{#{template}}", binding, template_file)
|
65
183
|
end
|
66
184
|
|
67
|
-
# Run markdown on the data and extract name, section, and
|
68
|
-
# tagline.
|
69
|
-
def markdown_filter(data)
|
70
|
-
html = Markdown.new(data).to_html
|
71
|
-
@tagline, html = html.split("</h1>\n", 2)
|
72
|
-
@tagline.sub!('<h1>', '')
|
73
|
-
|
74
|
-
# grab name and section from title
|
75
|
-
if @tagline =~ /([\w_:-]+)\((\d\w*)\) -- (.*)/
|
76
|
-
@name, @section = $1, $2
|
77
|
-
@tagline = $3
|
78
|
-
end
|
79
|
-
|
80
|
-
"<h2 id='NAME'>NAME</h2>\n" +
|
81
|
-
"<p><code>#{@name}</code> -- #{@tagline}</p>\n" +
|
82
|
-
html
|
83
|
-
end
|
84
|
-
|
85
185
|
# Convert special format unordered lists to definition lists.
|
86
186
|
def definition_list_filter(html)
|
87
|
-
doc =
|
88
|
-
|
187
|
+
doc = parse_html(html)
|
89
188
|
# process all unordered lists depth-first
|
90
|
-
doc.
|
91
|
-
items = ul.
|
189
|
+
doc.search('ul').to_a.reverse.each do |ul|
|
190
|
+
items = ul.search('li')
|
92
191
|
next if items.any? { |item| item.text.split("\n", 2).first !~ /:$/ }
|
93
192
|
|
94
193
|
ul.name = 'dl'
|
@@ -103,15 +202,88 @@ module Ron
|
|
103
202
|
term, definition = container.inner_html.split(":\n", 2)
|
104
203
|
|
105
204
|
dt = item.before("<dt>#{term}</dt>").previous_sibling
|
106
|
-
dt['class'] = 'flush' if dt.content.length <=
|
205
|
+
dt['class'] = 'flush' if dt.content.length <= 7
|
107
206
|
|
108
207
|
item.name = 'dd'
|
109
208
|
container.swap(wrap.sub(/></, ">#{definition}<"))
|
110
209
|
end
|
111
210
|
end
|
211
|
+
doc
|
212
|
+
end
|
112
213
|
|
113
|
-
|
214
|
+
# Perform angle quote (<THESE>) post filtering.
|
215
|
+
def angle_quote_post_filter(html)
|
216
|
+
doc = parse_html(html)
|
217
|
+
# convert all angle quote vars nested in code blocks
|
218
|
+
# back to the original text
|
219
|
+
doc.search('code text()').each do |node|
|
220
|
+
next unless node.to_s.include?('var>')
|
221
|
+
new = node.document.create_text_node(
|
222
|
+
node.to_s.
|
223
|
+
gsub('<var>', '<').
|
224
|
+
gsub("</var>", '>')
|
225
|
+
)
|
226
|
+
node.replace(new)
|
227
|
+
end
|
228
|
+
doc
|
114
229
|
end
|
115
230
|
|
231
|
+
# Run markdown on the data and extract name, section, and
|
232
|
+
# tagline.
|
233
|
+
def markdown_filter(data)
|
234
|
+
html = Markdown.new(data).to_html
|
235
|
+
@tagline, html = html.split("</h1>\n", 2)
|
236
|
+
if html.nil?
|
237
|
+
html = @tagline
|
238
|
+
@tagline = nil
|
239
|
+
else
|
240
|
+
# grab name and section from title
|
241
|
+
@tagline.sub!('<h1>', '')
|
242
|
+
if @tagline =~ /([\w_.\[\]~+=@:-]+)\s*\((\d\w*)\)\s*--?\s*(.*)/
|
243
|
+
@name = $1
|
244
|
+
@section = $2
|
245
|
+
@tagline = $3
|
246
|
+
elsif @tagline =~ /([\w_.\[\]~+=@:-]+)\s+--\s+(.*)/
|
247
|
+
@name = $1
|
248
|
+
@tagline = $2
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
html.to_s
|
253
|
+
end
|
254
|
+
|
255
|
+
# Convert all <WORD> to <var>WORD</var> but only if WORD
|
256
|
+
# isn't an HTML tag.
|
257
|
+
def angle_quote_pre_filter(data)
|
258
|
+
data.gsub(/\<([^:.\/]+?)\>/) do |match|
|
259
|
+
contents = $1
|
260
|
+
tag, attrs = contents.split(' ', 2)
|
261
|
+
if attrs =~ /\/=/ ||
|
262
|
+
HTML.include?(tag.sub(/^\//, '')) ||
|
263
|
+
data.include?("</#{tag}>")
|
264
|
+
match.to_s
|
265
|
+
else
|
266
|
+
"<var>#{contents}</var>"
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
HTML = %w[
|
272
|
+
a abbr acronym b bdo big br cite code dfn
|
273
|
+
em i img input kbd label q samp select
|
274
|
+
small span strong sub sup textarea tt var
|
275
|
+
address blockquote div dl fieldset form
|
276
|
+
h1 h2 h3 h4 h5 h6 hr noscript ol p pre
|
277
|
+
table ul
|
278
|
+
].to_set
|
279
|
+
|
280
|
+
private
|
281
|
+
def parse_html(html)
|
282
|
+
if html.kind_of?(Nokogiri::HTML::DocumentFragment)
|
283
|
+
html
|
284
|
+
else
|
285
|
+
Nokogiri::HTML.fragment(html.to_s)
|
286
|
+
end
|
287
|
+
end
|
116
288
|
end
|
117
289
|
end
|
data/lib/ron/layout.html
CHANGED
@@ -1,39 +1,70 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
3
|
<head>
|
4
|
-
<
|
4
|
+
<meta http-equiv='content-type' value='text/html;charset=utf8'>
|
5
|
+
<meta name='generator' value='Ron/v#{Ron::VERSION}'>
|
6
|
+
<title>#{name}(#{section})#{tagline ? " -- " + tagline : ''}</title>
|
5
7
|
<style type='text/css'>
|
6
|
-
body {
|
8
|
+
body {margin:0}
|
9
|
+
#man, #man code, #man pre, #man tt, #man kbd, #man samp {
|
7
10
|
font-family:consolas,monospace;
|
8
|
-
font-size:
|
11
|
+
font-size:16px;
|
9
12
|
line-height:1.25;
|
10
|
-
color:#
|
11
|
-
|
12
|
-
#man { max-width:
|
13
|
-
#man h1, #man h2, #man h3
|
14
|
-
#man h1 { text-align:center }
|
15
|
-
#man h2 { font-size:
|
16
|
-
#man h3 { font-size:
|
17
|
-
#man p, #man ul, #man ol, #man dl, #man pre
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
#man
|
26
|
-
#man
|
27
|
-
#man
|
13
|
+
color:#434241;
|
14
|
+
background:#fff; }
|
15
|
+
#man { max-width:85ex; text-align:justify; margin:0 25px 25px 25px }
|
16
|
+
#man h1, #man h2, #man h3 { color:#232221;clear:left }
|
17
|
+
#man h1 { font-size:28px; margin:10px 0 30px 0; text-align:center }
|
18
|
+
#man h2 { font-size:18px; margin-bottom:2px; margin-top:10px; line-height:1.2; }
|
19
|
+
#man h3 { font-size:16px; margin:0 0 0 4ex; }
|
20
|
+
#man p, #man ul, #man ol, #man dl, #man pre { margin:0 0 18px 0; }
|
21
|
+
#man pre {
|
22
|
+
color:#333231;
|
23
|
+
background:#edeceb;
|
24
|
+
padding:5px 10px;
|
25
|
+
border-left:2ex solid #ddd;
|
26
|
+
margin-top:-10px;
|
27
|
+
margin-bottom:12px; }
|
28
|
+
#man > p, #man > ul, #man > ol, #man > dl, #man > pre { margin-left:8ex; }
|
29
|
+
#man dt { margin:0; clear:left }
|
30
|
+
#man dt.flush { float:left; width:8ex }
|
31
|
+
#man dd { margin:0 0 0 9ex }
|
32
|
+
#man code, #man strong, #man b { font-weight:bold; color:#131211; }
|
33
|
+
#man pre code { font-weight:normal; color:#232221; background:inherit }
|
34
|
+
#man em, var, u {
|
35
|
+
font-style:normal; color:#333231; border-bottom:1px solid #999; }
|
36
|
+
#man h1.man-title { display:none; }
|
37
|
+
#man ol.man, #man ol.man li { margin:2px 0 10px 0; padding:0;
|
38
|
+
float:left; width:33%; list-style-type:none;
|
39
|
+
text-transform:uppercase; font-size:18px; color:#999;
|
40
|
+
letter-spacing:1px;}
|
41
|
+
#man ol.man { width:100%; }
|
42
|
+
#man ol.man li.tl { text-align:left }
|
43
|
+
#man ol.man li.tc { text-align:center;letter-spacing:4px }
|
44
|
+
#man ol.man li.tr { text-align:right }
|
45
|
+
#man ol.man a { color:#999 }
|
46
|
+
#man ol.man a:hover { color:#333231 }
|
28
47
|
</style>
|
29
48
|
</head>
|
30
49
|
<body>
|
31
50
|
<div id='man'>
|
32
51
|
|
33
|
-
<h1>#{
|
52
|
+
<h1 class='man-title'>#{name}(#{section})</h1>
|
53
|
+
|
54
|
+
<ol class='head man'>
|
55
|
+
<li class='tl'>#{name if section}#{"("+section+")" if name and section}</li>
|
56
|
+
<li class='tc'>#{manual}</li>
|
57
|
+
<li class='tr'>#{name if section}#{"("+section+")" if name and section}</li>
|
58
|
+
</ol>
|
34
59
|
|
35
60
|
#{html}
|
36
61
|
|
62
|
+
<ol class='foot man'>
|
63
|
+
<li class='tl'>#{organization}</li>
|
64
|
+
<li class='tc'>#{date.strftime('%B %Y')}</li>
|
65
|
+
<li class='tr'>#{name if section}#{"("+section+")" if name and section}</li>
|
66
|
+
</ol>
|
67
|
+
|
37
68
|
</div>
|
38
69
|
</body>
|
39
70
|
</html>
|
data/lib/ron/roff.rb
CHANGED
@@ -16,9 +16,9 @@ module Ron
|
|
16
16
|
|
17
17
|
protected
|
18
18
|
def title_heading(name, section, tagline, manual, version, date)
|
19
|
-
comment "generated with Ron"
|
19
|
+
comment "generated with Ron/v#{Ron::VERSION}"
|
20
20
|
comment "http://github.com/rtomayko/ron/"
|
21
|
-
macro "TH", %["#{escape(name.upcase)}" #{section} "#{date}" "#{version}" "#{manual}"]
|
21
|
+
macro "TH", %["#{escape(name.upcase)}" #{section} "#{date.strftime('%B %Y')}" "#{version}" "#{manual}"]
|
22
22
|
end
|
23
23
|
|
24
24
|
def block_filter(node)
|
@@ -74,6 +74,22 @@ module Ron
|
|
74
74
|
end
|
75
75
|
write "\n"
|
76
76
|
|
77
|
+
# ordered/unordered lists
|
78
|
+
# when 'ul'
|
79
|
+
# # macro "IP", '\(bu'
|
80
|
+
# block_filter(node.children)
|
81
|
+
# when 'ol'
|
82
|
+
# macro "IP", '1.'
|
83
|
+
# block_filter(node.children)
|
84
|
+
# when 'li'
|
85
|
+
# macro "IP" unless prev.nil?
|
86
|
+
# if node.search('p').any?
|
87
|
+
# block_filter(node.children)
|
88
|
+
# else
|
89
|
+
# inline_filter(node.children)
|
90
|
+
# end
|
91
|
+
# write "\n"
|
92
|
+
|
77
93
|
else
|
78
94
|
warn "unrecognized block tag: %p", node.name
|
79
95
|
end
|
@@ -85,14 +101,19 @@ module Ron
|
|
85
101
|
return
|
86
102
|
end
|
87
103
|
|
104
|
+
prev = node.previous_sibling
|
105
|
+
prev = prev.previous_sibling until prev.nil? || prev.element?
|
106
|
+
|
88
107
|
case node.name
|
89
108
|
when 'text'
|
90
|
-
|
91
|
-
|
109
|
+
text = node.content
|
110
|
+
text = text.sub(/^\n+/m, '') if prev && prev.name == 'br'
|
111
|
+
write escape(text.sub(/\n+$/, ' '))
|
112
|
+
when 'code', 'b', 'strong', 'kbd', 'samp'
|
92
113
|
write '\fB'
|
93
114
|
inline_filter(node.children)
|
94
115
|
write '\fR'
|
95
|
-
when 'em', 'i', 'u'
|
116
|
+
when 'var', 'em', 'i', 'u'
|
96
117
|
write '\fI'
|
97
118
|
inline_filter(node.children)
|
98
119
|
write '\fR'
|
data/man/ron.1.ron
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
ron(1) --
|
2
|
-
|
1
|
+
ron(1) -- build markdown-based man pages
|
2
|
+
========================================
|
3
3
|
|
4
4
|
## SYNOPSIS
|
5
5
|
|
6
|
-
`ron` [
|
7
|
-
`ron` --build
|
8
|
-
`ron` --install
|
9
|
-
`ron` --man
|
6
|
+
`ron` [ <OPTIONS> ]
|
7
|
+
`ron` --build <FILE> ...
|
8
|
+
`ron` --install <FILE> ...
|
9
|
+
`ron` --man <FILE>
|
10
10
|
|
11
11
|
## DESCRIPTION
|
12
12
|
|
@@ -15,7 +15,7 @@ ron(1) -- the opposite of roff
|
|
15
15
|
and install standard UNIX / roff(7) formatted man pages and to
|
16
16
|
generate nicely formatted HTML manual pages.
|
17
17
|
|
18
|
-
The `ron` command converts one or more named input <
|
18
|
+
The `ron` command converts one or more named input <FILE>s
|
19
19
|
(or standard input when no files are named or the file name `-`
|
20
20
|
is given) from humane man page markup to one or more destination
|
21
21
|
output formats. If no output format is selected explicitly, `ron`
|
@@ -24,13 +24,13 @@ writes output in roff format.
|
|
24
24
|
## FILES
|
25
25
|
|
26
26
|
The `ron` command expects input to be formatted as ron(5) text.
|
27
|
-
Source files are typically named '
|
28
|
-
`hello.1.ron`). The
|
29
|
-
and section defined in
|
27
|
+
Source files are typically named '<NAME>.<SECTION>.ron' (e.g.,
|
28
|
+
`hello.1.ron`). The <NAME> and <SECTION> should match the name
|
29
|
+
and section defined in <FILE>'s heading.
|
30
30
|
|
31
31
|
When building roff and/or HTML output files with the `--build`
|
32
32
|
argument, destination filenames are determined by taking the basename
|
33
|
-
of the input
|
33
|
+
of the input <FILE> and adding the appropriate file extension (or
|
34
34
|
removing the file extension in the case of roff output).
|
35
35
|
|
36
36
|
For example, the command `ron -b --html --roff hello.1.ron` would
|
@@ -46,8 +46,8 @@ The following arguments change this behavior:
|
|
46
46
|
* `-b`, `--build`:
|
47
47
|
Write output directly to files instead of standard output. When
|
48
48
|
the `--roff` option is provided, writes roff output to
|
49
|
-
|
50
|
-
output to '
|
49
|
+
<file>.<section>. When the `--html` option is provided, writes
|
50
|
+
output to '<file>.<section>.html'.
|
51
51
|
|
52
52
|
* `-i`, `--install`:
|
53
53
|
Install the roff formatted man page to the local system such
|
@@ -59,20 +59,42 @@ The following arguments change this behavior:
|
|
59
59
|
_/usr/local/man_.
|
60
60
|
|
61
61
|
* `-m`, `--man`:
|
62
|
-
Display
|
62
|
+
Display <FILE>s as if man(1) were invoked on the roff output
|
63
63
|
file. This simulates default man behavior by piping the roff
|
64
64
|
output through groff(1) and the paging program specified by the
|
65
65
|
`MANPAGER` environment variable.
|
66
66
|
|
67
|
-
|
67
|
+
These options control the format used in generated output:
|
68
68
|
|
69
|
-
* `--
|
70
|
-
Generate HTML output.
|
71
|
-
|
72
|
-
* `--roff`:
|
69
|
+
* `-r`, `--roff`:
|
73
70
|
Generate roff output. This is the default behavior when no
|
74
71
|
other format argument is provided.
|
75
72
|
|
73
|
+
* `-5`, `--html`:
|
74
|
+
Generate output in HTML format.
|
75
|
+
|
76
|
+
* `-f`, `--fragment`:
|
77
|
+
Generate output in HTML format but only the document
|
78
|
+
fragment, not the header, title, or footer.
|
79
|
+
|
80
|
+
All document attributes displayed in the header and footer areas
|
81
|
+
of generated content can be specified with these options:
|
82
|
+
|
83
|
+
* `--manual`=<MANUAL>:
|
84
|
+
The name of the manual this man page belongs to; <MANUAL> is
|
85
|
+
prominently displayed top-center in the header area.
|
86
|
+
|
87
|
+
* `--organization`=<NAME>:
|
88
|
+
The name of the group, organization, or individual
|
89
|
+
responsible for publishing the document; <NAME> is displayed
|
90
|
+
in the bottom-left footer area.
|
91
|
+
|
92
|
+
* `--date`=<DATE>:
|
93
|
+
The document's published date; <DATE> must be formatted
|
94
|
+
`YYYY-MM-DD` and is displayed in the bottom-center footer
|
95
|
+
area. The <FILE> mtime is used when no <DATE> is given,
|
96
|
+
or the current time when no <FILE> is available.
|
97
|
+
|
76
98
|
## EXAMPLES
|
77
99
|
|
78
100
|
Generate `roff(7)` output on stdout:
|
@@ -113,7 +135,7 @@ Install the roff man page for a ron file:
|
|
113
135
|
* `MANHOME`:
|
114
136
|
Location where roff formatted man pages should be installed.
|
115
137
|
Relevant only when the `--installed` argument is provided.
|
116
|
-
|
138
|
+
<PATH> is to the base of a man file hierarchy. e.g.,
|
117
139
|
`/usr/local/share/man`, `/home/rtomayko/man`.
|
118
140
|
|
119
141
|
* `MANPAGER`:
|
@@ -125,7 +147,8 @@ Install the roff man page for a ron file:
|
|
125
147
|
|
126
148
|
## BUGS
|
127
149
|
|
128
|
-
Ron is written in Ruby.
|
150
|
+
Ron is written in Ruby. C and/or standalone Perl implementations
|
151
|
+
would be preferable for ease of packaging and distribution.
|
129
152
|
|
130
153
|
## COPYRIGHT
|
131
154
|
|
data/man/ron.5.ron
CHANGED
@@ -99,11 +99,13 @@ uses the following bits of markdown(5) to accomplish this:
|
|
99
99
|
displayed in in <b>boldface</b>. Note that all text included
|
100
100
|
within `backticks` is displayed literally; other inline markup
|
101
101
|
is not processed.
|
102
|
+
* `**double-stars**`:
|
103
|
+
Like `backticks` but may contain other inline markup.
|
102
104
|
* `_`_underbars_`_`:
|
103
105
|
User-specified arguments, variables, or user input; typically
|
104
|
-
displayed
|
105
|
-
*
|
106
|
-
|
106
|
+
displayed with <u>underline</u>.
|
107
|
+
* `<angle-quotes>`:
|
108
|
+
Same as _underbars_. This is not compatible with Markdown.
|
107
109
|
|
108
110
|
Here is grep(1)'s DESCRIPTION section represented in `ron`:
|
109
111
|
|
data/man/ron.7.ron
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
ron(7) -- the opposite of roff
|
2
|
+
==============================
|
3
|
+
|
4
|
+
DESCRIPTION
|
5
|
+
-----------
|
6
|
+
|
7
|
+
Ron is a humane text format and toolchain for
|
8
|
+
creating UNIX man pages -- and things that
|
9
|
+
appear as man pages from a distance. Use it
|
10
|
+
to build and install standard UNIX roff man
|
11
|
+
pages or to generate nicely formatted HTML
|
12
|
+
manual pages for the web.
|
13
|
+
|
14
|
+
The ron file format is based on Markdown. In
|
15
|
+
fact, ron files are 100% Markdown compatible
|
16
|
+
but have a more rigidly defined structure and
|
17
|
+
extend Markdown in some ways to provide
|
18
|
+
features commonly found in man pages (e.g.,
|
19
|
+
definition lists). The ron(5) manual page
|
20
|
+
included with this distribution defines the
|
21
|
+
format in more detail.
|
22
|
+
|
23
|
+
INSTALL
|
24
|
+
-------
|
25
|
+
|
26
|
+
Ron can be installed using rubygems:
|
27
|
+
|
28
|
+
$ [sudo] gem install ron
|
29
|
+
|
30
|
+
Or, clone the git repository and install from
|
31
|
+
source:
|
32
|
+
|
33
|
+
$ git clone git://github.com/rtomayko/ron.git
|
34
|
+
$ cd ron
|
35
|
+
$ rake package
|
36
|
+
$ [sudo] rake install
|
37
|
+
|
38
|
+
EXAMPLES
|
39
|
+
--------
|
40
|
+
|
41
|
+
The .ron files located under the repository's
|
42
|
+
./man directory show off a wide range of ron
|
43
|
+
capabilities. The HTML versions of these
|
44
|
+
files are available at:
|
45
|
+
|
46
|
+
http://rtomayko.github.com/ron/ron.1.html
|
47
|
+
http://rtomayko.github.com/ron/ron.5.html
|
48
|
+
http://rtomayko.github.com/ron/markdown.5.html
|
49
|
+
|
50
|
+
BASIC USAGE
|
51
|
+
-----------
|
52
|
+
|
53
|
+
To generate a roff man page from the included
|
54
|
+
`markdown.5.ron` file and open it in man(1):
|
55
|
+
|
56
|
+
$ ron -b man/markdown.5.ron
|
57
|
+
building: man/markdown.5
|
58
|
+
$ man man/markdown.5
|
59
|
+
|
60
|
+
To generate a standalone HTML version:
|
61
|
+
|
62
|
+
$ ron -b --html man/markdown.5.ron
|
63
|
+
building: man/markdown.5.html
|
64
|
+
$ open man/markdown.5.html
|
65
|
+
|
66
|
+
To build roff and HTML versions of all ron
|
67
|
+
files:
|
68
|
+
|
69
|
+
$ ron -b --roff --html man/*.ron
|
70
|
+
|
71
|
+
If you just want to view a ron file as if it
|
72
|
+
were a man page without building any
|
73
|
+
intermediate files:
|
74
|
+
|
75
|
+
$ ron -m man/markdown.5.ron
|
76
|
+
|
77
|
+
The ron(1) manual page included with this
|
78
|
+
distribution includes full documentation on
|
79
|
+
ron command line options.
|
80
|
+
|
81
|
+
RATIONALE
|
82
|
+
---------
|
83
|
+
|
84
|
+
Some people think UNIX manual pages are a
|
85
|
+
poor and outdated form of documentation. I
|
86
|
+
disagree.
|
87
|
+
|
88
|
+
- Man pages typically follow a well defined
|
89
|
+
structure that's immediately familiar and
|
90
|
+
provides a useful starting point for
|
91
|
+
developers documenting new tools,
|
92
|
+
libraries, and formats.
|
93
|
+
|
94
|
+
- Man pages get to the point. Because they're
|
95
|
+
written in an inverted style, with a
|
96
|
+
SYNOPSIS section followed by additional
|
97
|
+
detail, prose, and finally references to
|
98
|
+
other sources of information, man pages
|
99
|
+
provide the best of both cheat sheet and
|
100
|
+
reference style documentation.
|
101
|
+
|
102
|
+
- Man pages have very limited text formatting
|
103
|
+
capabilities. This is a feature. You get
|
104
|
+
bold and underline, basically, and they're
|
105
|
+
typically applied consistently across man
|
106
|
+
pages.
|
107
|
+
|
108
|
+
- Most man pages use only a single level of
|
109
|
+
section hierarchy (although two levels are
|
110
|
+
technically supported). Hierarchy destroys
|
111
|
+
otherwise good documentation by adding
|
112
|
+
unnecessary complexity. Feynman described
|
113
|
+
the whole of quantum electro dynamics with
|
114
|
+
only two levels of hierarchy. How can you
|
115
|
+
possibly need more? Man pages force you to
|
116
|
+
keep it simple.
|
117
|
+
|
118
|
+
- Man pages have a simple referencing syntax;
|
119
|
+
e.g., sh(1), fork(2), markdown(5). HTML
|
120
|
+
versions can use this to generate links
|
121
|
+
between pages.
|
122
|
+
|
123
|
+
- The classical terminal man page display is
|
124
|
+
typographically well thought out. Big bold
|
125
|
+
section headings, justified monospaced
|
126
|
+
text, nicely indented paragraphs,
|
127
|
+
intelligently aligned definition lists, and
|
128
|
+
an informational header and footer.
|
129
|
+
|
130
|
+
All that being said, trying to figure out how
|
131
|
+
to create a man page can be a really tedious
|
132
|
+
process. The roff/man macro languages are
|
133
|
+
highly extensible, fractured between multiple
|
134
|
+
dialects, and include a bunch of stuff that's
|
135
|
+
entirely irrelevant to modern man page
|
136
|
+
creation. It's also horribly ugly compared to
|
137
|
+
today's humane text formats or even HTML
|
138
|
+
(just sayin').
|
139
|
+
|
140
|
+
Ron aims to address many of the issues with
|
141
|
+
man page creation while preserving the things
|
142
|
+
that makes man pages a great form of
|
143
|
+
documentation.
|
144
|
+
|
145
|
+
COPYRIGHT
|
146
|
+
---------
|
147
|
+
|
148
|
+
Ron is Copyright (C) 2009 Ryan Tomayko
|
149
|
+
See the file COPYING for more information.
|
data/ron.gemspec
CHANGED
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'ron'
|
6
|
-
s.version = '0.
|
7
|
-
s.date = '2009-11-
|
6
|
+
s.version = '0.2'
|
7
|
+
s.date = '2009-11-23'
|
8
8
|
|
9
9
|
s.description = "The opposite of roff"
|
10
10
|
s.summary = "The opposite of roff"
|
@@ -25,10 +25,20 @@ Gem::Specification.new do |s|
|
|
25
25
|
man/markdown.5.ron
|
26
26
|
man/ron.1.ron
|
27
27
|
man/ron.5.ron
|
28
|
+
man/ron.7.ron
|
28
29
|
ron.gemspec
|
30
|
+
test/angle_bracket_syntax.html
|
31
|
+
test/angle_bracket_syntax.ron
|
32
|
+
test/basic_document.html
|
33
|
+
test/basic_document.ron
|
34
|
+
test/custom_title_document.html
|
35
|
+
test/custom_title_document.ron
|
36
|
+
test/definition_list_syntax.html
|
37
|
+
test/definition_list_syntax.ron
|
29
38
|
test/document_test.rb
|
30
39
|
test/ron_test.rb
|
31
|
-
test/
|
40
|
+
test/titleless_document.html
|
41
|
+
test/titleless_document.ron
|
32
42
|
]
|
33
43
|
# = MANIFEST =
|
34
44
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h2 id='NAME'>NAME</h2>
|
2
|
+
<p><code>angle_bracket_syntax</code> -- angle bracket syntax test</p>
|
3
|
+
<p>A <var>WORD</var> in angle brackets is converted to <var>WORD</var>,</p>
|
4
|
+
|
5
|
+
<pre><code>except when <WORD> is
|
6
|
+
part of a preformatted
|
7
|
+
code block,
|
8
|
+
</code></pre>
|
9
|
+
|
10
|
+
<p>or when <code><WORD></code> is enclosed in backticks.</p>
|
11
|
+
|
12
|
+
<p>or when <var>WORD</var> has a <dot.> or <foo:colon>.</p>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
angle_bracket_syntax(5) -- angle bracket syntax test
|
2
|
+
====================================================
|
3
|
+
|
4
|
+
A <WORD> in angle brackets is converted to <var>WORD</var>,
|
5
|
+
|
6
|
+
except when <WORD> is
|
7
|
+
part of a preformatted
|
8
|
+
code block,
|
9
|
+
|
10
|
+
or when `<WORD>` is enclosed in backticks.
|
11
|
+
|
12
|
+
or when <WORD> has a <dot.> or <foo:colon>.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<h2 id='NAME'>NAME</h2>
|
2
|
+
<p><code>defition_list_syntax</code> -- hiya</p>
|
3
|
+
<p>Definition lists look like unordered lists:</p>
|
4
|
+
|
5
|
+
<dl>
|
6
|
+
<dt class="flush">term</dt>
|
7
|
+
<dd><p>definition</p></dd>
|
8
|
+
<dt>another one</dt>
|
9
|
+
<dd>
|
10
|
+
<p>The definition may span
|
11
|
+
multiple lines and even</p>
|
12
|
+
|
13
|
+
<p>start</p>
|
14
|
+
|
15
|
+
<p>new paragraphs</p>
|
16
|
+
</dd>
|
17
|
+
<dt>
|
18
|
+
<code>--somearg</code>=<var>VALUE</var>
|
19
|
+
</dt>
|
20
|
+
<dd><p>We can do that too.</p></dd>
|
21
|
+
</dl>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
defition_list_syntax(5) -- hiya
|
2
|
+
===============================
|
3
|
+
|
4
|
+
Definition lists look like unordered lists:
|
5
|
+
|
6
|
+
* term:
|
7
|
+
definition
|
8
|
+
|
9
|
+
* another one:
|
10
|
+
The definition may span
|
11
|
+
multiple lines and even
|
12
|
+
|
13
|
+
start
|
14
|
+
|
15
|
+
new paragraphs
|
16
|
+
|
17
|
+
* `--somearg`=<VALUE>:
|
18
|
+
We can do that too.
|
data/test/document_test.rb
CHANGED
@@ -2,34 +2,87 @@ require 'contest'
|
|
2
2
|
require 'ron/document'
|
3
3
|
|
4
4
|
class DocumentTest < Test::Unit::TestCase
|
5
|
-
SIMPLE_FILE = "#{File.dirname(__FILE__)}/
|
6
|
-
HELLO_DATA = "# hello(1) -- hello world"
|
5
|
+
SIMPLE_FILE = "#{File.dirname(__FILE__)}/basic_document.ron"
|
7
6
|
|
8
|
-
test "
|
7
|
+
test "new with path" do
|
9
8
|
doc = Ron::Document.new(SIMPLE_FILE)
|
10
9
|
assert_equal File.read(SIMPLE_FILE), doc.data
|
11
10
|
end
|
12
11
|
|
13
|
-
test "
|
14
|
-
doc = Ron::Document.new('hello.1.ron') {
|
15
|
-
assert_equal
|
12
|
+
test "new with path and block" do
|
13
|
+
doc = Ron::Document.new('hello.1.ron') { "# hello(1) -- hello world" }
|
14
|
+
assert_equal "# hello(1) -- hello world", doc.data
|
16
15
|
end
|
17
16
|
|
18
|
-
|
17
|
+
test "new with path and block but missing name section" do
|
18
|
+
doc = Ron::Document.new('foo.7.ron') { '' }
|
19
|
+
assert_equal 'foo', doc.name
|
20
|
+
assert_equal '7', doc.section
|
21
|
+
end
|
22
|
+
|
23
|
+
test "new with non conventional path and missing name section" do
|
24
|
+
doc = Ron::Document.new('bar.ron') { '' }
|
25
|
+
assert_equal 'bar', doc.name
|
26
|
+
assert_equal nil, doc.section
|
27
|
+
assert_equal "./bar.html", doc.path_for('html')
|
28
|
+
assert_equal "./bar", doc.path_for('roff')
|
29
|
+
assert_equal "./bar", doc.path_for('')
|
30
|
+
assert_equal "./bar", doc.path_for(nil)
|
31
|
+
end
|
32
|
+
|
33
|
+
test "new with path and name section mismatch" do
|
34
|
+
doc = Ron::Document.new('foo/rick.7.ron') { "# randy(3) -- I'm confused." }
|
35
|
+
assert_equal 'randy', doc.name
|
36
|
+
assert_equal 'rick', doc.path_name
|
37
|
+
assert_equal '3', doc.section
|
38
|
+
assert_equal '7', doc.path_section
|
39
|
+
assert_equal 'rick.7', doc.basename
|
40
|
+
assert_equal 'foo/rick.7.bar', doc.path_for(:bar)
|
41
|
+
end
|
42
|
+
|
43
|
+
test "new with no path and a name section" do
|
44
|
+
doc = Ron::Document.new { "# brandy(5) -- wootderitis" }
|
45
|
+
assert_equal nil, doc.path_name
|
46
|
+
assert_equal nil, doc.path_section
|
47
|
+
assert_equal 'brandy', doc.name
|
48
|
+
assert_equal '5', doc.section
|
49
|
+
assert_equal 'brandy.5', doc.basename
|
50
|
+
assert_equal 'brandy.5.foo', doc.path_for(:foo)
|
51
|
+
end
|
52
|
+
|
53
|
+
context "simple conventionally named document" do
|
19
54
|
setup do
|
20
|
-
@doc = Ron::Document.new('hello.1.ron') {
|
55
|
+
@doc = Ron::Document.new('hello.1.ron') { "# hello(1) -- hello world" }
|
21
56
|
end
|
22
57
|
|
23
58
|
should "load data" do
|
24
|
-
assert_equal
|
59
|
+
assert_equal "# hello(1) -- hello world", @doc.data
|
25
60
|
end
|
26
61
|
|
27
|
-
should "extract the name" do
|
62
|
+
should "extract the manual page name from the filename or document" do
|
28
63
|
assert_equal 'hello', @doc.name
|
29
64
|
end
|
30
65
|
|
31
|
-
should "extract the section" do
|
66
|
+
should "extract the manual page section from the filename or document" do
|
32
67
|
assert_equal '1', @doc.section
|
33
68
|
end
|
69
|
+
|
70
|
+
should "convert to an HTML fragment" do
|
71
|
+
assert_equal %[<h2 id='NAME'>NAME</h2>\n<p><code>hello</code> -- hello world</p>\n],
|
72
|
+
@doc.to_html_fragment
|
73
|
+
end
|
74
|
+
|
75
|
+
should "convert to HTML with a layout" do
|
76
|
+
assert_match %r{^<!DOCTYPE html.*}m, @doc.to_html
|
77
|
+
assert_match %[<h2 id='NAME'>NAME</h2>\n<p><code>hello</code> -- hello world</p>],
|
78
|
+
@doc.to_html
|
79
|
+
end
|
80
|
+
|
81
|
+
should "construct a path to related documents" do
|
82
|
+
assert_equal "./hello.1.html", @doc.path_for(:html)
|
83
|
+
assert_equal "./hello.1", @doc.path_for(:roff)
|
84
|
+
assert_equal "./hello.1", @doc.path_for('')
|
85
|
+
assert_equal "./hello.1", @doc.path_for(nil)
|
86
|
+
end
|
34
87
|
end
|
35
88
|
end
|
data/test/ron_test.rb
CHANGED
@@ -1,21 +1,22 @@
|
|
1
1
|
require 'contest'
|
2
|
+
require 'ron'
|
2
3
|
|
3
|
-
# ron command tests
|
4
4
|
class RonTest < Test::Unit::TestCase
|
5
5
|
testdir = File.dirname(__FILE__)
|
6
6
|
bindir = File.dirname(testdir)
|
7
7
|
ENV['PATH'] = "#{bindir}:#{ENV['PATH']}"
|
8
|
+
ENV['RUBYLIB'] = $LOAD_PATH.join(':')
|
8
9
|
|
9
10
|
SIMPLE_FILE = "#{File.dirname(__FILE__)}/simple.ron"
|
10
11
|
|
11
12
|
test "takes ron text on stdin and produces roff on stdout" do
|
12
|
-
output = `echo '# hello(1) -- hello world' | ron`
|
13
|
+
output = `echo '# hello(1) -- hello world' | ron --date=2009-11-23`
|
13
14
|
lines = output.split("\n")
|
14
15
|
assert_equal 7, lines.size
|
15
|
-
assert_equal %[.\\" generated with Ron], lines.shift
|
16
|
+
assert_equal %[.\\" generated with Ron/v#{Ron::VERSION}], lines.shift
|
16
17
|
assert_equal %[.\\" http://github.com/rtomayko/ron/], lines.shift
|
17
18
|
assert_equal %[.], lines.shift
|
18
|
-
assert_equal %[.TH "HELLO" 1 "" "" ""], lines.shift
|
19
|
+
assert_equal %[.TH "HELLO" 1 "November 2009" "" ""], lines.shift
|
19
20
|
assert_equal %[.], lines.shift
|
20
21
|
assert_equal %[.SH "NAME"], lines.shift
|
21
22
|
assert_equal %[\\fBhello\\fR \\-\\- hello world], lines.shift
|
@@ -24,6 +25,30 @@ class RonTest < Test::Unit::TestCase
|
|
24
25
|
|
25
26
|
test "produces html instead of roff with the --html argument" do
|
26
27
|
output = `echo '# hello(1) -- hello world' | ron --html`
|
27
|
-
assert_match(/<h2 id=
|
28
|
+
assert_match(/<h2 id='NAME'>NAME<\/h2>/, output)
|
29
|
+
end
|
30
|
+
|
31
|
+
test "produces html fragment with the --fragment argument" do
|
32
|
+
output = `echo '# hello(1) -- hello world' | ron --fragment`
|
33
|
+
assert_equal "<h2 id='NAME'>NAME</h2>\n<p><code>hello</code> -- hello world</p>\n",
|
34
|
+
output
|
35
|
+
end
|
36
|
+
|
37
|
+
# file based tests
|
38
|
+
Dir[testdir + '/*.ron'].each do |source|
|
39
|
+
dest = source.sub(/ron$/, 'html')
|
40
|
+
wrong = source.sub(/ron$/, "wrong")
|
41
|
+
test File.basename(source, '.ron') do
|
42
|
+
html = `ron --html --fragment #{source}`
|
43
|
+
expected = File.read(dest) rescue ''
|
44
|
+
if expected != html
|
45
|
+
File.open(wrong, 'wb') { |f| f.write(html) }
|
46
|
+
diff = `diff -u #{dest} #{wrong} 2>/dev/null`
|
47
|
+
fail "the #{dest} file does not exist" if diff.empty?
|
48
|
+
flunk diff
|
49
|
+
elsif File.exist?(wrong)
|
50
|
+
File.unlink(wrong)
|
51
|
+
end
|
52
|
+
end
|
28
53
|
end
|
29
54
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ron
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Tomayko
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-23 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -63,10 +63,20 @@ files:
|
|
63
63
|
- man/markdown.5.ron
|
64
64
|
- man/ron.1.ron
|
65
65
|
- man/ron.5.ron
|
66
|
+
- man/ron.7.ron
|
66
67
|
- ron.gemspec
|
68
|
+
- test/angle_bracket_syntax.html
|
69
|
+
- test/angle_bracket_syntax.ron
|
70
|
+
- test/basic_document.html
|
71
|
+
- test/basic_document.ron
|
72
|
+
- test/custom_title_document.html
|
73
|
+
- test/custom_title_document.ron
|
74
|
+
- test/definition_list_syntax.html
|
75
|
+
- test/definition_list_syntax.ron
|
67
76
|
- test/document_test.rb
|
68
77
|
- test/ron_test.rb
|
69
|
-
- test/
|
78
|
+
- test/titleless_document.html
|
79
|
+
- test/titleless_document.ron
|
70
80
|
has_rdoc: true
|
71
81
|
homepage: http://github.com/rtomayko/ron/
|
72
82
|
licenses: []
|