kramdown-man 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,4 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
4
+ man/kramdown-man.1.md
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ doc/
2
+ pkg/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ before_install:
3
+ - gem install ffi rubygems-tasks rspec yard kramdown
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - jruby-18mode
8
+ - jruby-19mode
9
+ - rbx-18mode
10
+ - rbx-19mode
11
+ script: rake spec
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --markup-provider kramdown --title "kramdown-man Documentation" --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,20 @@
1
+ ### 0.1.3 / 2013-05-05
2
+
3
+ * Initial release:
4
+ * Converts markdown to [roff]:
5
+ * Supports codespans, emphasis and strong fonts.
6
+ * Supports normal and tagged paragraphs.
7
+ * Supports bullet lists.
8
+ * Supports multi-paragraph list items and blockquotes.
9
+ * Supports horizontal rules.
10
+ * Supports converting `[bash](man:bash(1))` links into man page references.
11
+ * Provides Rake task for converting `man/*.md` into man pages.
12
+ * Uses the pure-Ruby [Kramdown][kramdown] markdown parser.
13
+ * Supports [Ruby] 1.8.x, 1.9.x, 2.0.x, [JRuby], [Rubinius].
14
+
15
+ [kramdown]: http://kramdown.rubyforge.org/
16
+ [roff]: http://en.wikipedia.org/wiki/Roff
17
+
18
+ [Ruby]: http://www.ruby-lang.org/
19
+ [JRuby]: http://jruby.org/
20
+ [Rubinius]: http://rubini.us/
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Hal Brodigan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # kramdown-man
2
+
3
+ * [Homepage](https://github.com/postmodern/kramdown-man#readme)
4
+ * [Issues](https://github.com/postmodern/kramdown-man/issues)
5
+ * [Documentation](http://rubydoc.info/gems/kramdown-man/frames)
6
+ * [Email](mailto:postmodern.mod3 at gmail.com)
7
+
8
+ [![Build Status](https://secure.travis-ci.org/postmodern/kramdown-man.png?branch=master)](https://travis-ci.org/postmodern/kramdown-man)
9
+
10
+ ## Description
11
+
12
+ A [Kramdown][kramdown] convert for converting Markdown files into man pages.
13
+
14
+ ## Features
15
+
16
+ * Converts markdown to [roff]:
17
+ * Supports codespans, emphasis and strong fonts.
18
+ * Supports normal and tagged paragraphs.
19
+ * Supports bullet lists.
20
+ * Supports multi-paragraph list items and blockquotes.
21
+ * Supports horizontal rules.
22
+ * Supports converting `[bash](man:bash(1))` links into man page references.
23
+ * Provides Rake task for converting `man/*.md` into man pages.
24
+ * Uses the pure-Ruby [Kramdown][kramdown] markdown parser.
25
+ * Supports [Ruby] 1.8.x, 1.9.x, 2.0.x, [JRuby], [Rubinius].
26
+
27
+ ## Synopsis
28
+
29
+ Render a man page from markdown:
30
+
31
+ $ kramdown-man <man/myprog.1.md >man/myprog.1
32
+
33
+ ## Examples
34
+
35
+ Render a man page from a markdown file:
36
+
37
+ require 'kramdown/man'
38
+
39
+ doc = Kramdown::Document.new(File.read('man/kramdown-man.1.md'))
40
+ File.write('man/kramdown-man.1',doc.to_man)
41
+
42
+ system 'man', 'man/kramdown-man.1'
43
+
44
+ Define a `man` and file tasks which render all `*.md` files within the
45
+ `man/` directory:
46
+
47
+ require 'kramdown/man/task'
48
+ Kramdown::Man::Task.new
49
+
50
+ ## Syntax
51
+
52
+ ### Formatting
53
+
54
+ `code`
55
+
56
+ `code`
57
+
58
+ *emphasis*
59
+
60
+ *emphasis*
61
+
62
+ **strong**
63
+
64
+ **strong**
65
+
66
+ ### Paragraphs
67
+
68
+ Normal paragraph.
69
+
70
+ Normal paragraph.
71
+
72
+ `--tagged`
73
+ Text here.
74
+
75
+ `--tagged`
76
+ Text here.
77
+
78
+ ### Links
79
+
80
+ [website](http://example.com/)
81
+
82
+ [website](http://example.com/)
83
+
84
+ [bash](man:bash(1))
85
+
86
+ [bash](man:bash(1))
87
+
88
+ Email <bob@example.com>
89
+
90
+ Email <bob@example.com>
91
+
92
+ ### Lists
93
+
94
+ * one
95
+ * two
96
+ * three
97
+
98
+ extra paragraph
99
+
100
+
101
+ * one
102
+ * two
103
+ * three
104
+
105
+ extra paragraph
106
+
107
+ 1. one
108
+ 2. two
109
+ 3. three
110
+
111
+ extra paragraph
112
+
113
+ 1. one
114
+ 2. two
115
+ 3. three
116
+
117
+ extra paragraph
118
+
119
+ ### Horizontal Rule
120
+
121
+ -------------------------------------------------------------------------------
122
+
123
+ -------------------------------------------------------------------------------
124
+
125
+ ### Blockquotes
126
+
127
+ > Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
128
+ >
129
+ > --Antoine de Saint-Exupéry
130
+
131
+ > Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
132
+ >
133
+ > --Antoine de Saint-Exupéry
134
+
135
+ ### Code Blocks
136
+
137
+ #include <stdio.h>
138
+
139
+ int main()
140
+ {
141
+ printf("hello world\n");
142
+ return 0;
143
+ }
144
+
145
+ #include <stdio.h>
146
+
147
+ int main()
148
+ {
149
+ printf("hello world\n");
150
+ return 0;
151
+ }
152
+
153
+ ## Requirements
154
+
155
+ * [kramdown] ~> 1.0
156
+
157
+ ## Install
158
+
159
+ $ gem install kramdown-man
160
+
161
+ ## Alternatives
162
+
163
+ * [Redcarpet::Render::ManPage](http://rubydoc.info/gems/redcarpet/Redcarpet/Render/ManPage)
164
+ * [ronn](https://github.com/rtomayko/ronn#readme)
165
+ * [md2man](https://github.com/sunaku/md2man#readme)
166
+
167
+ ## Copyright
168
+
169
+ Copyright (c) 2013 Hal Brodigan
170
+
171
+ See {file:LICENSE.txt} for details.
172
+
173
+ [kramdown]: http://kramdown.rubyforge.org/
174
+ [roff]: http://en.wikipedia.org/wiki/Roff
175
+
176
+ [Ruby]: http://www.ruby-lang.org/
177
+ [JRuby]: http://jruby.org/
178
+ [Rubinius]: http://rubini.us/
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'rake'
5
+
6
+ begin
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ require 'rubygems/tasks'
9
+
10
+ Gem::Tasks.new
11
+ rescue LoadError => e
12
+ warn e.message
13
+ warn "Run `gem install rubygems-tasks` to install Gem::Tasks."
14
+ end
15
+
16
+ begin
17
+ gem 'rspec', '~> 2.4'
18
+ require 'rspec/core/rake_task'
19
+
20
+ RSpec::Core::RakeTask.new
21
+ rescue LoadError => e
22
+ task :spec do
23
+ abort "Please run `gem install rspec` to install RSpec."
24
+ end
25
+ end
26
+
27
+ task :test => :spec
28
+ task :default => :spec
29
+
30
+ begin
31
+ gem 'yard', '~> 0.8'
32
+ require 'yard'
33
+
34
+ YARD::Rake::YardocTask.new
35
+ rescue LoadError => e
36
+ task :yard do
37
+ abort "Please run `gem install yard` to install YARD."
38
+ end
39
+ end
40
+ task :doc => :yard
41
+
42
+ $LOAD_PATH.unshift(File.expand_path('lib'))
43
+
44
+ require 'kramdown/man/tasks'
45
+ Kramdown::Man::Tasks.new
data/bin/kramdown-man ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.expand_path('../lib',File.dirname(__FILE__))
4
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
5
+
6
+ require 'kramdown'
7
+ require 'kramdown/man'
8
+
9
+ case ARGV[0]
10
+ when '-h', '--help'
11
+ warn "usage: #{File.dirname($0)} <INPUT.md >OUTPUT"
12
+ exit
13
+ end
14
+
15
+ doc = Kramdown::Document.new(ARGF.read)
16
+ puts doc.to_man
data/gemspec.yml ADDED
@@ -0,0 +1,15 @@
1
+ name: kramdown-man
2
+ summary: Converts markdown to man pages
3
+ description: A Kramdown converter for converting Markdown files into man pages.
4
+ license: MIT
5
+ authors: Postmodern
6
+ email: postmodern.mod3@gmail.com
7
+ homepage: https://github.com/postmodern/kramdown-man#readme
8
+
9
+ dependencies:
10
+ kramdown: ~> 1.0
11
+
12
+ development_dependencies:
13
+ rspec: ~> 2.4
14
+ rubygems-tasks: ~> 0.2
15
+ yard: ~> 0.8
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'kramdown/man/version'
14
+ Kramdown::Man::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+
24
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
25
+
26
+ gem.files = `git ls-files`.split($/)
27
+ gem.files = glob[gemspec['files']] if gemspec['files']
28
+
29
+ gem.executables = gemspec.fetch('executables') do
30
+ glob['bin/*'].map { |path| File.basename(path) }
31
+ end
32
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
33
+
34
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
35
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
36
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
37
+
38
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
39
+ %w[ext lib].select { |dir| File.directory?(dir) }
40
+ })
41
+
42
+ gem.requirements = gemspec['requirements']
43
+ gem.required_ruby_version = gemspec['required_ruby_version']
44
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
45
+ gem.post_install_message = gemspec['post_install_message']
46
+
47
+ split = lambda { |string| string.split(/,\s*/) }
48
+
49
+ if gemspec['dependencies']
50
+ gemspec['dependencies'].each do |name,versions|
51
+ gem.add_dependency(name,split[versions])
52
+ end
53
+ end
54
+
55
+ if gemspec['development_dependencies']
56
+ gemspec['development_dependencies'].each do |name,versions|
57
+ gem.add_development_dependency(name,split[versions])
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,439 @@
1
+ # encoding: utf-8
2
+ require 'kramdown/man/version'
3
+
4
+ require 'kramdown/converter/base'
5
+
6
+ module Kramdown
7
+ module Converter
8
+ #
9
+ # Converts markdown into a roff man-page.
10
+ #
11
+ class Man < Base
12
+
13
+ # Comment header
14
+ HEADER = [
15
+ ".\\\" Generated by kramdown-man #{::Kramdown::Man::VERSION}",
16
+ ".\\\" https://github.com/postmodern/kramdown-roff#readme"
17
+ ].join("\n")
18
+
19
+ # Typographic Symbols and their UTF8 chars
20
+ TYPOGRAPHIC_SYMS = {
21
+ :ndash => "--",
22
+ :mdash => "—",
23
+ :hellip => "…",
24
+ :laquo => "«",
25
+ :raquo => "»",
26
+ :laquo_space => "«",
27
+ :raquo_space => "»"
28
+ }
29
+
30
+ # Smart Quotes and their UTF8 chars
31
+ SMART_QUOTES = {
32
+ :lsquo => "‘",
33
+ :rsquo => "’",
34
+ :ldquo => "“",
35
+ :rdquo => "”"
36
+ }
37
+
38
+ #
39
+ # Initializes the converter.
40
+ #
41
+ # @param [Kramdown::Element] root
42
+ # The root of the markdown document.
43
+ #
44
+ # @param [Hash] options
45
+ # Markdown options.
46
+ #
47
+ def initialize(root,options)
48
+ super(root,options)
49
+
50
+ @ol_index = 0
51
+ end
52
+
53
+ #
54
+ # Converts the markdown document into a man-page.
55
+ #
56
+ # @param [Kramdown::Element] root
57
+ # The root of a markdown document.
58
+ #
59
+ # @return [String]
60
+ # The roff output.
61
+ #
62
+ def convert(root)
63
+ "#{HEADER}\n#{convert_root(root)}"
64
+ end
65
+
66
+ #
67
+ # Converts the root of a markdown document.
68
+ #
69
+ # @param [Kramdown::Element] root
70
+ # The root of the markdown document.
71
+ #
72
+ # @return [String]
73
+ # The roff output.
74
+ #
75
+ def convert_root(root)
76
+ root.children.map { |child|
77
+ convert_element(child)
78
+ }.compact.join("\n")
79
+ end
80
+
81
+ #
82
+ # Converts an element.
83
+ #
84
+ # @param [Kramdown::Element] element
85
+ # An arbitrary element within the markdown document.
86
+ #
87
+ # @return [String]
88
+ # The roff output.
89
+ #
90
+ def convert_element(element)
91
+ method = "convert_#{element.type}"
92
+ send(method,element) if respond_to?(method)
93
+ end
94
+
95
+ #
96
+ # Converts a `kd:blank` element.
97
+ #
98
+ # @param [Kramdown::Element] blank
99
+ # A `kd:blank` element.
100
+ #
101
+ # @return [String]
102
+ # The roff output.
103
+ #
104
+ def convert_blank(blank)
105
+ '.LP'
106
+ end
107
+
108
+ #
109
+ # Converts a `kd:text` element.
110
+ #
111
+ # @param [Kramdown::Element] text
112
+ # A `kd:text` element.
113
+ #
114
+ # @return [String]
115
+ # The roff output.
116
+ #
117
+ def convert_text(text)
118
+ escape(text.value)
119
+ end
120
+
121
+ #
122
+ # Converts a `kd:typographic_sym` element.
123
+ #
124
+ # @param [Kramdown::Element] sym
125
+ # A `kd:typographic_sym` element.
126
+ #
127
+ # @return [String]
128
+ # The roff output.
129
+ #
130
+ def convert_typographic_sym(sym)
131
+ TYPOGRAPHIC_SYMS[sym.value]
132
+ end
133
+
134
+ #
135
+ # Converts a `kd:smart_quote` element.
136
+ #
137
+ # @param [Kramdown::Element] quote
138
+ # A `kd:smart_quote` element.
139
+ #
140
+ # @return [String]
141
+ # The roff output.
142
+ #
143
+ def convert_smart_quote(quote)
144
+ SMART_QUOTES[quote.value]
145
+ end
146
+
147
+ #
148
+ # Converts a `kd:header` element.
149
+ #
150
+ # @param [Kramdown::Element] header
151
+ # A `kd:header` element.
152
+ #
153
+ # @return [String]
154
+ # The roff output.
155
+ #
156
+ def convert_header(header)
157
+ text = header.options[:raw_text]
158
+
159
+ case header.options[:level]
160
+ when 1 then ".TH #{text}"
161
+ when 2 then ".SH #{text}"
162
+ else ".SS #{text}"
163
+ end
164
+ end
165
+
166
+ #
167
+ # Converts a `kd:hr` element.
168
+ #
169
+ # @param [Kramdown::Element] hr
170
+ # A `kd:hr` element.
171
+ #
172
+ # @return [String]
173
+ # The roff output.
174
+ #
175
+ def convert_hr(hr)
176
+ ".ti 0\n\\l'\\n(.lu'"
177
+ end
178
+
179
+ #
180
+ # Converts a `kd:ul` element.
181
+ #
182
+ # @param [Kramdown::Element] ul
183
+ # A `kd:ul` element.
184
+ #
185
+ # @return [String]
186
+ # The roff output.
187
+ #
188
+ def convert_ul(ul)
189
+ content = ul.children.map { |li| convert_ul_li(li) }.join("\n")
190
+
191
+ return ".RS\n#{content}\n.RE"
192
+ end
193
+
194
+ #
195
+ # Converts a `kd:li` element within a `kd:ul` list.
196
+ #
197
+ # @param [Kramdown::Element] li
198
+ # A `kd:li` element.
199
+ #
200
+ # @return [String]
201
+ # The roff output.
202
+ #
203
+ def convert_ul_li(li)
204
+ li.children.each_with_index.map { |child,index|
205
+ if child.type == :p
206
+ content = convert_children(child.children)
207
+
208
+ if index == 0 then ".IP \\(bu 2\n#{content}"
209
+ else ".IP \\( 2\n#{content}"
210
+ end
211
+ end
212
+ }.compact.join("\n")
213
+ end
214
+
215
+ #
216
+ # Converts a `kd:ol` element.
217
+ #
218
+ # @param [Kramdown::Element] ol
219
+ # A `kd:ol` element.
220
+ #
221
+ # @return [String]
222
+ # The roff output.
223
+ #
224
+ def convert_ol(ol)
225
+ @ol_index += 1
226
+
227
+ header = ".nr step#{@ol_index} 0 1"
228
+ content = ol.children.map { |li| convert_ol_li(li) }.join("\n")
229
+
230
+ return "#{header}\n.RS\n#{content}\n.RE"
231
+ end
232
+
233
+ #
234
+ # Converts a `kd:li` element within a `kd:ol` list.
235
+ #
236
+ # @param [Kramdown::Element] li
237
+ # A `kd:li` element.
238
+ #
239
+ # @return [String]
240
+ # The roff output.
241
+ #
242
+ def convert_ol_li(li)
243
+ li.children.each_with_index.map { |child,index|
244
+ if child.type == :p
245
+ content = convert_children(child.children)
246
+
247
+ if index == 0 then ".IP \\n+[step#{@ol_index}]\n#{content}"
248
+ else ".IP \\n\n#{content}"
249
+ end
250
+ end
251
+ }.compact.join("\n")
252
+ end
253
+
254
+ #
255
+ # Converts a `kd:abbreviation` element.
256
+ #
257
+ # @param [Kramdown::Element] abbr
258
+ # A `kd:abbreviation` element.
259
+ #
260
+ # @return [String]
261
+ # The roff output.
262
+ #
263
+ def convert_abbreviation(abbr)
264
+ escape(abbr.value)
265
+ end
266
+
267
+ #
268
+ # Converts a `kd:blockquote` element.
269
+ #
270
+ # @param [Kramdown::Element] blockquote
271
+ # A `kd:blockquote` element.
272
+ #
273
+ # @return [String]
274
+ # The roff output.
275
+ #
276
+ def convert_blockquote(blockquote)
277
+ content = blockquote.children.map { |child|
278
+ case child.type
279
+ when :p then convert_children(child.children)
280
+ else convert_element(child)
281
+ end
282
+ }.join("\n")
283
+
284
+ return ".PP\n.RS\n#{content}\n.RE"
285
+ end
286
+
287
+ #
288
+ # Converts a `kd:codeblock` element.
289
+ #
290
+ # @param [Kramdown::Element] codeblock
291
+ # A `kd:codeblock` element.
292
+ #
293
+ # @return [String]
294
+ # The roff output.
295
+ #
296
+ def convert_codeblock(codeblock)
297
+ ".nf\n#{escape(codeblock.value).rstrip}\n.fi"
298
+ end
299
+
300
+ #
301
+ # Converts a `kd:comment` element.
302
+ #
303
+ # @param [Kramdown::Element] comment
304
+ # A `kd:comment` element.
305
+ #
306
+ # @return [String]
307
+ # The roff output.
308
+ #
309
+ def convert_comment(comment)
310
+ comment.value.lines.map { |line|
311
+ ".\\\" #{line}"
312
+ }.join("\n")
313
+ end
314
+
315
+ #
316
+ # Converts a `kd:p` element.
317
+ #
318
+ # @param [Kramdown::Element] p
319
+ # A `kd:p` element.
320
+ #
321
+ # @return [String]
322
+ # The roff output.
323
+ #
324
+ def convert_p(p)
325
+ children = p.children
326
+
327
+ if (children.length >= 2) &&
328
+ (children[0].type == :em || children[0].type == :codespan) &&
329
+ (children[1].type == :text && children[1].value =~ /^( |\t)/)
330
+ [
331
+ '.TP',
332
+ convert_element(children[0]),
333
+ convert_text(children[1]).lstrip,
334
+ convert_children(children[2..-1])
335
+ ].join("\n").rstrip
336
+ else
337
+ ".PP\n#{convert_children(children)}"
338
+ end
339
+ end
340
+
341
+ #
342
+ # Converts a `kd:em` element.
343
+ #
344
+ # @param [Kramdown::Element] em
345
+ # A `kd:em` element.
346
+ #
347
+ # @return [String]
348
+ # The roff output.
349
+ #
350
+ def convert_em(em)
351
+ "\\fI#{convert_children(em.children)}\\fP"
352
+ end
353
+
354
+ #
355
+ # Converts a `kd:strong` element.
356
+ #
357
+ # @param [Kramdown::Element] strong
358
+ # A `kd:strong` element.
359
+ #
360
+ # @return [String]
361
+ # The roff output.
362
+ #
363
+ def convert_strong(strong)
364
+ "\\fB#{convert_children(strong.children)}\\fP"
365
+ end
366
+
367
+ #
368
+ # Converts a `kd:codespan` element.
369
+ #
370
+ # @param [Kramdown::Element] codespan
371
+ # A `kd:codespan` element.
372
+ #
373
+ # @return [String]
374
+ # The roff output.
375
+ #
376
+ def convert_codespan(codespan)
377
+ "\\fB\\fC#{codespan.value}\\fR"
378
+ end
379
+
380
+ #
381
+ # Converts a `kd:a` element.
382
+ #
383
+ # @param [Kramdown::Element] a
384
+ # A `kd:a` element.
385
+ #
386
+ # @return [String]
387
+ # The roff output.
388
+ #
389
+ def convert_a(a)
390
+ href = a.attr['href']
391
+ text = convert_children(a.children)
392
+
393
+ case href
394
+ when /^mailto:/
395
+ email = href[7..-1]
396
+
397
+ unless text == email then "#{text}\n.MT #{email}\n.ME"
398
+ else "\n.MT #{email}\n.ME"
399
+ end
400
+ when /^man:/
401
+ match = href.match(/man:([A-Za-z0-9_-]+)(?:\((\d[a-z]?)\))?/)
402
+
403
+ if match[2] then "\n.BR #{match[1]} (#{match[2]})"
404
+ else "\n.BR #{match[1]}"
405
+ end
406
+ else
407
+ "#{text}\n.UR #{href}\n.UE"
408
+ end
409
+ end
410
+
411
+ #
412
+ # Converts the children of an element.
413
+ #
414
+ # @param [Array<Kramdown::Element>] children
415
+ # The children of an element.
416
+ #
417
+ # @return [String]
418
+ # The roff output.
419
+ #
420
+ def convert_children(children)
421
+ children.map { |child| convert_element(child) }.join.strip
422
+ end
423
+
424
+ #
425
+ # Escapes text for roff.
426
+ #
427
+ # @param [String] text
428
+ # The unescaped text.
429
+ #
430
+ # @return [String]
431
+ # The escaped text.
432
+ #
433
+ def escape(text)
434
+ text.gsub('\\','\&\&').gsub('-','\\-')
435
+ end
436
+
437
+ end
438
+ end
439
+ end