kramdown-rfc2629 0.12.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/README.md +59 -0
- data/bin/kramdown-rfc2629 +16 -0
- data/kramdown-rfc2629.gemspec +18 -0
- data/lib/kramdown-rfc2629.rb +420 -0
- metadata +84 -0
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# kramdown-rfc2629
|
2
|
+
|
3
|
+
[kramdown][] is a [markdown][] parser by Thomas Leitner, which has a
|
4
|
+
number of backends for generating HTML, Latex, and markdown again.
|
5
|
+
|
6
|
+
**kramdown-rfc2629** is an additional backend to that: It allows the
|
7
|
+
generation of [RFC 2629][] compliant XML markup (also known as XML2RFC
|
8
|
+
markup).
|
9
|
+
|
10
|
+
Who would care? Anybody who is writing Internet-Drafts and RFCs in
|
11
|
+
the [IETF][] and prefers (or has co-authors who prefer) to do part of
|
12
|
+
their work in markdown.
|
13
|
+
|
14
|
+
# Usage
|
15
|
+
|
16
|
+
Start by installing the kramdown-rfc2629 gem (this requires kramdown
|
17
|
+
version 0.12.0, but has been tested with version 0.11.0 and 0.12.0):
|
18
|
+
|
19
|
+
sudo gem install kramdown-rfc2629
|
20
|
+
|
21
|
+
The guts of kramdown-rfc2629 are in one Ruby file,
|
22
|
+
`lib/kramdown-rfc2629.rb` --- this melds nicely into the extension
|
23
|
+
structure provided by kramdown. `bin/kramdown-rfc2629` is a simple
|
24
|
+
command-line program showing how to use this. For this, you'll need a
|
25
|
+
Ruby 1.9 that can be found under the name "ruby1.9", and maybe XML2RFC
|
26
|
+
if you want to see the fruits of your work.
|
27
|
+
|
28
|
+
kramdown-rfc2629 mydraft.mkd >mydraft.xml
|
29
|
+
xml2rfc mydraft.xml
|
30
|
+
|
31
|
+
# Examples
|
32
|
+
|
33
|
+
`stupid.mkd` is a markdown version of an actual Internet-Draft (for a
|
34
|
+
protocol called [STuPiD][] \[sic!]). This demonstrates some, but not
|
35
|
+
all features of kramdown-rfc2629. Since markdown/kramdown does not
|
36
|
+
cater for all the structure of an RFC 2629 style document, some of the
|
37
|
+
markup is in XML, and the example switches between XML and markdown
|
38
|
+
using kramdown's `{::nomarkdown}` and `{:/nomarkdown}` (this is ugly,
|
39
|
+
but works well enough).
|
40
|
+
|
41
|
+
# Risks and Side-Effects
|
42
|
+
|
43
|
+
The code is not very polished (in particular, the code for tables is a
|
44
|
+
joke), and you probably still need to understand [RFC 2629][] if you
|
45
|
+
want to write an Internet-Draft.
|
46
|
+
|
47
|
+
# License
|
48
|
+
|
49
|
+
(kramdown itself appears to be licensed GPLv3.) As kramdown-rfc2629
|
50
|
+
is in part derived from kramdown source, there is little choice: It is
|
51
|
+
also licensed under GPLv3, which you can google yourself. (Being
|
52
|
+
stuck at GPLv3 does not make me happy, but it is just for this tool so
|
53
|
+
it's probably not going to kill any RFC author.)
|
54
|
+
|
55
|
+
[kramdown]: http://kramdown.rubyforge.org/
|
56
|
+
[stupid]: http://tools.ietf.org/id/draft-hartke-xmpp-stupid-00
|
57
|
+
[RFC 2629]: http://xml.resource.org
|
58
|
+
[markdown]: http://en.wikipedia.org/wiki/Markdown
|
59
|
+
[IETF]: http://www.ietf.org
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby1.9
|
2
|
+
require 'kramdown-rfc2629'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
Encoding.default_external = "UTF-8" # wake up, smell the coffee
|
6
|
+
|
7
|
+
options = {input: 'RFC2629Kramdown'}
|
8
|
+
input = ARGF.read.gsub(/\{::include\s+(.*?)\}/) {
|
9
|
+
File.read($1).chomp
|
10
|
+
}
|
11
|
+
if input =~ /\A<\?xml/ # if this is a whole XML file, protect it
|
12
|
+
input = "{::nomarkdown}\n#{input}\n{:/nomarkdown}\n"
|
13
|
+
end
|
14
|
+
doc = Kramdown::Document.new(input, options)
|
15
|
+
$stderr.puts doc.warnings.to_yaml unless doc.warnings.empty?
|
16
|
+
puts doc.to_rfc2629
|
@@ -0,0 +1,18 @@
|
|
1
|
+
spec = Gem::Specification.new do |s|
|
2
|
+
s.name = 'kramdown-rfc2629'
|
3
|
+
s.version = '0.12.1'
|
4
|
+
s.summary = "Kramdown extension for generating RFC 2629 XML."
|
5
|
+
s.description = %{An RFC2629 (XML2RFC) generating backend for Thomas Leitner's
|
6
|
+
"kramdown" markdown parser. Mostly useful for RFC writers.}
|
7
|
+
s.add_dependency('kramdown', '~> 0.12')
|
8
|
+
s.files = Dir['lib/**/*.rb'] + %w(README.md kramdown-rfc2629.gemspec bin/kramdown-rfc2629)
|
9
|
+
s.require_path = 'lib'
|
10
|
+
s.executables = ['kramdown-rfc2629']
|
11
|
+
s.default_executable = 'kramdown-rfc2629'
|
12
|
+
s.required_ruby_version = '>= 1.9.2'
|
13
|
+
s.requirements = 'wget'
|
14
|
+
# s.has_rdoc = true
|
15
|
+
s.author = "Carsten Bormann"
|
16
|
+
s.email = "cabo@tzi.org"
|
17
|
+
s.homepage = "http://github.com/cabo/kramdown-rfc2629"
|
18
|
+
end
|
@@ -0,0 +1,420 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2010 Carsten Bormann <cabo@tzi.org>
|
5
|
+
#
|
6
|
+
# This file is designed to work with kramdown.
|
7
|
+
# License: GPLv3, unfortunately (look it up).
|
8
|
+
# Any code that I haven't stolen from kramdown is also licensed under
|
9
|
+
# the 2-clause BSD license (look it up).
|
10
|
+
#++
|
11
|
+
#
|
12
|
+
|
13
|
+
raise "sorry, 1.8 was last decade" unless RUBY_VERSION >= '1.9'
|
14
|
+
|
15
|
+
# this version is adapted to kramdown 0.12.0
|
16
|
+
gem 'kramdown', '= 0.12.0'
|
17
|
+
require 'kramdown'
|
18
|
+
|
19
|
+
require 'rexml/parsers/baseparser'
|
20
|
+
|
21
|
+
class Object
|
22
|
+
def deep_clone
|
23
|
+
Marshal.load(Marshal.dump(self))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Kramdown
|
28
|
+
|
29
|
+
module Parser
|
30
|
+
class RFC2629Kramdown < Kramdown
|
31
|
+
|
32
|
+
def initialize(*doc)
|
33
|
+
super
|
34
|
+
@span_parsers.unshift(:xref)
|
35
|
+
end
|
36
|
+
|
37
|
+
XREF_START = /\{\{(.*?)\}\}/u
|
38
|
+
|
39
|
+
# Introduce new {{target}} syntax for empty xrefs, which would
|
40
|
+
# otherwise be an ugly  or 
|
41
|
+
# (I'd rather use [[target]], but that somehow clashes with links.)
|
42
|
+
def parse_xref
|
43
|
+
@src.pos += @src.matched_size
|
44
|
+
href = @src[1]
|
45
|
+
el = Element.new(:xref, nil, {'target' => href})
|
46
|
+
@tree.children << el
|
47
|
+
end
|
48
|
+
define_parser(:xref, XREF_START, '{{')
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Element
|
54
|
+
def rfc2629_fix
|
55
|
+
if a = attr
|
56
|
+
if anchor = a.delete('id')
|
57
|
+
a['anchor'] = anchor
|
58
|
+
end
|
59
|
+
if anchor = a.delete('href')
|
60
|
+
a['target'] = anchor
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module Converter
|
67
|
+
|
68
|
+
# Converts a Kramdown::Document to HTML.
|
69
|
+
class Rfc2629 < Base
|
70
|
+
|
71
|
+
# we use these to do XML stuff, too (XXX: 0.11 vs. 0.12)
|
72
|
+
include ::Kramdown::Utils::HTML rescue include ::Kramdown::Utils::Html
|
73
|
+
|
74
|
+
def el_html_attributes(el)
|
75
|
+
html_attributes(el) rescue html_attributes(el.attr) # XXX 0.11 vs. 0.12
|
76
|
+
end
|
77
|
+
|
78
|
+
# :stopdoc:
|
79
|
+
|
80
|
+
# Defines the amount of indentation used when nesting XML tags.
|
81
|
+
INDENTATION = 2
|
82
|
+
|
83
|
+
# Initialize the XML converter with the given Kramdown document +doc+.
|
84
|
+
def initialize(*doc)
|
85
|
+
super
|
86
|
+
@sec_level = 1
|
87
|
+
@in_dt = 0
|
88
|
+
end
|
89
|
+
|
90
|
+
def convert(el, indent = -INDENTATION, opts = {})
|
91
|
+
if el.children[-1].type == :raw
|
92
|
+
raw = convert1(el.children.pop, indent, opts)
|
93
|
+
end
|
94
|
+
"#{convert1(el, indent, opts)}#{end_sections(1, indent)}#{raw}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def convert1(el, indent, opts = {})
|
98
|
+
el.rfc2629_fix
|
99
|
+
send("convert_#{el.type}", el, indent, opts)
|
100
|
+
end
|
101
|
+
|
102
|
+
def inner_a(el, indent, opts)
|
103
|
+
indent += INDENTATION
|
104
|
+
el.children.map do |inner_el|
|
105
|
+
inner_el.rfc2629_fix
|
106
|
+
send("convert_#{inner_el.type}", inner_el, indent, opts)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def inner(el, indent, opts)
|
111
|
+
inner_a(el, indent, opts).join('')
|
112
|
+
end
|
113
|
+
|
114
|
+
def convert_blank(el, indent, opts)
|
115
|
+
"\n"
|
116
|
+
end
|
117
|
+
|
118
|
+
def convert_text(el, indent, opts)
|
119
|
+
escape_html(el.value, :text)
|
120
|
+
end
|
121
|
+
|
122
|
+
def convert_p(el, indent, opts)
|
123
|
+
if (el.children.size == 1 && el.children[0].type == :img) || opts[:unpacked]
|
124
|
+
inner(el, indent, opts) # Part of the bad reference hack
|
125
|
+
else
|
126
|
+
"#{' '*indent}<t#{el_html_attributes(el)}>#{inner(el, indent, opts)}</t>\n"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def saner_generate_id(value)
|
131
|
+
generate_id(value).gsub(/-+/, '-')
|
132
|
+
end
|
133
|
+
|
134
|
+
def convert_codeblock(el, indent, opts)
|
135
|
+
el.attr['anchor'] ||= saner_generate_id(el.value)
|
136
|
+
result = el.value
|
137
|
+
# compensate for XML2RFC idiosyncracy by insisting on a blank line
|
138
|
+
unless el.attr.delete('tight')
|
139
|
+
result[0,0] = "\n" unless result[0,1] == "\n"
|
140
|
+
end
|
141
|
+
"#{' '*indent}<figure#{el_html_attributes(el)}><artwork><![CDATA[#{result}#{result =~ /\n\Z/ ? '' : "\n"}]]></artwork></figure>\n"
|
142
|
+
end
|
143
|
+
|
144
|
+
def convert_blockquote(el, indent, opts)
|
145
|
+
"#{' '*indent}<t><list style='empty'#{el_html_attributes(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</list></t>\n"
|
146
|
+
end
|
147
|
+
|
148
|
+
def end_sections(to_level, indent)
|
149
|
+
if indent < 0
|
150
|
+
indent = 0
|
151
|
+
end
|
152
|
+
if @sec_level >= to_level
|
153
|
+
delta = (@sec_level - to_level)
|
154
|
+
@sec_level = to_level
|
155
|
+
"#{' '*indent}</section>\n" * delta
|
156
|
+
else
|
157
|
+
$stderr.puts "Incorrect section nesting: Need to start with 1"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def convert_header(el, indent, opts)
|
162
|
+
# todo: handle appendix tags
|
163
|
+
el = el.deep_clone
|
164
|
+
options = @doc ? @doc.options : @options # XXX: 0.11 vs. 0.12
|
165
|
+
if options[:auto_ids] && !el.attr['anchor']
|
166
|
+
el.attr['anchor'] = saner_generate_id(el.options[:raw_text])
|
167
|
+
end
|
168
|
+
el.attr['title'] = inner(el, indent, opts)
|
169
|
+
"#{end_sections(el.options[:level], indent)}#{' '*indent}<section#{@sec_level += 1; el_html_attributes(el)}>\n"
|
170
|
+
end
|
171
|
+
|
172
|
+
def convert_hr(el, indent, opts) # misuse for page break
|
173
|
+
"#{' '*indent}<t><vspace blankLines='999' /></t>\n"
|
174
|
+
end
|
175
|
+
|
176
|
+
STYLES = {ul: 'symbols', ol: 'numbers', dl: 'hanging'}
|
177
|
+
|
178
|
+
def convert_ul(el, indent, opts)
|
179
|
+
style = STYLES[el.type]
|
180
|
+
"#{' '*indent}<t><list style='#{style}'#{el_html_attributes(el)}>\n#{inner(el, indent, opts)}#{' '*indent}</list></t>\n"
|
181
|
+
end
|
182
|
+
alias :convert_ol :convert_ul
|
183
|
+
alias :convert_dl :convert_ul
|
184
|
+
|
185
|
+
def convert_li(el, indent, opts)
|
186
|
+
res_a = inner_a(el, indent, opts)
|
187
|
+
if el.children.empty? || el.children.first.options[:category] == :span
|
188
|
+
res = res_a.join('')
|
189
|
+
else # merge multiple <t> elements
|
190
|
+
res = res_a.select { |x|
|
191
|
+
x.strip != ''
|
192
|
+
}.map { |x|
|
193
|
+
x.sub(/\A\s*<t>(.*)<\/t>\s*\Z/m) { $1}
|
194
|
+
}.join("#{' '*indent}<vspace blankLines='1'/>\n").gsub(%r{(</list>)\s*<vspace blankLines='1'/>}) { $1 }.gsub(%r{<vspace blankLines='1'/>\s*(<list)}) { $1 }
|
195
|
+
end
|
196
|
+
"#{' '*indent}<t#{el_html_attributes(el)}>#{res}#{(res =~ /\n\Z/ ? ' '*indent : '')}</t>\n"
|
197
|
+
end
|
198
|
+
def convert_dd(el, indent, opts)
|
199
|
+
output = ' '*indent
|
200
|
+
if @in_dt == 1
|
201
|
+
@in_dt = 0
|
202
|
+
else
|
203
|
+
output << "<t#{el_html_attributes(el)}>"
|
204
|
+
end
|
205
|
+
res = inner(el, indent+INDENTATION, opts.merge(unpacked: true))
|
206
|
+
# if el.children.empty? || el.children.first.options[:category] != :block
|
207
|
+
output << res << (res =~ /\n\Z/ ? ' '*indent : '')
|
208
|
+
# else FIXME: The latter case is needed for more complex cases
|
209
|
+
# output << "\n" << res << ' '*indent
|
210
|
+
# end
|
211
|
+
output << "</t>\n"
|
212
|
+
end
|
213
|
+
|
214
|
+
def convert_dt(el, indent, opts) # SERIOUSLY BAD HACK:
|
215
|
+
close = "#{' '*indent}</t>\n" * @in_dt
|
216
|
+
@in_dt = 1
|
217
|
+
"#{close}#{' '*indent}<t#{el_html_attributes(el)} hangText='#{inner(el, indent, opts)}'>\n"
|
218
|
+
end
|
219
|
+
|
220
|
+
HTML_TAGS_WITH_BODY=['div', 'script']
|
221
|
+
|
222
|
+
def convert_html_element(el, indent, opts)
|
223
|
+
res = inner(el, indent, opts)
|
224
|
+
if el.options[:category] == :span
|
225
|
+
"<#{el.value}#{el_html_attributes(el)}" << (!res.empty? ? ">#{res}</#{el.value}>" : " />")
|
226
|
+
else
|
227
|
+
output = ''
|
228
|
+
output << ' '*indent if !el.options[:parent_is_raw]
|
229
|
+
output << "<#{el.value}#{el_html_attributes(el)}"
|
230
|
+
if !res.empty? && el.options[:parse_type] != :block
|
231
|
+
output << ">#{res}</#{el.value}>"
|
232
|
+
elsif !res.empty?
|
233
|
+
output << ">\n#{res}" << ' '*indent << "</#{el.value}>"
|
234
|
+
elsif HTML_TAGS_WITH_BODY.include?(el.value)
|
235
|
+
output << "></#{el.value}>"
|
236
|
+
else
|
237
|
+
output << " />"
|
238
|
+
end
|
239
|
+
output << "\n" if el.options[:outer_element] || !el.options[:parent_is_raw]
|
240
|
+
output
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def convert_xml_comment(el, indent, opts)
|
245
|
+
if el.options[:category] == :block && !el.options[:parent_is_raw]
|
246
|
+
' '*indent + el.value + "\n"
|
247
|
+
else
|
248
|
+
el.value
|
249
|
+
end
|
250
|
+
end
|
251
|
+
alias :convert_xml_pi :convert_xml_comment
|
252
|
+
alias :convert_html_doctype :convert_xml_comment
|
253
|
+
|
254
|
+
ALIGNMENTS = { default: :left, left: :left, right: :right, center: :center}
|
255
|
+
|
256
|
+
def convert_table(el, indent, opts) # This only works for tables with headers
|
257
|
+
alignment = el.options[:alignment].map { |al| ALIGNMENTS[al]}
|
258
|
+
"#{' '*indent}<texttable#{el_html_attributes(el)}>\n#{inner(el, indent, opts.merge(table_alignment: alignment))}#{' '*indent}</texttable>\n"
|
259
|
+
end
|
260
|
+
|
261
|
+
def convert_thead(el, indent, opts)
|
262
|
+
inner(el, indent, opts)
|
263
|
+
end
|
264
|
+
alias :convert_tbody :convert_thead
|
265
|
+
alias :convert_tfoot :convert_thead
|
266
|
+
alias :convert_tr :convert_thead
|
267
|
+
|
268
|
+
def convert_td(el, indent, opts)
|
269
|
+
if alignment = opts[:table_alignment]
|
270
|
+
alignment = alignment.shift
|
271
|
+
end
|
272
|
+
res = inner(el, indent, opts)
|
273
|
+
if alignment
|
274
|
+
"#{' '*indent}<ttcol align='#{alignment}'#{el_html_attributes(el)}>#{res.empty? ? " " : res}</ttcol>\n"
|
275
|
+
else
|
276
|
+
"#{' '*indent}<c#{el_html_attributes(el)}>#{res.empty? ? " " : res}</c>\n"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
alias :convert_th :convert_td
|
280
|
+
|
281
|
+
def convert_comment(el, indent, opts)
|
282
|
+
## Don't actually output all those comments into the XML:
|
283
|
+
# if el.options[:category] == :block
|
284
|
+
# "#{' '*indent}<!-- #{el.value} -->\n"
|
285
|
+
# else
|
286
|
+
# "<!-- #{el.value} -->"
|
287
|
+
# end
|
288
|
+
end
|
289
|
+
|
290
|
+
def convert_br(el, indent, opts)
|
291
|
+
"<br />"
|
292
|
+
end
|
293
|
+
|
294
|
+
def convert_a(el, indent, opts)
|
295
|
+
do_obfuscation = el.attr['href'] =~ /^mailto:/
|
296
|
+
if do_obfuscation
|
297
|
+
el = el.deep_clone
|
298
|
+
href = obfuscate(el.attr['href'].sub(/^mailto:/, ''))
|
299
|
+
mailto = obfuscate('mailto')
|
300
|
+
el.attr['href'] = "#{mailto}:#{href}"
|
301
|
+
end
|
302
|
+
res = inner(el, indent, opts)
|
303
|
+
res = obfuscate(res) if do_obfuscation
|
304
|
+
"<eref#{el_html_attributes(el)}>#{res}</eref>"
|
305
|
+
end
|
306
|
+
|
307
|
+
def convert_xref(el, indent, opts)
|
308
|
+
"<xref#{el_html_attributes(el)}/>"
|
309
|
+
end
|
310
|
+
|
311
|
+
REFCACHEDIR = ".refcache"
|
312
|
+
def get_and_cache_resource(url, tn = Time.now, tvalid = 7200)
|
313
|
+
Dir.mkdir(REFCACHEDIR) unless Dir.exists?(REFCACHEDIR)
|
314
|
+
fn = "#{REFCACHEDIR}/#{File.basename(url)}"
|
315
|
+
f = File.stat(fn) rescue nil
|
316
|
+
if !f || tn - f.ctime >= tvalid
|
317
|
+
$stderr.puts "#{fn}: #{f && tn-f.ctime}"
|
318
|
+
`cd #{REFCACHEDIR}; wget -Nnv "#{url}"` # ignore errors if offline (hack)
|
319
|
+
File.utime nil, nil, fn
|
320
|
+
end
|
321
|
+
File.read(fn)
|
322
|
+
end
|
323
|
+
|
324
|
+
def convert_img(el, indent, opts) # misuse the tag!
|
325
|
+
if a = el.attr
|
326
|
+
alt = a.delete('alt').strip
|
327
|
+
alt = '' if alt == '!' # work around re-wrap uglyness
|
328
|
+
if anchor = a.delete('src')
|
329
|
+
a['target'] = anchor
|
330
|
+
end
|
331
|
+
end
|
332
|
+
if alt == ":include:" # Really bad misuse of tag...
|
333
|
+
to_insert = ""
|
334
|
+
anchor.scan(/([A-Z-]+)[.]?([a-z0-9-]+)/) do |t, n|
|
335
|
+
fn = "reference.#{t}.#{n}.xml"
|
336
|
+
sub = { "RFC" => "bibxml", "I-D" => "bibxml3" }[t]
|
337
|
+
puts "Huh: ${fn}" unless sub
|
338
|
+
url = "http://xml.resource.org/public/rfc/#{sub}/#{fn}"
|
339
|
+
to_insert = get_and_cache_resource(url)
|
340
|
+
end
|
341
|
+
to_insert.gsub(/<\?xml version='1.0' encoding='UTF-8'\?>/, '')
|
342
|
+
else
|
343
|
+
"<xref#{el_html_attributes(el)}>#{alt}</xref>"
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def convert_codespan(el, indent, opts)
|
348
|
+
"<spanx style='verb'#{el_html_attributes(el)}>#{escape_html(el.value)}</spanx>"
|
349
|
+
end
|
350
|
+
|
351
|
+
def convert_footnote(el, indent, opts) # XXX: This is wrong.
|
352
|
+
"<xref target='#{escape_html(el.value)}'#{el_html_attributes(el)}/>"
|
353
|
+
end
|
354
|
+
|
355
|
+
def convert_raw(el, indent, opts)
|
356
|
+
end_sections(1, indent) +
|
357
|
+
el.value + (el.options[:category] == :block ? "\n" : '')
|
358
|
+
end
|
359
|
+
|
360
|
+
EMPH = { em: "emph", strong: "strong"}
|
361
|
+
|
362
|
+
def convert_em(el, indent, opts)
|
363
|
+
"<spanx style='#{EMPH[el.type]}'#{el_html_attributes(el)}>#{inner(el, indent, opts)}</spanx>"
|
364
|
+
end
|
365
|
+
alias :convert_strong :convert_em
|
366
|
+
|
367
|
+
def convert_entity(el, indent, opts)
|
368
|
+
entity_to_str(el.value)
|
369
|
+
end
|
370
|
+
|
371
|
+
TYPOGRAPHIC_SYMS = {
|
372
|
+
:mdash => [::Kramdown::Utils::Entities.entity('mdash')],
|
373
|
+
:ndash => [::Kramdown::Utils::Entities.entity('ndash')],
|
374
|
+
:hellip => [::Kramdown::Utils::Entities.entity('hellip')],
|
375
|
+
:laquo_space => [::Kramdown::Utils::Entities.entity('laquo'), ::Kramdown::Utils::Entities.entity('nbsp')],
|
376
|
+
:raquo_space => [::Kramdown::Utils::Entities.entity('nbsp'), ::Kramdown::Utils::Entities.entity('raquo')],
|
377
|
+
:laquo => [::Kramdown::Utils::Entities.entity('laquo')],
|
378
|
+
:raquo => [::Kramdown::Utils::Entities.entity('raquo')]
|
379
|
+
}
|
380
|
+
def convert_typographic_sym(el, indent, opts)
|
381
|
+
TYPOGRAPHIC_SYMS[el.value].map {|e| entity_to_str(e)}.join('')
|
382
|
+
end
|
383
|
+
|
384
|
+
def convert_smart_quote(el, indent, opts)
|
385
|
+
entity_to_str(::Kramdown::Utils::Entities.entity(el.value.to_s))
|
386
|
+
end
|
387
|
+
|
388
|
+
def convert_math(el, indent, opts) # XXX: This is wrong
|
389
|
+
el = el.deep_clone
|
390
|
+
el.attr['class'] ||= ''
|
391
|
+
el.attr['class'] += (el.attr['class'].empty? ? '' : ' ') + 'math'
|
392
|
+
type = 'span'
|
393
|
+
type = 'div' if el.options[:category] == :block
|
394
|
+
"<#{type}#{el_html_attributes(el)}>#{escape_html(el.value, :text)}</#{type}>#{type == 'div' ? "\n" : ''}"
|
395
|
+
end
|
396
|
+
|
397
|
+
def convert_abbreviation(el, indent, opts) # XXX: This is wrong
|
398
|
+
title = @doc.parse_infos[:abbrev_defs][el.value]
|
399
|
+
title = nil if title.empty?
|
400
|
+
"<abbr#{title ? " title=\"#{title}\"" : ''}>#{el.value}</abbr>"
|
401
|
+
end
|
402
|
+
|
403
|
+
def convert_root(el, indent, opts)
|
404
|
+
result = inner(el, indent, opts)
|
405
|
+
end
|
406
|
+
|
407
|
+
# Helper method for obfuscating the +text+ by using XML entities.
|
408
|
+
def obfuscate(text)
|
409
|
+
result = ""
|
410
|
+
text.each_byte do |b|
|
411
|
+
result += (b > 128 ? b.chr : "&#%03d;" % b)
|
412
|
+
end
|
413
|
+
result.force_encoding(text.encoding) if RUBY_VERSION >= '1.9'
|
414
|
+
result
|
415
|
+
end
|
416
|
+
|
417
|
+
end
|
418
|
+
|
419
|
+
end
|
420
|
+
end
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kramdown-rfc2629
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 12
|
8
|
+
- 1
|
9
|
+
version: 0.12.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Carsten Bormann
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-04 00:00:00 +01:00
|
18
|
+
default_executable: kramdown-rfc2629
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: kramdown
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
- 12
|
31
|
+
version: "0.12"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: |-
|
35
|
+
An RFC2629 (XML2RFC) generating backend for Thomas Leitner's
|
36
|
+
"kramdown" markdown parser. Mostly useful for RFC writers.
|
37
|
+
email: cabo@tzi.org
|
38
|
+
executables:
|
39
|
+
- kramdown-rfc2629
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- lib/kramdown-rfc2629.rb
|
46
|
+
- README.md
|
47
|
+
- kramdown-rfc2629.gemspec
|
48
|
+
- bin/kramdown-rfc2629
|
49
|
+
has_rdoc: true
|
50
|
+
homepage: http://github.com/cabo/kramdown-rfc2629
|
51
|
+
licenses: []
|
52
|
+
|
53
|
+
post_install_message:
|
54
|
+
rdoc_options: []
|
55
|
+
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
segments:
|
64
|
+
- 1
|
65
|
+
- 9
|
66
|
+
- 2
|
67
|
+
version: 1.9.2
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
requirements:
|
77
|
+
- wget
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.3.7
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Kramdown extension for generating RFC 2629 XML.
|
83
|
+
test_files: []
|
84
|
+
|