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 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
+