tartan 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README +130 -0
  3. data/TODO +17 -0
  4. data/lib/core_ext/array.rb +12 -0
  5. data/lib/core_ext/file.rb +15 -0
  6. data/lib/core_ext/hash.rb +16 -0
  7. data/lib/core_ext/match_data.rb +62 -0
  8. data/lib/core_ext/module.rb +17 -0
  9. data/lib/core_ext/regexp.rb +33 -0
  10. data/lib/markdown.yml +499 -0
  11. data/lib/symbolize.rb +78 -0
  12. data/lib/table.yml +63 -0
  13. data/lib/tartan.rb +359 -0
  14. data/lib/tartan_markdown.rb +8 -0
  15. data/lib/tartan_markdown_def.rb +7 -0
  16. data/lib/tartan_table_def.rb +7 -0
  17. data/lib/tartan_test_base_def.rb +5 -0
  18. data/lib/tartan_wikilink_def.rb +14 -0
  19. data/lib/test_base.yml +18 -0
  20. data/lib/wiki-test.rb +94 -0
  21. data/lib/wiki_rule.rb +240 -0
  22. data/lib/wikilink.yml +18 -0
  23. data/test/MarkdownTest_1.0/Amps and angle encoding.html +17 -0
  24. data/test/MarkdownTest_1.0/Amps and angle encoding.text +21 -0
  25. data/test/MarkdownTest_1.0/Auto links.html +18 -0
  26. data/test/MarkdownTest_1.0/Auto links.text +13 -0
  27. data/test/MarkdownTest_1.0/Backslash codeescapes.html +68 -0
  28. data/test/MarkdownTest_1.0/Backslash codeescapes.text +68 -0
  29. data/test/MarkdownTest_1.0/Backslash simpleescapes.html +33 -0
  30. data/test/MarkdownTest_1.0/Backslash simpleescapes.text +33 -0
  31. data/test/MarkdownTest_1.0/Blockquotes with code blocks.html +15 -0
  32. data/test/MarkdownTest_1.0/Blockquotes with code blocks.text +11 -0
  33. data/test/MarkdownTest_1.0/Hard-wrapped paragraphs with list-like lines.html +8 -0
  34. data/test/MarkdownTest_1.0/Hard-wrapped paragraphs with list-like lines.text +8 -0
  35. data/test/MarkdownTest_1.0/Horizontal rules.html +71 -0
  36. data/test/MarkdownTest_1.0/Horizontal rules.text +67 -0
  37. data/test/MarkdownTest_1.0/Inline HTML (Advanced).html +14 -0
  38. data/test/MarkdownTest_1.0/Inline HTML (Advanced).text +14 -0
  39. data/test/MarkdownTest_1.0/Inline HTML (Simple).html +72 -0
  40. data/test/MarkdownTest_1.0/Inline HTML (Simple).text +69 -0
  41. data/test/MarkdownTest_1.0/Inline HTML comments.html +13 -0
  42. data/test/MarkdownTest_1.0/Inline HTML comments.text +13 -0
  43. data/test/MarkdownTest_1.0/Links, inline style.html +9 -0
  44. data/test/MarkdownTest_1.0/Links, inline style.text +9 -0
  45. data/test/MarkdownTest_1.0/Links, reference style.html +18 -0
  46. data/test/MarkdownTest_1.0/Links, reference style.text +31 -0
  47. data/test/MarkdownTest_1.0/Literal quotes in titles.html +3 -0
  48. data/test/MarkdownTest_1.0/Literal quotes in titles.text +7 -0
  49. data/test/MarkdownTest_1.0/Markdown Documentation - Basics.html +314 -0
  50. data/test/MarkdownTest_1.0/Markdown Documentation - Basics.text +306 -0
  51. data/test/MarkdownTest_1.0/Markdown Documentation - Syntax.html +942 -0
  52. data/test/MarkdownTest_1.0/Markdown Documentation - Syntax.text +888 -0
  53. data/test/MarkdownTest_1.0/Nested blockquotes.html +9 -0
  54. data/test/MarkdownTest_1.0/Nested blockquotes.text +5 -0
  55. data/test/MarkdownTest_1.0/Ordered and unordered lists.html +137 -0
  56. data/test/MarkdownTest_1.0/Ordered and unordered lists.text +122 -0
  57. data/test/MarkdownTest_1.0/Strong and em together.html +7 -0
  58. data/test/MarkdownTest_1.0/Strong and em together.text +7 -0
  59. data/test/MarkdownTest_1.0/Tabs.html +25 -0
  60. data/test/MarkdownTest_1.0/Tabs.text +21 -0
  61. data/test/MarkdownTest_1.0/Tidyness.html +8 -0
  62. data/test/MarkdownTest_1.0/Tidyness.text +5 -0
  63. data/test/MarkdownTest_1.0/run-markdown.rb +56 -0
  64. data/test/MarkdownTest_1.0/test-fireball-markdown.rb +177 -0
  65. data/test/MarkdownTest_1.0/testdiff.rb +42 -0
  66. data/test/harder/test-markdown-harder.rb +11 -0
  67. data/test/harder/test-markdown-harder.yml +111 -0
  68. data/test/redcloth/redcloth-markdown-tests.rb +29 -0
  69. data/test/redcloth/redcloth-markdown-tests.yml +218 -0
  70. data/test/test-combo.rb +23 -0
  71. data/test/test-hash.rb +31 -0
  72. data/test/test-markdown.rb +11 -0
  73. data/test/test-markdown.yml +1144 -0
  74. data/test/test-match-data.rb +54 -0
  75. data/test/test-readme-example.rb +48 -0
  76. data/test/test-tables.rb +16 -0
  77. data/test/test-tables.yml +82 -0
  78. data/test/test-tartan-markdown.rb +11 -0
  79. data/test/test-tartan.rb +306 -0
  80. data/test/test-wikilink.rb +18 -0
  81. data/test/test-wikilink.yml +22 -0
  82. data/test/wikilink-test-helper.rb +14 -0
  83. metadata +139 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006 Larry Baltz & David B. Anderson
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 ADDED
@@ -0,0 +1,130 @@
1
+ == Welcome to Tartan
2
+
3
+ Tartan is a general purpose text parsing engine whose main target is wiki text
4
+ parsing. (see c2.com[http://c2.com/cgi/wiki?WikiWikiWeb] and
5
+ Wikipedia[http://en.wikipedia.org/wiki/Wiki]) It doesn't implement one specific
6
+ mark-up, but instead, provides a way to specify a variety of mark-ups. So,
7
+ Tartan is a bit more "involved" than a purpose built parser like
8
+ RedCloth[http://whytheluckystiff.net/ruby/redcloth/] or
9
+ BlueCloth[http://www.deveiate.org/projects/BlueCloth], but provides the
10
+ following benefits:
11
+
12
+ 1. separates the specific wiki syntax specification from the
13
+ implementation
14
+ 2. allows layering and extension of parsing rules
15
+ 3. allows multiple output formats from the same syntax specification
16
+
17
+ The current implementation of Tartan is in Ruby and includes a full Markdown
18
+ parser (described in YAML). The format of the parsing specification has been
19
+ created with an eye to having a language independent definition of wiki (and
20
+ possibly other) mark-ups. That's a lofty goal, and Tartan hasn't quite gotten
21
+ there yet, but we think there's a clear path. In any case, even if it is only
22
+ available in Ruby it will hopefully be helpful for projects needing to do
23
+ something more than just convert wiki text directly into HTML.
24
+
25
+ == Usage
26
+
27
+ So, really all you want to do is generate HTML from Markdown text. Here's
28
+ how you do it:
29
+
30
+ require 'tartan_markdown'
31
+
32
+ html = TartanMarkdown.new("* howdy\n* doody").to_html
33
+ # => "<ul>\n<li>howdy</li>\n<li>doody</li>\n</ul>"
34
+
35
+ Other parsers would have similar names and would have the same usage. In
36
+ particular, you will need to require the parser class file and then creat a
37
+ new instance of the parser and call <tt>to_html</tt> on that instance.
38
+
39
+ You can also have other output methods, say <tt>to_xml</tt>, which would be
40
+ called in the same way on the instance of the parser object.
41
+
42
+ === Layering Parsers
43
+
44
+ You can add parsing syntax to existing parsers. This is done by building up a set of parsers specifications that work together.
45
+
46
+ In the Tartan distribution you have a specification for Markdown and you also
47
+ have a specification for table mark-up. You can combine them by creating a new
48
+ class that layers the tables onto the Markdown definition as follows in a file
49
+ called <tt>tartan_markdown_tables.rb</tt>:
50
+
51
+ require 'tartan_markdown_def'
52
+ require 'tartan_table_def'
53
+
54
+ class TartanMarkdownTables < Tartan
55
+ include TartanMarkdownDef
56
+ include TartanTableDef
57
+ end
58
+
59
+ In another file you could use this new parser:
60
+
61
+
62
+ require 'tartan_markdown_tables'
63
+
64
+ html = TartanMarkdownTables.new("[|*happy*||**days**|]").to_html
65
+ # => "<table class=\"\">
66
+ <tr><td><em>happy</em></td><td><strong>days</strong></td></tr>
67
+ </table>"
68
+
69
+ == The Parsing Specification
70
+
71
+
72
+
73
+ === Overall Structure
74
+
75
+ Each parser is made up of a parsing definition and optional helper methods. The specification is defined in YAML and the helper methods are defined in a parser definition class.
76
+
77
+ The parsing definition in YAML has the following general structure:
78
+
79
+ block:
80
+ - <parsing rule>
81
+ - <parsing rule>
82
+
83
+ <parsing context>:
84
+ - <parsing rules>
85
+
86
+ So the parsing rules are defined as a set of contexts and each context is an
87
+ list of parsing rules. The base context defaults to <tt>block</tt>; that is, the parser starts with the <tt>block</tt> context which may point the parser off to other contexts to parse blocks of the parsed text. More on this after the explanation of the parsing rules.
88
+
89
+ ==== Parsing Rules
90
+
91
+ The following is a simple parsing rule to match paragraphs and mark them up in HTML:
92
+
93
+ title: paragraph
94
+ match: "/(^[^\n]+$\n)+^[^\n]+$/m"
95
+ html:
96
+ start_mark: <p>
97
+ end_mark: </p>
98
+
99
+ A paragraph, in this case, is any grouping of non blank lines.
100
+
101
+ The parser will repetitively apply the <tt>match</tt> regular expression and if it matches, the <tt>html</tt> output sub-rule will put <tt><p></tt> and <tt></p></tt> around the text that is matched as a paragraph.
102
+
103
+ If we wanted to also mark off blocks of code that are indented by say 2 or more spaces at the beginning of the line, we could use the following rule:
104
+
105
+ title: code
106
+ match: "/(^[ ]{2,}\S.+?$\n)+^[ ]{2,}\S.+?$/m"
107
+ html:
108
+ start_mark: <pre><code>
109
+ end_mark: </code></pre>
110
+
111
+ When we want to add the <tt>code</tt> rule, the ordering becomes important. If we put the <tt>paragraph</tt> rule first, it will gobble up both the paragraphs and the code blocks since it's just looking for groups of non blank lines. To prevent this we need to put the <tt>code</tt> rule first. So the overall definition would be:
112
+
113
+ block:
114
+ - title: code
115
+ match: "/(^[ ]{2,}\S.+?$\n)+^[ ]{2,}\S.+?$/m"
116
+ html:
117
+ start_mark: <pre><code>
118
+ end_mark: </code></pre>
119
+ - title: paragraph
120
+ match: "/(^[^\n]+$\n)+^[^\n]+$/m"
121
+ html:
122
+ start_mark: <p>
123
+ end_mark: </p>
124
+
125
+
126
+ == The Name
127
+
128
+ Tartan is intended to weave together different parsing elements. It's intended
129
+ to be an alternative of both RedCloth[http:www.redcloth.org/] and BlueCloth. Tartan is a kind of cloth
130
+ that weaves different colors together in an interesting pattern.
data/TODO ADDED
@@ -0,0 +1,17 @@
1
+ To Do
2
+ * regular expression repetition reduction
3
+ * Markdown: > in code blocks not escaped (and perhaps other cases as well)
4
+ * > in code blocks not escaped (and perhaps other cases as well)
5
+ * extended links addon for naked URLs, eg: http://www.google.com
6
+ * update all the files to generate ID tags
7
+ * HTML comparator (ignore whitespace, optionally ignore class)
8
+ * change start_mark and end_mark to start_tag and end_tag
9
+ * strike through
10
+ * superscript, subscript
11
+
12
+ To consider
13
+ * class name on span
14
+ * math mark-up
15
+
16
+ Done
17
+ * get Markdown image links to work
@@ -0,0 +1,12 @@
1
+ class Array
2
+ alias :old_index :index
3
+ def index(*args, &block)
4
+ if not args.empty?
5
+ old_index(*args)
6
+ else
7
+ result = find_all(&block).map { |item| old_index(item) }
8
+ return nil if result.empty?
9
+ return result[0]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ # Extend the File class to add a function to check for a file in the
2
+ # load path.
3
+
4
+ class File
5
+ # find a file in the load path or raise an exception if the file can
6
+ # not be found.
7
+ def File.find_file_in_path(filename)
8
+ $:.each do |path|
9
+ file_with_path = path+'/'+filename
10
+ return file_with_path if file?(file_with_path)
11
+ end
12
+
13
+ raise ArgumentError, "Can't find file #{filename} in Ruby library path"
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ class Hash
2
+ def deep_merge(hash)
3
+ target = dup
4
+
5
+ hash.keys.each do |key|
6
+ if hash[key].is_a?(Hash) and self[key].is_a?(Hash)
7
+ target[key] = target[key].deep_merge(hash[key])
8
+ next
9
+ end
10
+
11
+ target[key] = hash[key]
12
+ end
13
+
14
+ target
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ require 'pp'
2
+
3
+ class MatchData
4
+ def sym2index(sym)
5
+ case sym
6
+ when '+', :last_match, :last, "last_match", "last"
7
+ last_match_index
8
+ when '&', :all, "all"
9
+ 0
10
+ when /[0-9]+/
11
+ sym.to_i
12
+ when Integer
13
+ sym
14
+ else
15
+ nil
16
+ end
17
+ end
18
+
19
+ def replace(replace_string)
20
+ replace_string.gsub(/\\([0-9+&'`\\])/) {|sub|
21
+ case $1
22
+ when '\\'
23
+ '\\'
24
+ when '`'
25
+ pre_match
26
+ when "'"
27
+ post_match
28
+ else
29
+ to_a[sym2index($1)]
30
+ end
31
+ }
32
+ end
33
+
34
+ def last_match_index
35
+ index = length - 1
36
+ to_a.reverse.each do |sub_match|
37
+ return index if ! sub_match.nil?
38
+ index -= 1
39
+ end
40
+ end
41
+
42
+ def pre_sub_match(index)
43
+ if index.abs >= length
44
+ raise ArgumentError, "absolute value of index greater than length"
45
+ end
46
+
47
+ index = length + index if index < 0
48
+
49
+ string[offset(0)[0]...offset(index)[0]]
50
+ end
51
+
52
+ def post_sub_match(index)
53
+ if index.abs >= length
54
+ raise ArgumentError, "absolute value of index greater than length"
55
+ end
56
+
57
+ index = length + index if index < 0
58
+
59
+ string[offset(index)[1]...offset(0)[1]]
60
+ end
61
+ end
62
+
@@ -0,0 +1,17 @@
1
+ class Module
2
+ def method_missing(method_name, *args, &block)
3
+ @arg_sets ||= {}
4
+ @arg_sets[method_name] = [args, block]
5
+ end
6
+
7
+ def included(klass)
8
+ return unless defined? @arg_sets
9
+ @arg_sets.each do |method, (args, block)|
10
+ if klass.methods.include?(method.id2name)
11
+ klass.send(method, *args, &block)
12
+ else
13
+ raise "method #{method} not defined in #{klass}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ class Regexp
2
+ def to_regexp
3
+ self
4
+ end
5
+ end
6
+
7
+ class String
8
+ def chars
9
+ arr = []
10
+ scan(/./m) {|char| arr << char}
11
+ arr
12
+ end
13
+ def to_regexp
14
+ if self =~ /\A\s*\/((?:\\\/|[^\/])*)\/([imxnNeEsSuU]*)\s*\z/m
15
+ options = 0
16
+ lang = ''
17
+ $2.chars.each do |char|
18
+ case char
19
+ when 'i': options |= Regexp::IGNORECASE
20
+ when 'm': options |= Regexp::MULTILINE
21
+ when 'x': options |= Regexp::EXTENDED
22
+ when 'n', 'N': lang = 'n'
23
+ when 'e', 'E': lang = 'e'
24
+ when 's', 'S': lang = 's'
25
+ when 'u', 'U': lang = 'u'
26
+ end
27
+ end
28
+ Regexp.compile($1, options, lang)
29
+ else
30
+ nil
31
+ end
32
+ end
33
+ end
data/lib/markdown.yml ADDED
@@ -0,0 +1,499 @@
1
+ #$Id: markdown.rb 227 2006-06-12 16:30:08Z larry $
2
+
3
+ # To resolve:
4
+ # How to handle (if at all) raw <h1>..<h6> tags.
5
+ # span parsing of headers
6
+ # handle return (\r) characters properly (especially in \r\n combo)
7
+
8
+ span:
9
+ - title: backtick_2
10
+ shelve: true
11
+ match: /`` ?(.+?) ?``/
12
+ subparse:
13
+ context: back_smarties
14
+ match_group: 1
15
+ html:
16
+ start_mark: '<code>'
17
+ end_mark: '</code>'
18
+
19
+ - title: backtick_1
20
+ shelve: true
21
+ match: /`(.+?)`/
22
+ subparse:
23
+ context: back_smarties
24
+ match_group: 1
25
+ html:
26
+ start_mark: '<code>'
27
+ end_mark: '</code>'
28
+
29
+ - title: ref_image
30
+ shelve: true
31
+ match: /!\[(.*?)\][ ]?\[(.*?)\]/
32
+ html:
33
+ replace: '<img src="{{{\2url}}}" alt="\1"{{{\2title}}} />'
34
+
35
+ - title: ref_link_no_id
36
+ shelve: true
37
+ match: /\[(.*?)\][ ]?\[\]/
38
+ html:
39
+ replace: '<a href="{{{\1url}}}"{{{\1title}}}>\1</a>'
40
+
41
+ - title: ref_link
42
+ shelve: true
43
+ match: /\[(.*?)\][ ]?\[(.*?)\]/
44
+ html:
45
+ replace: '<a href="{{{\2url}}}"{{{\2title}}}>\1</a>'
46
+
47
+ - title: html_span
48
+ shelve: true
49
+ match: >
50
+ / <\/?
51
+ (?:span|cite|del|em|strong|dfn|code|samp|kbd|var|abbr
52
+ |acronym|b|i|font|a|img|object|tt|big|small|strike|s|u
53
+ |sup|sub|q)
54
+ . *?>/x
55
+ html:
56
+ start_mark: ''
57
+ end_mark: ''
58
+
59
+ - title: entity_escaped
60
+ shelve: true
61
+ match: '/&[[:alnum:]-]+;/'
62
+ html:
63
+ start_mark: ''
64
+ end_mark: ''
65
+
66
+ - title: amp
67
+ match: /&/
68
+ html:
69
+ replace: '&amp;'
70
+
71
+ - title: backslash_gt
72
+ match: /\\>/
73
+ html:
74
+ replace: '&gt;'
75
+
76
+ - title: lt
77
+ match: /</
78
+ html:
79
+ replace: '&lt;'
80
+
81
+ - title: gt
82
+ match: '/(?:(?!^))>/'
83
+ html:
84
+ replace: '&gt;'
85
+
86
+ - title: backslash_escapes
87
+ shelve: true
88
+ match: /\\([\\\`\*\_\{\}\[\]\(\)\>\#\.\!\+\-])/
89
+ html:
90
+ replace: '\1'
91
+
92
+ - title: linebreak
93
+ match: /[ \t]{2,}$/
94
+ html:
95
+ replace: "<br />"
96
+
97
+ - rescan
98
+
99
+ - title: inline_image_with_title
100
+ shelve: true
101
+ match: /!\[(.+?)\]\((.+??)\s+"(.+?)"\)/
102
+ html:
103
+ replace: '<img src="\2" alt="\1" title="\3" />'
104
+
105
+ - rescan
106
+
107
+ - title: inline_image
108
+ shelve: true
109
+ match: /!\[(.+?)\]\((.*?)\)/
110
+ html:
111
+ replace: '<img src="\2" alt="\1" />'
112
+
113
+ - rescan
114
+
115
+ - title: link_with_title
116
+ shelve: true
117
+ match: /\[(.+?)\]\((.+??)\s+"(.+?)"\)/
118
+ html:
119
+ replace: '<a href="\2" title="\3">\1</a>'
120
+ - rescan
121
+
122
+ - title: link
123
+ shelve: true
124
+ match: /\[(.+?)\]\((.*?)\)/
125
+ html:
126
+ replace: '<a href="\2">\1</a>'
127
+
128
+ - rescan
129
+
130
+ - title: pre_emphasis
131
+
132
+ - title: strong_em
133
+ match: '/(?:\*{3}(.+?)\*{3})|(?:_{3}(.+?)_{3})/'
134
+ subparse:
135
+ context: span
136
+ match_group: last
137
+ html:
138
+ start_mark: '<strong><em>'
139
+ end_mark: '</em></strong>'
140
+ - rescan
141
+
142
+ - title: strong
143
+ match: '/(?:\*{2}(.+?)\*{2})|(?:_{2}(.+?)_{2})/'
144
+ subparse:
145
+ context: span
146
+ match_group: last
147
+ html:
148
+ start_mark: '<strong>'
149
+ end_mark: '</strong>'
150
+ - rescan
151
+
152
+ - title: em
153
+ match: '/(?:\*(.+?)\*)|(?:\_(.+?)\_)/'
154
+ subparse:
155
+ context: span
156
+ match_group: last
157
+ html:
158
+ start_mark: '<em>'
159
+ end_mark: '</em>'
160
+
161
+ - title: post_emphasis
162
+
163
+ back_smarties:
164
+ - title: backslash_gt
165
+ match: /\\>/
166
+ html:
167
+ replace: '\\&gt;'
168
+
169
+ - title: backslash_lt
170
+ match: /\\</
171
+ html:
172
+ replace: '\\&lt;'
173
+
174
+ - title: amp
175
+ match: /&/
176
+ html:
177
+ replace: '&amp;'
178
+
179
+ - title: backslash_gt
180
+ match: /\\>/
181
+ html:
182
+ replace: '&gt;'
183
+
184
+ - title: lt
185
+ match: /</
186
+ html:
187
+ replace: '&lt;'
188
+
189
+ - title: gt
190
+ match: '/(?:(?!^))>/'
191
+ html:
192
+ replace: '&gt;'
193
+
194
+ block:
195
+ - title: strip_return
196
+ match: /\r/
197
+ html:
198
+ replace: ''
199
+
200
+ - rescan
201
+
202
+ - title: main_block
203
+
204
+ - title: reference_title
205
+ match: >
206
+ /\n(?:[ ]{0,3})
207
+ \[([^\]]*)\]:\s+(?:<([^>]*)>|(\S*))\s+
208
+ (?:"([^"]*?)"|'([^']*?)')[ \t]*/mx
209
+ set:
210
+ '\1url': '\2\3'
211
+ '\1title': ' title="\4\5"'
212
+ html:
213
+ replace: ''
214
+
215
+ - title: reference
216
+ match: '/\n(?: {0,3})\[([^:\n]*)\]:\s+(?:<([^>]*)>|(\S*))$/m'
217
+ set:
218
+ '\1url': '\2\3'
219
+ '\1title': ''
220
+ html:
221
+ replace: ''
222
+
223
+ - title: html_comment
224
+ shelve: true
225
+ match: /(<!--.*?-->)/m
226
+ html:
227
+ replace: '\1'
228
+
229
+ - title: underline_header1
230
+ match: '/^([^\n\t #=-][^\n]*?)[ \t]*\n=+[ \t]*$/m'
231
+ subparse:
232
+ context: span
233
+ match_group: 1
234
+ html:
235
+ start_mark: '<h1>'
236
+ end_mark: '</h1>'
237
+
238
+ - title: underline_header2
239
+ match: '/^([^\n\s#=-][^\n]*?)[ \t]*\n-+[ \t]*$/m'
240
+ subparse:
241
+ context: span
242
+ match_group: 1
243
+ html:
244
+ start_mark: '<h2>'
245
+ end_mark: '</h2>'
246
+
247
+ - title: hash_header
248
+ match: '/^(\# {1,6})\s*([^#]*?)(?:\s*\#+\s*|\s*)$/x'
249
+ subparse:
250
+ context: span
251
+ match_group: 2
252
+ html:
253
+ start_mark: '<h#{len(\1)}>'
254
+ end_mark: '</h#{len(\1)}>'
255
+
256
+ - title: blockquote
257
+ match: '/^((?:>.*?$)(?:\n[^\n]+)*)/m'
258
+ subparse: embeddedBlock
259
+ strip:
260
+ match: /^(> |>$)/
261
+ replace: ''
262
+ unstrip:
263
+ match: /^|(\n)\z/
264
+ replace: '\1> '
265
+ html:
266
+ start_mark: "<blockquote>\n"
267
+ end_mark: "\n</blockquote>"
268
+ # Needs to go before the bullet lists to ensure that
269
+ # spaced - and * HRs aren't interpreted as bullet lists
270
+
271
+ - title: horizontal_rule
272
+ match: >
273
+ / (?:(\n)\s*(\n)|\A|\A\s*(\n))
274
+ [ ]{0,3}([-_*][ ]?){3,}[ \t]*?$/xm
275
+ html:
276
+ replace: '\1\2\3<hr />'
277
+
278
+ - title: bulletListSpaced
279
+ match: >
280
+ / (?>\A(\s*)|\n(\n))
281
+ (
282
+ [-*+](?>[ ]+|\t)[^\n]*
283
+ (?>\n(?>[ ]{4}|\t)?[^\n]+)*
284
+ (?>
285
+ \n\n(?>[ ]{4}|\t)[^-*+\n][^\n]*
286
+ (?>\n(?>[ ]{4}|\t)?[^\n]+)*
287
+ )*
288
+ (?>
289
+ \n\n[-*+](?:[ ]+|\t)[^\n]*
290
+ (?>\n
291
+ (?>[ ]{4}|\t)?
292
+ [^\n]+
293
+ )*
294
+ (?>
295
+ \n\n(?>[ ]{4}|\t)[^-*+\n][^\n]*
296
+ (?>\n(?>[ ]{4}|\t)?[^\n]+)*
297
+ )*
298
+ )+
299
+ )/xm
300
+ subparse:
301
+ context: listSpaced
302
+ match_group: 3
303
+ html:
304
+ start_mark: "<ul>\n"
305
+ end_mark: "\n</ul>"
306
+
307
+ - title: bulletListClose
308
+ match: >
309
+ / (?:\A(\s*)|\n(\n))
310
+ ([-*+](?:[ ]+|\t)[^\n]+(:?\n[ \t]*[^\s][^\n]*)*)/xm
311
+ subparse:
312
+ context: listClose
313
+ match_group: 3
314
+ html:
315
+ start_mark: "\\1\\2<ul>\n"
316
+ end_mark: "\n</ul>"
317
+
318
+ - title: numberedListSpaced
319
+ match: >
320
+ / (?>\A(\s*)|\n(\n))
321
+ (
322
+ (?>^[[:digit:]]+\.
323
+ (?>[ ]+|\t)[^\n]*)
324
+ (?>\n(?:[ ]{4}|\t)?
325
+ [^\n]+
326
+ )*
327
+ (?>
328
+ (?>\n\n(?:[ ]{4}|\t)[^[:digit:]\n][^\n]*)
329
+ (?>\n(?:[ ]{4}|\t)?[^\n]+)*
330
+ )*
331
+ (?>\n\n
332
+ (?>^[[:digit:]]+\.
333
+ (?>[ ]+|\t)[^\n]*)
334
+ (?>\n(?:[ ]{4}|\t)?
335
+ [^\n]+
336
+ )*
337
+ (?>
338
+ (?>\n\n(?:[ ]{4}|\t)[^[:digit:]\n][^\n]*)
339
+ (?>\n(?:[ ]{4}|\t)?[^\n]+)*
340
+ )*
341
+ )+
342
+ )/xm
343
+ subparse:
344
+ context: listSpaced
345
+ match_group: 3
346
+ html:
347
+ start_mark: "\\1\\2<ol>\n"
348
+ end_mark: "\n</ol>"
349
+
350
+ - title: numberedListClose
351
+ match: >
352
+ / (?:\A(\s*)|\n(\n))
353
+ ((?:^[[:digit:]]+\.(?:[ ]+|\t)[^\n]*)
354
+ (?:\n(?:[[:digit:]]+\.(?:[ ]+|\t)
355
+ |(?:[ ]{4}|\t)?
356
+ )[^\n]+
357
+ )*
358
+ )/xm
359
+ subparse:
360
+ context: listClose
361
+ match_group: 3
362
+ html:
363
+ start_mark: "\\1\\2<ol>\n"
364
+ end_mark: "\n</ol>"
365
+
366
+ - title: html_block
367
+ shelve: true
368
+ match: >
369
+ / ^[ ]{0,3}<(script|table|div|pre|center|blockquote|p|ul|ol|h[1-6])(?:[^>]*)?>
370
+ .*?
371
+ <\/\1>/xm
372
+ html: true
373
+
374
+ - title: code
375
+ match: >
376
+ / (?:\A|(\n)(?:[ ]{4}|\t)?(\n))((?:\t|[ ]{4})[^\n]*
377
+ (?:\n+(?:\t|[ ]{4})[^\n]*)*)/xm
378
+ subparse:
379
+ context: codeBlock
380
+ match_group: 3
381
+ strip:
382
+ match: '/^(?:\t|[ ]{4})/'
383
+ replace: ''
384
+ unstrip:
385
+ match: /\n/
386
+ replace: "\n "
387
+ html:
388
+ start_mark: '\1\2<pre><code>'
389
+ end_mark: "\n</code></pre>"
390
+
391
+ - title: paragraph
392
+ match: '/((?:^\S.*?$)(?:\n\S[^\n]*)*)/m'
393
+ subparse: span
394
+ html:
395
+ start_mark: '<p>'
396
+ end_mark: '</p>'
397
+
398
+ - title: extraReturns
399
+ match: '/^(?:\s*\n){3,}/'
400
+ html:
401
+ replace: "\n\n"
402
+
403
+ codeBlock:
404
+ - title: codeContents
405
+ match: /(\A.+\z)/m
406
+ rescan: true
407
+ html:
408
+ replace: '#{untabify(\1)}'
409
+
410
+ - title: check_smarties
411
+ match: /(\A.+\z)/m
412
+ subparse: back_smarties
413
+
414
+ embeddedBlock:
415
+ - title: emBulletListClose
416
+ match: >
417
+ / ((?:^[-*+](?:[ ]+|\t).*?$)
418
+ (?:\n(?:[-*+]|(?:[ ]{4}|\t)?)[^\n]*)*
419
+ )/xm
420
+ subparse: listClose
421
+ html:
422
+ start_mark: "<ul>\n"
423
+ end_mark: "\n</ul>"
424
+
425
+ - title: emNumberedListClose
426
+ match: >-
427
+ / ( (?:^[[:digit:]]+\.(?:[ ]+|\t).*?$)
428
+ (?:\n(?:[[:digit:]]+\.|(?:[ ]{4}|\t)?)
429
+ [^\n]*)*
430
+ )/xm
431
+ subparse: listClose
432
+ html:
433
+ start_mark: "<ol>\n"
434
+ end_mark: "\n</ol>"
435
+
436
+ - title: embeddedPara
437
+ position: first
438
+ match:
439
+ /\A (?:(?![*+-]|[[:digit:]]))
440
+ (?:(?:\S[^\n]*)(?:\n\S[^\n]*)*)
441
+ \n?\z/xm
442
+ subparse: span
443
+ html:
444
+ end_mark: '\1'
445
+
446
+ - title: embeddedRemainder
447
+ match: /.+/m
448
+ subparse: block
449
+ html: true
450
+
451
+ listSpaced:
452
+ - title: spacedListItem
453
+ match: >-
454
+ /^(?:^(?:[-*+]|[[:digit:]]+\.)
455
+ (?:[ ]+|\t).*?$
456
+ )
457
+ (?:\n[^-*+[:digit:]\n][^\n]*)*
458
+ (?:
459
+ (?:\n\n(?:[ ]{4}|\t)[^-*+[:digit:]\n][^\n]*)
460
+ (?:\n[^-*+[:digit:]\n][^\n]*)*
461
+ )*/xm
462
+ strip:
463
+ match: '/^(([-*+]|[[:digit:]]\.)\s*|(?: |\t))/'
464
+ replace: ''
465
+ subparse: block
466
+ html:
467
+ start_mark: '<li>'
468
+ end_mark: "</li>"
469
+
470
+ - title: listSpacedDoubleReturn
471
+ match: /\n\n/
472
+ html:
473
+ replace: "\n"
474
+
475
+ listClose:
476
+ - title: closeListItem
477
+ match: >
478
+ /^(
479
+ (?:
480
+ (?:[-*+]|[[:digit:]+]\.)
481
+ (?:[ ]+|\t).*?$
482
+ )
483
+ (?:\n(?![-*+\n]|[[:digit:]]+\.)[^\n]*)*
484
+ )/xm
485
+ strip:
486
+ match: >
487
+ /^( (?:[-*+]|[[:digit:]]+\.)\s*
488
+ |(?:[ ]+|\t)
489
+ )/x
490
+ replace: ''
491
+ subparse: embeddedBlock
492
+ html:
493
+ start_mark: '<li>'
494
+ end_mark: '</li>'
495
+
496
+ - title: listCloseDoubleReturn
497
+ match: /\n\n/
498
+ html:
499
+ replace: "\n"