kramdown-rfc2629 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
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 ![!](target) or ![ ](target)
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? ? "&#160;" : res}</ttcol>\n"
275
+ else
276
+ "#{' '*indent}<c#{el_html_attributes(el)}>#{res.empty? ? "&#160;" : 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
+