kramdown 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kramdown might be problematic. Click here for more details.

Files changed (44) hide show
  1. data/ChangeLog +276 -0
  2. data/Rakefile +2 -2
  3. data/VERSION +1 -1
  4. data/benchmark/benchmark.rb +1 -1
  5. data/benchmark/historic-jruby-1.4.0.dat +7 -7
  6. data/benchmark/historic-ruby-1.8.6.dat +7 -7
  7. data/benchmark/historic-ruby-1.8.7.dat +7 -7
  8. data/benchmark/historic-ruby-1.9.1p243.dat +7 -7
  9. data/benchmark/historic-ruby-1.9.2dev.dat +7 -7
  10. data/bin/kramdown +46 -1
  11. data/doc/index.page +2 -2
  12. data/doc/syntax.page +7 -3
  13. data/lib/kramdown/converter.rb +6 -285
  14. data/lib/kramdown/converter/base.rb +75 -0
  15. data/lib/kramdown/converter/html.rb +325 -0
  16. data/lib/kramdown/converter/latex.rb +516 -0
  17. data/lib/kramdown/document.rb +36 -66
  18. data/lib/kramdown/options.rb +262 -0
  19. data/lib/kramdown/parser/kramdown.rb +36 -17
  20. data/lib/kramdown/parser/kramdown/attribute_list.rb +1 -1
  21. data/lib/kramdown/parser/kramdown/autolink.rb +1 -1
  22. data/lib/kramdown/parser/kramdown/codespan.rb +1 -1
  23. data/lib/kramdown/parser/kramdown/emphasis.rb +2 -2
  24. data/lib/kramdown/parser/kramdown/escaped_chars.rb +2 -2
  25. data/lib/kramdown/parser/kramdown/extension.rb +46 -2
  26. data/lib/kramdown/parser/kramdown/footnote.rb +1 -1
  27. data/lib/kramdown/parser/kramdown/html.rb +2 -2
  28. data/lib/kramdown/parser/kramdown/html_entity.rb +4 -5
  29. data/lib/kramdown/parser/kramdown/line_break.rb +1 -1
  30. data/lib/kramdown/parser/kramdown/link.rb +2 -2
  31. data/lib/kramdown/parser/kramdown/smart_quotes.rb +213 -0
  32. data/lib/kramdown/parser/kramdown/typographic_symbol.rb +1 -1
  33. data/lib/kramdown/version.rb +1 -1
  34. data/test/testcases/encoding.html +46 -0
  35. data/test/testcases/encoding.text +28 -0
  36. data/test/testcases/span/01_link/inline.html +1 -1
  37. data/test/testcases/span/01_link/reference.html +2 -2
  38. data/test/testcases/span/escaped_chars/normal.html +4 -0
  39. data/test/testcases/span/escaped_chars/normal.text +4 -0
  40. data/test/testcases/span/text_substitutions/entities.html +1 -1
  41. data/test/testcases/span/text_substitutions/typography.html +12 -0
  42. data/test/testcases/span/text_substitutions/typography.text +12 -0
  43. metadata +9 -3
  44. data/lib/kramdown/extension.rb +0 -98
@@ -95,7 +95,7 @@ module Kramdown
95
95
  add_text(@src.matched)
96
96
  end
97
97
  end
98
- define_parser(:span_ial, IAL_SPAN_START)
98
+ define_parser(:span_ial, IAL_SPAN_START, '\{:')
99
99
 
100
100
  end
101
101
  end
@@ -35,7 +35,7 @@ module Kramdown
35
35
  add_text(@src[1].sub(/^mailto:/, ''), el)
36
36
  @tree.children << el
37
37
  end
38
- define_parser(:autolink, AUTOLINK_START)
38
+ define_parser(:autolink, AUTOLINK_START, '<')
39
39
 
40
40
  end
41
41
  end
@@ -50,7 +50,7 @@ module Kramdown
50
50
  add_text(result)
51
51
  end
52
52
  end
53
- define_parser(:codespan, CODESPAN_DELIMITER)
53
+ define_parser(:codespan, CODESPAN_DELIMITER, '`')
54
54
 
55
55
  end
56
56
  end
@@ -42,7 +42,7 @@ module Kramdown
42
42
  el = Element.new(elem)
43
43
  stop_re = /#{Regexp.escape(delim)}/
44
44
  found = parse_spans(el, stop_re) do
45
- (@src.string[@src.pos-1, 1] !~ /\s/) &&
45
+ (@src.pre_match[-1, 1] !~ /\s/) &&
46
46
  (elem != :em || !@src.match?(/#{Regexp.escape(delim*2)}(?!#{Regexp.escape(delim)})/)) &&
47
47
  (type != '_' || !@src.match?(/#{Regexp.escape(delim)}[[:alpha:]]/)) && el.children.size > 0
48
48
  end
@@ -62,7 +62,7 @@ module Kramdown
62
62
  add_text(result)
63
63
  end
64
64
  end
65
- define_parser(:emphasis, EMPHASIS_START)
65
+ define_parser(:emphasis, EMPHASIS_START, '\*|_')
66
66
 
67
67
  end
68
68
  end
@@ -24,14 +24,14 @@ module Kramdown
24
24
  module Parser
25
25
  class Kramdown
26
26
 
27
- ESCAPED_CHARS = /\\([\\.*_+`()\[\]{}#!:|-])/
27
+ ESCAPED_CHARS = /\\([\\.*_+`()\[\]{}#!:|"'-])/
28
28
 
29
29
  # Parse the backslash-escaped character at the current location.
30
30
  def parse_escaped_chars
31
31
  @src.pos += @src.matched_size
32
32
  add_text(@src[1])
33
33
  end
34
- define_parser(:escaped_chars, ESCAPED_CHARS)
34
+ define_parser(:escaped_chars, ESCAPED_CHARS, '\\\\')
35
35
 
36
36
  end
37
37
  end
@@ -26,6 +26,50 @@ module Kramdown
26
26
  module Parser
27
27
  class Kramdown
28
28
 
29
+ # The base extension class.
30
+ #
31
+ # This class provides implementations for the default extensions defined in the kramdown
32
+ # specification.
33
+ #
34
+ # An extension is a method called <tt>parse_EXTNAME</tt> where +EXTNAME+ is the extension name.
35
+ # These methods are called with three parameters:
36
+ #
37
+ # [+parser+]
38
+ # The parser instance from which the extension method is called.
39
+ # [+opts+]
40
+ # A hash containing the options set in the extension.
41
+ # [+body+]
42
+ # A string containing the body of the extension. If no body is available, this is +nil+.
43
+ class Extension
44
+
45
+ # Just ignore everything and do nothing.
46
+ def parse_comment(parser, opts, body)
47
+ nil
48
+ end
49
+
50
+ # Add the body (if available) as <tt>:raw</tt> Element to the +parser.tree+.
51
+ def parse_nomarkdown(parser, opts, body)
52
+ parser.tree.children << Element.new(:raw, body) if body.kind_of?(String)
53
+ end
54
+
55
+ # Update the document and parser options with the options set in +opts+.
56
+ def parse_options(parser, opts, body)
57
+ opts.select do |k,v|
58
+ k = k.to_sym
59
+ if Kramdown::Options.defined?(k)
60
+ parser.doc.options[k] = Kramdown::Options.parse(k, v) rescue parser.doc.options[k]
61
+ false
62
+ else
63
+ true
64
+ end
65
+ end.each do |k,v|
66
+ parser.warning("Unknown kramdown option '#{k}'")
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+
29
73
  EXT_BLOCK_START_STR = "^#{OPT_SPACE}\\{::(%s):(:)?(#{ALD_ANY_CHARS}*)\\}\s*?\n"
30
74
  EXT_BLOCK_START = /#{EXT_BLOCK_START_STR % ALD_ID_NAME}/
31
75
 
@@ -38,7 +82,7 @@ module Kramdown
38
82
  body = nil
39
83
  parse_attribute_list(@src[3], opts)
40
84
 
41
- if !@doc.extension.public_methods.map {|m| m.to_s}.include?("parse_#{ext}")
85
+ if !@extension.public_methods.map {|m| m.to_s}.include?("parse_#{ext}")
42
86
  warning("No extension named '#{ext}' found - ignoring extension block")
43
87
  body = :invalid
44
88
  end
@@ -54,7 +98,7 @@ module Kramdown
54
98
  end
55
99
  end
56
100
 
57
- @doc.extension.send("parse_#{ext}", self, opts, body) if body != :invalid
101
+ @extension.send("parse_#{ext}", self, opts, body) if body != :invalid
58
102
 
59
103
  true
60
104
  end
@@ -66,7 +66,7 @@ module Kramdown
66
66
  add_text(@src.matched)
67
67
  end
68
68
  end
69
- define_parser(:footnote_marker, FOOTNOTE_MARKER_START)
69
+ define_parser(:footnote_marker, FOOTNOTE_MARKER_START, '\[')
70
70
 
71
71
  end
72
72
  end
@@ -146,7 +146,7 @@ module Kramdown
146
146
  end
147
147
  elsif parse_type == :span
148
148
  if result = @src.scan_until(/(?=<\/#{el.value}\s*>)/m)
149
- add_text(@src.string[curpos...@src.pos], el)
149
+ add_text(extract_string(curpos...@src.pos), el)
150
150
  @src.scan(HTML_TAG_CLOSE_RE)
151
151
  else
152
152
  add_text(@src.scan(/.*/m), el)
@@ -246,7 +246,7 @@ module Kramdown
246
246
  add_text(@src.scan(/./))
247
247
  end
248
248
  end
249
- define_parser(:span_html, HTML_SPAN_START)
249
+ define_parser(:span_html, HTML_SPAN_START, '<')
250
250
 
251
251
  end
252
252
  end
@@ -20,19 +20,18 @@
20
20
  #++
21
21
  #
22
22
 
23
- require 'rexml/parsers/baseparser'
24
-
25
23
  module Kramdown
26
24
  module Parser
27
25
  class Kramdown
28
26
 
27
+ HTML_ENTITY_RE = /&([\w:][\-\w\d\.:]*);|&#(\d+);|&\#x([0-9a-fA-F]+);/
28
+
29
29
  # Parse the HTML entity at the current location.
30
30
  def parse_html_entity
31
31
  @src.pos += @src.matched_size
32
- @tree.children << Element.new(:entity, @src.matched)
32
+ @tree.children << Element.new(:entity, @src[1] || (@src[2] && @src[2].to_i) || @src[3].hex)
33
33
  end
34
- define_parser(:html_entity, REXML::Parsers::BaseParser::REFERENCE_RE)
35
-
34
+ define_parser(:html_entity, HTML_ENTITY_RE, '&')
36
35
 
37
36
  end
38
37
  end
@@ -31,7 +31,7 @@ module Kramdown
31
31
  @src.pos += @src.matched_size
32
32
  @tree.children << Element.new(:br)
33
33
  end
34
- define_parser(:line_break, LINE_BREAK)
34
+ define_parser(:line_break, LINE_BREAK, '( |\\\\)(?=\n)')
35
35
 
36
36
  end
37
37
  end
@@ -91,7 +91,7 @@ module Kramdown
91
91
  add_text(result)
92
92
  return
93
93
  end
94
- alt_text = @src.string[reset_pos...@src.pos]
94
+ alt_text = extract_string(reset_pos...@src.pos)
95
95
  conv_link_id = alt_text.gsub(/(\s|\n)+/m, ' ').gsub(LINK_ID_NON_CHARS, '').downcase
96
96
  @src.scan(stop_re)
97
97
 
@@ -146,7 +146,7 @@ module Kramdown
146
146
  add_text(result)
147
147
  end
148
148
  end
149
- define_parser(:link, LINK_START)
149
+ define_parser(:link, LINK_START, '!?\[')
150
150
 
151
151
  end
152
152
  end
@@ -0,0 +1,213 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of kramdown.
7
+ #
8
+ # kramdown is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU General Public License
19
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ #
21
+ #
22
+ # Parts of this file are based on code from Maruku by Andrea Censi.
23
+ # The needed license statements follow:
24
+ #
25
+ # Copyright (C) 2006 Andrea Censi <andrea (at) rubyforge.org>
26
+ #
27
+ # Maruku is free software; you can redistribute it and/or modify
28
+ # it under the terms of the GNU General Public License as published by
29
+ # the Free Software Foundation; either version 2 of the License, or
30
+ # (at your option) any later version.
31
+ #
32
+ # Maruku is distributed in the hope that it will be useful,
33
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
34
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
+ # GNU General Public License for more details.
36
+ #
37
+ # You should have received a copy of the GNU General Public License
38
+ # along with Maruku; if not, write to the Free Software
39
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
40
+ #
41
+ # NOTA BENE:
42
+ #
43
+ # The following algorithm is a rip-off of RubyPants written by
44
+ # Christian Neukirchen.
45
+ #
46
+ # RubyPants is a Ruby port of SmartyPants written by John Gruber.
47
+ #
48
+ # This file is distributed under the GPL, which I guess is compatible
49
+ # with the terms of the RubyPants license.
50
+ #
51
+ # -- Andrea Censi
52
+ #
53
+ # = RubyPants -- SmartyPants ported to Ruby
54
+ #
55
+ # Ported by Christian Neukirchen <mailto:chneukirchen@gmail.com>
56
+ # Copyright (C) 2004 Christian Neukirchen
57
+ #
58
+ # Incooporates ideas, comments and documentation by Chad Miller
59
+ # Copyright (C) 2004 Chad Miller
60
+ #
61
+ # Original SmartyPants by John Gruber
62
+ # Copyright (C) 2003 John Gruber
63
+ #
64
+ #
65
+ # = RubyPants -- SmartyPants ported to Ruby
66
+ #
67
+ #
68
+ # [snip]
69
+ #
70
+ # == Authors
71
+ #
72
+ # John Gruber did all of the hard work of writing this software in
73
+ # Perl for Movable Type and almost all of this useful documentation.
74
+ # Chad Miller ported it to Python to use with Pyblosxom.
75
+ #
76
+ # Christian Neukirchen provided the Ruby port, as a general-purpose
77
+ # library that follows the *Cloth API.
78
+ #
79
+ #
80
+ # == Copyright and License
81
+ #
82
+ # === SmartyPants license:
83
+ #
84
+ # Copyright (c) 2003 John Gruber
85
+ # (http://daringfireball.net)
86
+ # All rights reserved.
87
+ #
88
+ # Redistribution and use in source and binary forms, with or without
89
+ # modification, are permitted provided that the following conditions
90
+ # are met:
91
+ #
92
+ # * Redistributions of source code must retain the above copyright
93
+ # notice, this list of conditions and the following disclaimer.
94
+ #
95
+ # * Redistributions in binary form must reproduce the above copyright
96
+ # notice, this list of conditions and the following disclaimer in
97
+ # the documentation and/or other materials provided with the
98
+ # distribution.
99
+ #
100
+ # * Neither the name "SmartyPants" nor the names of its contributors
101
+ # may be used to endorse or promote products derived from this
102
+ # software without specific prior written permission.
103
+ #
104
+ # This software is provided by the copyright holders and contributors
105
+ # "as is" and any express or implied warranties, including, but not
106
+ # limited to, the implied warranties of merchantability and fitness
107
+ # for a particular purpose are disclaimed. In no event shall the
108
+ # copyright owner or contributors be liable for any direct, indirect,
109
+ # incidental, special, exemplary, or consequential damages (including,
110
+ # but not limited to, procurement of substitute goods or services;
111
+ # loss of use, data, or profits; or business interruption) however
112
+ # caused and on any theory of liability, whether in contract, strict
113
+ # liability, or tort (including negligence or otherwise) arising in
114
+ # any way out of the use of this software, even if advised of the
115
+ # possibility of such damage.
116
+ #
117
+ # === RubyPants license
118
+ #
119
+ # RubyPants is a derivative work of SmartyPants and smartypants.py.
120
+ #
121
+ # Redistribution and use in source and binary forms, with or without
122
+ # modification, are permitted provided that the following conditions
123
+ # are met:
124
+ #
125
+ # * Redistributions of source code must retain the above copyright
126
+ # notice, this list of conditions and the following disclaimer.
127
+ #
128
+ # * Redistributions in binary form must reproduce the above copyright
129
+ # notice, this list of conditions and the following disclaimer in
130
+ # the documentation and/or other materials provided with the
131
+ # distribution.
132
+ #
133
+ # This software is provided by the copyright holders and contributors
134
+ # "as is" and any express or implied warranties, including, but not
135
+ # limited to, the implied warranties of merchantability and fitness
136
+ # for a particular purpose are disclaimed. In no event shall the
137
+ # copyright owner or contributors be liable for any direct, indirect,
138
+ # incidental, special, exemplary, or consequential damages (including,
139
+ # but not limited to, procurement of substitute goods or services;
140
+ # loss of use, data, or profits; or business interruption) however
141
+ # caused and on any theory of liability, whether in contract, strict
142
+ # liability, or tort (including negligence or otherwise) arising in
143
+ # any way out of the use of this software, even if advised of the
144
+ # possibility of such damage.
145
+ #
146
+ # == Links
147
+ #
148
+ # John Gruber:: http://daringfireball.net
149
+ # SmartyPants:: http://daringfireball.net/projects/smartypants
150
+ #
151
+ # Chad Miller:: http://web.chad.org
152
+ #
153
+ # Christian Neukirchen:: http://kronavita.de/chris
154
+ #
155
+ #++
156
+ #
157
+
158
+ module Kramdown
159
+ module Parser
160
+ class Kramdown
161
+
162
+ SQ_PUNCT = '[!"#\$\%\'()*+,\-.\/:;<=>?\@\[\\\\\]\^_`{|}~]'
163
+ SQ_CLOSE = %![^\ \\\\\t\r\n\\[{(-]!
164
+
165
+ SQ_RULES = [
166
+ [/("|')(?=#{SQ_PUNCT}\B)/, [:rquote1]],
167
+ # Special case for double sets of quotes, e.g.:
168
+ # <p>He said, "'Quoted' words in a larger quote."</p>
169
+ [/(\s?)"'(?=\w)/, [1, :ldquo, :lsquo]],
170
+ [/(\s?)'"(?=\w)/, [1, :lsquo, :ldquo]],
171
+ # Special case for decade abbreviations (the '80s):
172
+ [/(\s?)'(?=\d\ds)/, [1, :rsquo]],
173
+
174
+ # Get most opening single/double quotes:
175
+ [/(\s)('|")(?=\w)/, [1, :lquote2]],
176
+ # Single/double closing quotes:
177
+ [/(#{SQ_CLOSE})('|")/, [1, :rquote2]],
178
+ # Special case for e.g. "<i>Custer</i>'s Last Stand."
179
+ [/("|')(\s|s\b|$)/, [:rquote1, 2]],
180
+ # Any remaining single quotes should be opening ones:
181
+ [/(.?)'/, [1, :lsquo]],
182
+ [/(.?)"/, [1, :ldquo]],
183
+ ] #'"
184
+
185
+ SQ_SUBSTS = {
186
+ [:rquote1, '"'] => :rdquo,
187
+ [:rquote1, "'"] => :rsquo,
188
+ [:rquote2, '"'] => :rdquo,
189
+ [:rquote2, "'"] => :rsquo,
190
+ [:lquote1, '"'] => :ldquo,
191
+ [:lquote1, "'"] => :lsquo,
192
+ [:lquote2, '"'] => :ldquo,
193
+ [:lquote2, "'"] => :lsquo,
194
+ }
195
+ SMART_QUOTES_RE = /[^\\]?["']/
196
+
197
+ # Parse the smart quotes at current location.
198
+ def parse_smart_quotes
199
+ regexp, substs = SQ_RULES.find {|reg, subst| @src.scan(reg)}
200
+ substs.each do |subst|
201
+ if subst.kind_of?(Integer)
202
+ add_text(@src[subst].to_s)
203
+ else
204
+ val = SQ_SUBSTS[[subst, @src[subst.to_s[-1,1].to_i]]] || subst
205
+ @tree.children << Element.new(:smart_quote, val)
206
+ end
207
+ end
208
+ end
209
+ define_parser(:smart_quotes, SMART_QUOTES_RE, '[^\\\\]?["\']')
210
+
211
+ end
212
+ end
213
+ end
@@ -41,7 +41,7 @@ module Kramdown
41
41
  add_text(val.dup)
42
42
  end
43
43
  end
44
- define_parser(:typographic_syms, TYPOGRAPHIC_SYMS_RE)
44
+ define_parser(:typographic_syms, TYPOGRAPHIC_SYMS_RE, '--|\\.\\.\\.|(?:\\\\| )?(?:<<|>>)')
45
45
 
46
46
  end
47
47
  end
@@ -23,6 +23,6 @@
23
23
  module Kramdown
24
24
 
25
25
  # The kramdown version.
26
- VERSION = '0.4.0'
26
+ VERSION = '0.5.0'
27
27
 
28
28
  end