newstile 1.0.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.
Files changed (405) hide show
  1. data/AUTHORS +1 -0
  2. data/CONTRIBUTERS +6 -0
  3. data/COPYING +24 -0
  4. data/ChangeLog +5489 -0
  5. data/GPL +674 -0
  6. data/README +31 -0
  7. data/Rakefile +342 -0
  8. data/VERSION +1 -0
  9. data/benchmark/benchmark.rb +34 -0
  10. data/benchmark/generate_data.rb +112 -0
  11. data/benchmark/historic-jruby-1.4.0.dat +7 -0
  12. data/benchmark/historic-ruby-1.8.6.dat +7 -0
  13. data/benchmark/historic-ruby-1.8.7.dat +7 -0
  14. data/benchmark/historic-ruby-1.9.1p243.dat +7 -0
  15. data/benchmark/historic-ruby-1.9.2dev.dat +7 -0
  16. data/benchmark/mdbasics.text +306 -0
  17. data/benchmark/mdsyntax.text +888 -0
  18. data/benchmark/static-jruby-1.4.0.dat +7 -0
  19. data/benchmark/static-ruby-1.8.6.dat +7 -0
  20. data/benchmark/static-ruby-1.8.7.dat +7 -0
  21. data/benchmark/static-ruby-1.9.1p243.dat +7 -0
  22. data/benchmark/static-ruby-1.9.2dev.dat +7 -0
  23. data/benchmark/testing.sh +9 -0
  24. data/benchmark/timing.sh +10 -0
  25. data/bin/newstile +82 -0
  26. data/data/newstile/document.html +18 -0
  27. data/data/newstile/document.latex +43 -0
  28. data/doc/default.scss.css +519 -0
  29. data/doc/default.template +80 -0
  30. data/doc/documentation.page +72 -0
  31. data/doc/index.page +96 -0
  32. data/doc/installation.page +90 -0
  33. data/doc/links.markdown +6 -0
  34. data/doc/news.feed +10 -0
  35. data/doc/news.page +28 -0
  36. data/doc/quickref.page +564 -0
  37. data/doc/syntax.page +1615 -0
  38. data/doc/tests.page +51 -0
  39. data/doc/virtual +2 -0
  40. data/lib/newstile.rb +23 -0
  41. data/lib/newstile/compatibility.rb +34 -0
  42. data/lib/newstile/converter.rb +43 -0
  43. data/lib/newstile/converter/base.rb +111 -0
  44. data/lib/newstile/converter/html.rb +405 -0
  45. data/lib/newstile/converter/latex.rb +577 -0
  46. data/lib/newstile/converter/markdown.rb +426 -0
  47. data/lib/newstile/converter/newstile.rb +426 -0
  48. data/lib/newstile/document.rb +168 -0
  49. data/lib/newstile/error.rb +27 -0
  50. data/lib/newstile/options.rb +296 -0
  51. data/lib/newstile/parser.rb +39 -0
  52. data/lib/newstile/parser/base.rb +94 -0
  53. data/lib/newstile/parser/html.rb +499 -0
  54. data/lib/newstile/parser/newstile.rb +325 -0
  55. data/lib/newstile/parser/newstile/abbreviation.rb +66 -0
  56. data/lib/newstile/parser/newstile/attribute_list.rb +111 -0
  57. data/lib/newstile/parser/newstile/autolink.rb +54 -0
  58. data/lib/newstile/parser/newstile/blank_line.rb +43 -0
  59. data/lib/newstile/parser/newstile/block_boundary.rb +46 -0
  60. data/lib/newstile/parser/newstile/blockquote.rb +63 -0
  61. data/lib/newstile/parser/newstile/codeblock.rb +60 -0
  62. data/lib/newstile/parser/newstile/codespan.rb +57 -0
  63. data/lib/newstile/parser/newstile/emphasis.rb +70 -0
  64. data/lib/newstile/parser/newstile/eob.rb +39 -0
  65. data/lib/newstile/parser/newstile/escaped_chars.rb +38 -0
  66. data/lib/newstile/parser/newstile/extension.rb +116 -0
  67. data/lib/newstile/parser/newstile/footnote.rb +74 -0
  68. data/lib/newstile/parser/newstile/header.rb +84 -0
  69. data/lib/newstile/parser/newstile/horizontal_rule.rb +39 -0
  70. data/lib/newstile/parser/newstile/html.rb +175 -0
  71. data/lib/newstile/parser/newstile/html_entity.rb +39 -0
  72. data/lib/newstile/parser/newstile/line_break.rb +38 -0
  73. data/lib/newstile/parser/newstile/link.rb +177 -0
  74. data/lib/newstile/parser/newstile/list.rb +239 -0
  75. data/lib/newstile/parser/newstile/math.rb +64 -0
  76. data/lib/newstile/parser/newstile/paragraph.rb +55 -0
  77. data/lib/newstile/parser/newstile/smart_quotes.rb +214 -0
  78. data/lib/newstile/parser/newstile/table.rb +134 -0
  79. data/lib/newstile/parser/newstile/typographic_symbol.rb +54 -0
  80. data/lib/newstile/utils.rb +37 -0
  81. data/lib/newstile/utils/entities.rb +336 -0
  82. data/lib/newstile/utils/html.rb +75 -0
  83. data/lib/newstile/utils/ordered_hash.rb +79 -0
  84. data/lib/newstile/version.rb +28 -0
  85. data/man/man1/newstile.1 +246 -0
  86. data/setup.rb +1585 -0
  87. data/test/run_tests.rb +59 -0
  88. data/test/test_files.rb +162 -0
  89. data/test/testcases/block/01_blank_line/spaces.html +1 -0
  90. data/test/testcases/block/01_blank_line/spaces.text +3 -0
  91. data/test/testcases/block/01_blank_line/tabs.html +1 -0
  92. data/test/testcases/block/01_blank_line/tabs.text +6 -0
  93. data/test/testcases/block/02_eob/beginning.html +1 -0
  94. data/test/testcases/block/02_eob/beginning.text +3 -0
  95. data/test/testcases/block/02_eob/end.html +1 -0
  96. data/test/testcases/block/02_eob/end.text +3 -0
  97. data/test/testcases/block/02_eob/middle.html +1 -0
  98. data/test/testcases/block/02_eob/middle.text +5 -0
  99. data/test/testcases/block/03_paragraph/indented.html +18 -0
  100. data/test/testcases/block/03_paragraph/indented.text +19 -0
  101. data/test/testcases/block/03_paragraph/no_newline_at_end.html +5 -0
  102. data/test/testcases/block/03_paragraph/no_newline_at_end.text +5 -0
  103. data/test/testcases/block/03_paragraph/one_para.html +1 -0
  104. data/test/testcases/block/03_paragraph/one_para.text +1 -0
  105. data/test/testcases/block/03_paragraph/two_para.html +4 -0
  106. data/test/testcases/block/03_paragraph/two_para.text +4 -0
  107. data/test/testcases/block/04_header/atx_header.html +37 -0
  108. data/test/testcases/block/04_header/atx_header.text +34 -0
  109. data/test/testcases/block/04_header/atx_header_no_newline_at_end.html +1 -0
  110. data/test/testcases/block/04_header/atx_header_no_newline_at_end.text +1 -0
  111. data/test/testcases/block/04_header/setext_header.html +30 -0
  112. data/test/testcases/block/04_header/setext_header.html.19 +30 -0
  113. data/test/testcases/block/04_header/setext_header.text +36 -0
  114. data/test/testcases/block/04_header/setext_header_no_newline_at_end.html +1 -0
  115. data/test/testcases/block/04_header/setext_header_no_newline_at_end.text +2 -0
  116. data/test/testcases/block/04_header/with_auto_id_prefix.html +3 -0
  117. data/test/testcases/block/04_header/with_auto_id_prefix.options +2 -0
  118. data/test/testcases/block/04_header/with_auto_id_prefix.text +3 -0
  119. data/test/testcases/block/04_header/with_auto_ids.html +17 -0
  120. data/test/testcases/block/04_header/with_auto_ids.options +1 -0
  121. data/test/testcases/block/04_header/with_auto_ids.text +19 -0
  122. data/test/testcases/block/05_blockquote/indented.html +25 -0
  123. data/test/testcases/block/05_blockquote/indented.text +14 -0
  124. data/test/testcases/block/05_blockquote/lazy.html +34 -0
  125. data/test/testcases/block/05_blockquote/lazy.text +20 -0
  126. data/test/testcases/block/05_blockquote/nested.html +10 -0
  127. data/test/testcases/block/05_blockquote/nested.text +6 -0
  128. data/test/testcases/block/05_blockquote/no_newline_at_end.html +4 -0
  129. data/test/testcases/block/05_blockquote/no_newline_at_end.text +2 -0
  130. data/test/testcases/block/05_blockquote/with_code_blocks.html +15 -0
  131. data/test/testcases/block/05_blockquote/with_code_blocks.text +11 -0
  132. data/test/testcases/block/06_codeblock/error.html +4 -0
  133. data/test/testcases/block/06_codeblock/error.text +4 -0
  134. data/test/testcases/block/06_codeblock/lazy.html +4 -0
  135. data/test/testcases/block/06_codeblock/lazy.text +5 -0
  136. data/test/testcases/block/06_codeblock/no_newline_at_end.html +2 -0
  137. data/test/testcases/block/06_codeblock/no_newline_at_end.text +1 -0
  138. data/test/testcases/block/06_codeblock/no_newline_at_end_1.html +2 -0
  139. data/test/testcases/block/06_codeblock/no_newline_at_end_1.text +2 -0
  140. data/test/testcases/block/06_codeblock/normal.html +13 -0
  141. data/test/testcases/block/06_codeblock/normal.text +10 -0
  142. data/test/testcases/block/06_codeblock/tilde_syntax.html +7 -0
  143. data/test/testcases/block/06_codeblock/tilde_syntax.text +9 -0
  144. data/test/testcases/block/06_codeblock/whitespace.html +3 -0
  145. data/test/testcases/block/06_codeblock/whitespace.text +3 -0
  146. data/test/testcases/block/06_codeblock/with_blank_line.html +13 -0
  147. data/test/testcases/block/06_codeblock/with_blank_line.text +12 -0
  148. data/test/testcases/block/06_codeblock/with_eob_marker.html +6 -0
  149. data/test/testcases/block/06_codeblock/with_eob_marker.text +5 -0
  150. data/test/testcases/block/06_codeblock/with_ial.html +6 -0
  151. data/test/testcases/block/06_codeblock/with_ial.text +5 -0
  152. data/test/testcases/block/07_horizontal_rule/error.html +7 -0
  153. data/test/testcases/block/07_horizontal_rule/error.html.19 +7 -0
  154. data/test/testcases/block/07_horizontal_rule/error.text +7 -0
  155. data/test/testcases/block/07_horizontal_rule/normal.html +17 -0
  156. data/test/testcases/block/07_horizontal_rule/normal.text +17 -0
  157. data/test/testcases/block/07_horizontal_rule/sepspaces.html +3 -0
  158. data/test/testcases/block/07_horizontal_rule/sepspaces.text +3 -0
  159. data/test/testcases/block/07_horizontal_rule/septabs.html +3 -0
  160. data/test/testcases/block/07_horizontal_rule/septabs.text +3 -0
  161. data/test/testcases/block/08_list/escaping.html +17 -0
  162. data/test/testcases/block/08_list/escaping.text +17 -0
  163. data/test/testcases/block/08_list/item_ial.html +7 -0
  164. data/test/testcases/block/08_list/item_ial.text +5 -0
  165. data/test/testcases/block/08_list/lazy.html +39 -0
  166. data/test/testcases/block/08_list/lazy.text +29 -0
  167. data/test/testcases/block/08_list/list_and_hr.html +9 -0
  168. data/test/testcases/block/08_list/list_and_hr.text +5 -0
  169. data/test/testcases/block/08_list/list_and_others.html +40 -0
  170. data/test/testcases/block/08_list/list_and_others.text +26 -0
  171. data/test/testcases/block/08_list/mixed.html +117 -0
  172. data/test/testcases/block/08_list/mixed.text +66 -0
  173. data/test/testcases/block/08_list/nested.html +17 -0
  174. data/test/testcases/block/08_list/nested.text +7 -0
  175. data/test/testcases/block/08_list/other_first_element.html +39 -0
  176. data/test/testcases/block/08_list/other_first_element.text +18 -0
  177. data/test/testcases/block/08_list/simple_ol.html +19 -0
  178. data/test/testcases/block/08_list/simple_ol.text +13 -0
  179. data/test/testcases/block/08_list/simple_ul.html +48 -0
  180. data/test/testcases/block/08_list/simple_ul.text +36 -0
  181. data/test/testcases/block/08_list/single_item.html +3 -0
  182. data/test/testcases/block/08_list/single_item.text +1 -0
  183. data/test/testcases/block/08_list/special_cases.html +55 -0
  184. data/test/testcases/block/08_list/special_cases.text +35 -0
  185. data/test/testcases/block/09_html/comment.html +18 -0
  186. data/test/testcases/block/09_html/comment.text +15 -0
  187. data/test/testcases/block/09_html/content_model/deflists.html +6 -0
  188. data/test/testcases/block/09_html/content_model/deflists.options +1 -0
  189. data/test/testcases/block/09_html/content_model/deflists.text +6 -0
  190. data/test/testcases/block/09_html/content_model/tables.html +14 -0
  191. data/test/testcases/block/09_html/content_model/tables.options +1 -0
  192. data/test/testcases/block/09_html/content_model/tables.text +14 -0
  193. data/test/testcases/block/09_html/html_and_codeblocks.html +15 -0
  194. data/test/testcases/block/09_html/html_and_codeblocks.options +1 -0
  195. data/test/testcases/block/09_html/html_and_codeblocks.text +13 -0
  196. data/test/testcases/block/09_html/html_to_native/code.html +10 -0
  197. data/test/testcases/block/09_html/html_to_native/code.text +9 -0
  198. data/test/testcases/block/09_html/html_to_native/comment.html +7 -0
  199. data/test/testcases/block/09_html/html_to_native/comment.text +8 -0
  200. data/test/testcases/block/09_html/html_to_native/emphasis.html +3 -0
  201. data/test/testcases/block/09_html/html_to_native/emphasis.text +3 -0
  202. data/test/testcases/block/09_html/html_to_native/entity.html +1 -0
  203. data/test/testcases/block/09_html/html_to_native/entity.text +1 -0
  204. data/test/testcases/block/09_html/html_to_native/header.html +6 -0
  205. data/test/testcases/block/09_html/html_to_native/header.options +2 -0
  206. data/test/testcases/block/09_html/html_to_native/header.text +6 -0
  207. data/test/testcases/block/09_html/html_to_native/list_dl.html +8 -0
  208. data/test/testcases/block/09_html/html_to_native/list_dl.text +8 -0
  209. data/test/testcases/block/09_html/html_to_native/list_ol.html +15 -0
  210. data/test/testcases/block/09_html/html_to_native/list_ol.text +17 -0
  211. data/test/testcases/block/09_html/html_to_native/list_ul.html +19 -0
  212. data/test/testcases/block/09_html/html_to_native/list_ul.text +22 -0
  213. data/test/testcases/block/09_html/html_to_native/options +1 -0
  214. data/test/testcases/block/09_html/html_to_native/paragraph.html +3 -0
  215. data/test/testcases/block/09_html/html_to_native/paragraph.text +4 -0
  216. data/test/testcases/block/09_html/html_to_native/table_normal.html +14 -0
  217. data/test/testcases/block/09_html/html_to_native/table_normal.text +12 -0
  218. data/test/testcases/block/09_html/html_to_native/table_simple.html +48 -0
  219. data/test/testcases/block/09_html/html_to_native/table_simple.text +56 -0
  220. data/test/testcases/block/09_html/html_to_native/typography.html +1 -0
  221. data/test/testcases/block/09_html/html_to_native/typography.html.19 +1 -0
  222. data/test/testcases/block/09_html/html_to_native/typography.text +1 -0
  223. data/test/testcases/block/09_html/invalid_html_1.html +5 -0
  224. data/test/testcases/block/09_html/invalid_html_1.text +5 -0
  225. data/test/testcases/block/09_html/invalid_html_2.html +5 -0
  226. data/test/testcases/block/09_html/invalid_html_2.text +5 -0
  227. data/test/testcases/block/09_html/markdown_attr.html +38 -0
  228. data/test/testcases/block/09_html/markdown_attr.text +38 -0
  229. data/test/testcases/block/09_html/not_parsed.html +24 -0
  230. data/test/testcases/block/09_html/not_parsed.text +24 -0
  231. data/test/testcases/block/09_html/parse_as_raw.html +30 -0
  232. data/test/testcases/block/09_html/parse_as_raw.options +1 -0
  233. data/test/testcases/block/09_html/parse_as_raw.text +29 -0
  234. data/test/testcases/block/09_html/parse_as_span.html +12 -0
  235. data/test/testcases/block/09_html/parse_as_span.options +1 -0
  236. data/test/testcases/block/09_html/parse_as_span.text +9 -0
  237. data/test/testcases/block/09_html/parse_block_html.html +21 -0
  238. data/test/testcases/block/09_html/parse_block_html.options +1 -0
  239. data/test/testcases/block/09_html/parse_block_html.text +17 -0
  240. data/test/testcases/block/09_html/processing_instruction.html +13 -0
  241. data/test/testcases/block/09_html/processing_instruction.text +12 -0
  242. data/test/testcases/block/09_html/simple.html +64 -0
  243. data/test/testcases/block/09_html/simple.html.19 +64 -0
  244. data/test/testcases/block/09_html/simple.options +1 -0
  245. data/test/testcases/block/09_html/simple.text +59 -0
  246. data/test/testcases/block/10_ald/simple.html +2 -0
  247. data/test/testcases/block/10_ald/simple.text +8 -0
  248. data/test/testcases/block/11_ial/auto_id_and_ial.html +1 -0
  249. data/test/testcases/block/11_ial/auto_id_and_ial.options +1 -0
  250. data/test/testcases/block/11_ial/auto_id_and_ial.text +2 -0
  251. data/test/testcases/block/11_ial/simple.html +25 -0
  252. data/test/testcases/block/11_ial/simple.text +34 -0
  253. data/test/testcases/block/12_extension/comment.html +8 -0
  254. data/test/testcases/block/12_extension/comment.text +12 -0
  255. data/test/testcases/block/12_extension/ignored.html +8 -0
  256. data/test/testcases/block/12_extension/ignored.text +8 -0
  257. data/test/testcases/block/12_extension/nomarkdown.html +10 -0
  258. data/test/testcases/block/12_extension/nomarkdown.kramdown +20 -0
  259. data/test/testcases/block/12_extension/nomarkdown.latex +13 -0
  260. data/test/testcases/block/12_extension/nomarkdown.text +21 -0
  261. data/test/testcases/block/12_extension/options.html +21 -0
  262. data/test/testcases/block/12_extension/options.text +21 -0
  263. data/test/testcases/block/12_extension/options2.html +10 -0
  264. data/test/testcases/block/12_extension/options2.text +5 -0
  265. data/test/testcases/block/12_extension/options3.html +7 -0
  266. data/test/testcases/block/12_extension/options3.text +7 -0
  267. data/test/testcases/block/13_definition_list/definition_at_beginning.html +1 -0
  268. data/test/testcases/block/13_definition_list/definition_at_beginning.text +1 -0
  269. data/test/testcases/block/13_definition_list/item_ial.html +12 -0
  270. data/test/testcases/block/13_definition_list/item_ial.text +8 -0
  271. data/test/testcases/block/13_definition_list/multiple_terms.html +13 -0
  272. data/test/testcases/block/13_definition_list/multiple_terms.text +10 -0
  273. data/test/testcases/block/13_definition_list/no_def_list.html +2 -0
  274. data/test/testcases/block/13_definition_list/no_def_list.text +2 -0
  275. data/test/testcases/block/13_definition_list/para_wrapping.html +10 -0
  276. data/test/testcases/block/13_definition_list/para_wrapping.text +6 -0
  277. data/test/testcases/block/13_definition_list/separated_by_eob.html +8 -0
  278. data/test/testcases/block/13_definition_list/separated_by_eob.text +5 -0
  279. data/test/testcases/block/13_definition_list/simple.html +8 -0
  280. data/test/testcases/block/13_definition_list/simple.text +7 -0
  281. data/test/testcases/block/13_definition_list/styled_terms.html +4 -0
  282. data/test/testcases/block/13_definition_list/styled_terms.text +2 -0
  283. data/test/testcases/block/13_definition_list/too_much_space.html +3 -0
  284. data/test/testcases/block/13_definition_list/too_much_space.text +4 -0
  285. data/test/testcases/block/13_definition_list/with_blocks.html +38 -0
  286. data/test/testcases/block/13_definition_list/with_blocks.text +24 -0
  287. data/test/testcases/block/14_table/errors.html +8 -0
  288. data/test/testcases/block/14_table/errors.text +9 -0
  289. data/test/testcases/block/14_table/footer.html +65 -0
  290. data/test/testcases/block/14_table/footer.text +25 -0
  291. data/test/testcases/block/14_table/header.html +103 -0
  292. data/test/testcases/block/14_table/header.text +32 -0
  293. data/test/testcases/block/14_table/no_table.html +3 -0
  294. data/test/testcases/block/14_table/no_table.text +3 -0
  295. data/test/testcases/block/14_table/simple.html +139 -0
  296. data/test/testcases/block/14_table/simple.text +38 -0
  297. data/test/testcases/block/15_math/normal.html +26 -0
  298. data/test/testcases/block/15_math/normal.text +28 -0
  299. data/test/testcases/block/16_toc/no_toc_depth.html +33 -0
  300. data/test/testcases/block/16_toc/no_toc_depth.options +1 -0
  301. data/test/testcases/block/16_toc/no_toc_depth.text +16 -0
  302. data/test/testcases/block/16_toc/toc_depth_2.html +24 -0
  303. data/test/testcases/block/16_toc/toc_depth_2.options +1 -0
  304. data/test/testcases/block/16_toc/toc_depth_2.text +16 -0
  305. data/test/testcases/encoding.html +46 -0
  306. data/test/testcases/encoding.text +28 -0
  307. data/test/testcases/span/01_link/empty.html +5 -0
  308. data/test/testcases/span/01_link/empty.text +5 -0
  309. data/test/testcases/span/01_link/image_in_a.html +5 -0
  310. data/test/testcases/span/01_link/image_in_a.text +5 -0
  311. data/test/testcases/span/01_link/imagelinks.html +14 -0
  312. data/test/testcases/span/01_link/imagelinks.text +16 -0
  313. data/test/testcases/span/01_link/inline.html +46 -0
  314. data/test/testcases/span/01_link/inline.html.19 +46 -0
  315. data/test/testcases/span/01_link/inline.text +48 -0
  316. data/test/testcases/span/01_link/link_defs.html +9 -0
  317. data/test/testcases/span/01_link/link_defs.text +26 -0
  318. data/test/testcases/span/01_link/links_with_angle_brackets.html +3 -0
  319. data/test/testcases/span/01_link/links_with_angle_brackets.text +3 -0
  320. data/test/testcases/span/01_link/reference.html +35 -0
  321. data/test/testcases/span/01_link/reference.html.19 +35 -0
  322. data/test/testcases/span/01_link/reference.text +47 -0
  323. data/test/testcases/span/02_emphasis/empty.html +3 -0
  324. data/test/testcases/span/02_emphasis/empty.text +3 -0
  325. data/test/testcases/span/02_emphasis/errors.html +9 -0
  326. data/test/testcases/span/02_emphasis/errors.text +9 -0
  327. data/test/testcases/span/02_emphasis/nesting.html +38 -0
  328. data/test/testcases/span/02_emphasis/nesting.text +33 -0
  329. data/test/testcases/span/02_emphasis/normal.html +46 -0
  330. data/test/testcases/span/02_emphasis/normal.text +46 -0
  331. data/test/testcases/span/03_codespan/empty.html +5 -0
  332. data/test/testcases/span/03_codespan/empty.text +5 -0
  333. data/test/testcases/span/03_codespan/errors.html +1 -0
  334. data/test/testcases/span/03_codespan/errors.text +1 -0
  335. data/test/testcases/span/03_codespan/highlighting.html +1 -0
  336. data/test/testcases/span/03_codespan/highlighting.text +1 -0
  337. data/test/testcases/span/03_codespan/normal.html +16 -0
  338. data/test/testcases/span/03_codespan/normal.text +16 -0
  339. data/test/testcases/span/04_footnote/definitions.html +17 -0
  340. data/test/testcases/span/04_footnote/definitions.latex +17 -0
  341. data/test/testcases/span/04_footnote/definitions.text +24 -0
  342. data/test/testcases/span/04_footnote/footnote_nr.html +12 -0
  343. data/test/testcases/span/04_footnote/footnote_nr.latex +2 -0
  344. data/test/testcases/span/04_footnote/footnote_nr.options +1 -0
  345. data/test/testcases/span/04_footnote/footnote_nr.text +4 -0
  346. data/test/testcases/span/04_footnote/markers.html +46 -0
  347. data/test/testcases/span/04_footnote/markers.latex +23 -0
  348. data/test/testcases/span/04_footnote/markers.text +26 -0
  349. data/test/testcases/span/05_html/across_lines.html +1 -0
  350. data/test/testcases/span/05_html/across_lines.text +2 -0
  351. data/test/testcases/span/05_html/invalid.html +1 -0
  352. data/test/testcases/span/05_html/invalid.text +1 -0
  353. data/test/testcases/span/05_html/link_with_mailto.html +1 -0
  354. data/test/testcases/span/05_html/link_with_mailto.text +1 -0
  355. data/test/testcases/span/05_html/markdown_attr.html +6 -0
  356. data/test/testcases/span/05_html/markdown_attr.text +6 -0
  357. data/test/testcases/span/05_html/normal.html +30 -0
  358. data/test/testcases/span/05_html/normal.text +30 -0
  359. data/test/testcases/span/abbreviations/abbrev.html +8 -0
  360. data/test/testcases/span/abbreviations/abbrev.text +15 -0
  361. data/test/testcases/span/abbreviations/abbrev_defs.html +2 -0
  362. data/test/testcases/span/abbreviations/abbrev_defs.text +5 -0
  363. data/test/testcases/span/autolinks/url_links.html +12 -0
  364. data/test/testcases/span/autolinks/url_links.text +12 -0
  365. data/test/testcases/span/escaped_chars/normal.html +43 -0
  366. data/test/testcases/span/escaped_chars/normal.text +43 -0
  367. data/test/testcases/span/extension/comment.html +6 -0
  368. data/test/testcases/span/extension/comment.text +6 -0
  369. data/test/testcases/span/extension/ignored.html +1 -0
  370. data/test/testcases/span/extension/ignored.text +1 -0
  371. data/test/testcases/span/extension/nomarkdown.html +1 -0
  372. data/test/testcases/span/extension/nomarkdown.text +1 -0
  373. data/test/testcases/span/extension/options.html +1 -0
  374. data/test/testcases/span/extension/options.text +1 -0
  375. data/test/testcases/span/ial/simple.html +6 -0
  376. data/test/testcases/span/ial/simple.text +6 -0
  377. data/test/testcases/span/line_breaks/normal.html +11 -0
  378. data/test/testcases/span/line_breaks/normal.latex +12 -0
  379. data/test/testcases/span/line_breaks/normal.text +11 -0
  380. data/test/testcases/span/math/normal.html +5 -0
  381. data/test/testcases/span/math/normal.text +5 -0
  382. data/test/testcases/span/text_substitutions/entities.html +4 -0
  383. data/test/testcases/span/text_substitutions/entities.options +1 -0
  384. data/test/testcases/span/text_substitutions/entities.text +4 -0
  385. data/test/testcases/span/text_substitutions/entities_as_char.html +1 -0
  386. data/test/testcases/span/text_substitutions/entities_as_char.html.19 +1 -0
  387. data/test/testcases/span/text_substitutions/entities_as_char.options +1 -0
  388. data/test/testcases/span/text_substitutions/entities_as_char.text +1 -0
  389. data/test/testcases/span/text_substitutions/entities_as_input.html +1 -0
  390. data/test/testcases/span/text_substitutions/entities_as_input.options +1 -0
  391. data/test/testcases/span/text_substitutions/entities_as_input.text +1 -0
  392. data/test/testcases/span/text_substitutions/entities_numeric.html +1 -0
  393. data/test/testcases/span/text_substitutions/entities_numeric.options +1 -0
  394. data/test/testcases/span/text_substitutions/entities_numeric.text +1 -0
  395. data/test/testcases/span/text_substitutions/entities_symbolic.html +1 -0
  396. data/test/testcases/span/text_substitutions/entities_symbolic.options +1 -0
  397. data/test/testcases/span/text_substitutions/entities_symbolic.text +1 -0
  398. data/test/testcases/span/text_substitutions/greaterthan.html +1 -0
  399. data/test/testcases/span/text_substitutions/greaterthan.text +1 -0
  400. data/test/testcases/span/text_substitutions/lowerthan.html +1 -0
  401. data/test/testcases/span/text_substitutions/lowerthan.text +1 -0
  402. data/test/testcases/span/text_substitutions/typography.html +18 -0
  403. data/test/testcases/span/text_substitutions/typography.html.19 +18 -0
  404. data/test/testcases/span/text_substitutions/typography.text +18 -0
  405. metadata +476 -0
@@ -0,0 +1,426 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009-2010 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of newstile.
7
+ #
8
+ # newstile 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
+
23
+ require 'rexml/parsers/baseparser'
24
+
25
+ module Newstile
26
+
27
+ module Converter
28
+
29
+ # Converts a Newstile::Document to the newstile format.
30
+ class Markdown < Base
31
+
32
+ # :stopdoc:
33
+
34
+ include ::Newstile::Utils::HTML
35
+
36
+ def initialize(doc)
37
+ super
38
+ @linkrefs = []
39
+ @footnotes = []
40
+ @abbrevs = []
41
+ @stack = []
42
+ end
43
+
44
+ def convert(el, opts = {:indent => 0})
45
+ res = send("convert_#{el.type}", el, opts)
46
+ if el.type != :html_element && el.type != :li && el.type != :dd && (ial = ial_for_element(el))
47
+ res << ial
48
+ res << "\n\n" if el.options[:category] == :block
49
+ elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] &&
50
+ ([el.type, :codeblock].include?(opts[:next].type) ||
51
+ (opts[:next].type == :blank && opts[:nnext] && [el.type, :codeblock].include?(opts[:nnext].type)))
52
+ res << "^\n\n"
53
+ elsif el.options[:category] == :block && ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) &&
54
+ (el.type != :p || !el.options[:transparent])
55
+ res << "\n"
56
+ end
57
+ res
58
+ end
59
+
60
+ def inner(el, opts = {:indent => 0})
61
+ @stack.push(el)
62
+ result = ''
63
+ el.children.each_with_index do |inner_el, index|
64
+ options = opts.dup
65
+ options[:index] = index
66
+ options[:prev] = (index == 0 ? nil : el.children[index-1])
67
+ options[:pprev] = (index <= 1 ? nil : el.children[index-2])
68
+ options[:next] = (index == el.children.length - 1 ? nil : el.children[index+1])
69
+ options[:nnext] = (index >= el.children.length - 2 ? nil : el.children[index+2])
70
+ result << convert(inner_el, options)
71
+ end
72
+ @stack.pop
73
+ result
74
+ end
75
+
76
+ def convert_blank(el, opts)
77
+ ""
78
+ end
79
+
80
+ ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]\{"'])|^[ ]{0,3}(:)/
81
+
82
+ def convert_text(el, opts)
83
+ if opts[:raw_text]
84
+ el.value
85
+ else
86
+ el.value.gsub(/\A\n/) do
87
+ opts[:prev] && opts[:prev].type == :br ? '' : "\n"
88
+ end.gsub(/\s+/, ' ').gsub(ESCAPED_CHAR_RE) { "\\#{$1 || $2}" }
89
+ end
90
+ end
91
+
92
+ def convert_p(el, opts)
93
+ w = @doc.options[:line_width] - opts[:indent].to_s.to_i
94
+ first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/)
95
+ first.gsub!(/^(?:(#)|(\d+)\.|([+-]\s))/) { $1 || $3 ? "\\#{$1 || $3}" : "#{$2}\\."}
96
+ first.gsub!(/\|/, '\\|')
97
+ second.gsub!(/^([=-]+\s*?)$/, "\\\1") if second
98
+ [first, second, *rest].compact.join("\n") + "\n"
99
+ end
100
+
101
+
102
+ def convert_codeblock(el, opts)
103
+ el.value.split(/\n/).map {|l| l.empty? ? " " : " #{l}"}.join("\n") + "\n"
104
+ end
105
+
106
+ def convert_blockquote(el, opts)
107
+ opts[:indent] += 2
108
+ inner(el, opts).chomp.split(/\n/).map {|l| "> #{l}"}.join("\n") << "\n"
109
+ end
110
+
111
+ def convert_summary(el, opts)
112
+ opts[:indent] += 2
113
+ inner(el, opts).chomp.split(/\n/).map {|l| "__#{l}__"}.join("\n") << "\n"
114
+ end
115
+
116
+ def convert_header(el, opts)
117
+ res = ''
118
+ res << "#{'#' * el.options[:level]} #{inner(el, opts)}"
119
+ res << " {##{el.attr['id']}}" if el.attr['id']
120
+ res << "\n"
121
+ end
122
+
123
+ def convert_hr(el, opts)
124
+ "* * *\n"
125
+ end
126
+
127
+ def convert_ul(el, opts)
128
+ inner(el, opts).sub(/\n+\Z/, "\n")
129
+ end
130
+ alias :convert_ol :convert_ul
131
+ alias :convert_dl :convert_ul
132
+
133
+ def convert_li(el, opts)
134
+ sym, width = if @stack.last.type == :ul
135
+ ['* ', el.children.first.type == :codeblock ? 4 : 2]
136
+ else
137
+ ["#{opts[:index] + 1}.".ljust(4), 4]
138
+ end
139
+ if ial = ial_for_element(el)
140
+ sym += ial + " "
141
+ end
142
+
143
+ opts[:indent] += width
144
+ text = inner(el, opts)
145
+ newlines = text.scan(/\n*\Z/).first
146
+ first, *last = text.split(/\n/)
147
+ last = last.map {|l| " "*width + l}.join("\n")
148
+ text = first + (last.empty? ? "" : "\n") + last + newlines
149
+ if el.children.first.type == :p && !el.children.first.options[:transparent]
150
+ res = "#{sym}#{text}"
151
+ res << "^\n" if el.children.size == 1 && @stack.last.children.last == el &&
152
+ (@stack.last.children.any? {|c| c.children.first.type != :p} || @stack.last.children.size == 1)
153
+ res
154
+ elsif el.children.first.type == :codeblock
155
+ "#{sym}\n #{text}"
156
+ else
157
+ "#{sym}#{text}"
158
+ end
159
+ end
160
+
161
+ def convert_dd(el, opts)
162
+ sym, width = ": ", (el.children.first.type == :codeblock ? 4 : 2)
163
+ if ial = ial_for_element(el)
164
+ sym += ial + " "
165
+ end
166
+
167
+ opts[:indent] += width
168
+ text = inner(el, opts)
169
+ newlines = text.scan(/\n*\Z/).first
170
+ first, *last = text.split(/\n/)
171
+ last = last.map {|l| " "*width + l}.join("\n")
172
+ text = first + (last.empty? ? "" : "\n") + last + newlines
173
+ text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd
174
+ text += "\n" if text !~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dt
175
+ if el.children.first.type == :p && !el.children.first.options[:transparent]
176
+ "\n#{sym}#{text}"
177
+ elsif el.children.first.type == :codeblock
178
+ "#{sym}\n #{text}"
179
+ else
180
+ "#{sym}#{text}"
181
+ end
182
+ end
183
+
184
+ def convert_dt(el, opts)
185
+ inner(el, opts) << "\n"
186
+ end
187
+
188
+ HTML_TAGS_WITH_BODY=['div', 'script', 'iframe', 'textarea']
189
+
190
+ def convert_html_element(el, opts)
191
+ markdown_attr = el.options[:category] == :block && el.children.any? do |c|
192
+ c.type != :html_element && (c.type != :p || !c.options[:transparent]) && c.options[:category] == :block
193
+ end
194
+ opts[:force_raw_text] = true if %w{script pre code}.include?(el.value)
195
+ opts[:raw_text] = opts[:force_raw_text] || opts[:block_raw_text] || (el.options[:category] != :span && !markdown_attr)
196
+ opts[:block_raw_text] = true if el.options[:category] == :block && opts[:raw_text]
197
+ res = inner(el, opts)
198
+ if el.options[:category] == :span
199
+ "<#{el.value}#{html_attributes(el)}" << (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}</#{el.value}>" : " />")
200
+ else
201
+ output = ''
202
+ output << "<#{el.value}#{html_attributes(el)}"
203
+ output << " markdown=\"1\"" if markdown_attr
204
+ if !res.empty? && el.options[:parse_type] != :block
205
+ output << ">#{res}</#{el.value}>"
206
+ elsif !res.empty?
207
+ output << ">\n#{res}" << "</#{el.value}>"
208
+ elsif HTML_TAGS_WITH_BODY.include?(el.value)
209
+ output << "></#{el.value}>"
210
+ else
211
+ output << " />"
212
+ end
213
+ output << "\n" if @stack.last.type != :html_element || @stack.last.options[:parse_type] != :raw
214
+ output
215
+ end
216
+ end
217
+
218
+ def convert_xml_comment(el, opts)
219
+ if el.options[:category] == :block && (@stack.last.type != :html_element || @stack.last.options[:parse_type] != :raw)
220
+ el.value + "\n"
221
+ else
222
+ el.value
223
+ end
224
+ end
225
+ alias :convert_xml_pi :convert_xml_comment
226
+ alias :convert_html_doctype :convert_xml_comment
227
+
228
+ def convert_table(el, opts)
229
+ opts[:alignment] = el.options[:alignment]
230
+ inner(el, opts)
231
+ end
232
+
233
+ def convert_thead(el, opts)
234
+ rows = inner(el, opts)
235
+ if opts[:alignment].all? {|a| a == :default}
236
+ "#{rows}|" + "-"*10 + "\n"
237
+ else
238
+ "#{rows}| " + opts[:alignment].map do |a|
239
+ case a
240
+ when :left then ":-"
241
+ when :right then "-:"
242
+ when :center then ":-:"
243
+ when :default then "-"
244
+ end
245
+ end.join(' ') + "\n"
246
+ end
247
+ end
248
+
249
+ def convert_tbody(el, opts)
250
+ res = ''
251
+ res << inner(el, opts)
252
+ res << '|' << '-'*10 << "\n" if opts[:next] && opts[:next].type == :tbody
253
+ res
254
+ end
255
+
256
+ def convert_tfoot(el, opts)
257
+ "|" + "="*10 + "\n#{inner(el, opts)}"
258
+ end
259
+
260
+ def convert_tr(el, opts)
261
+ "| " + el.children.map {|c| convert(c, opts)}.join(" | ") + " |\n"
262
+ end
263
+
264
+ def convert_td(el, opts)
265
+ inner(el, opts).gsub(/\|/, '\\|')
266
+ end
267
+ alias :convert_th :convert_td
268
+
269
+ def convert_comment(el, opts)
270
+ if el.options[:category] == :block
271
+ "{::comment}\n#{el.value}\n{:/}\n"
272
+ else
273
+ "{::comment}#{el.value}{:/}"
274
+ end
275
+ end
276
+
277
+ def convert_br(el, opts)
278
+ " \n"
279
+ end
280
+
281
+ def convert_a(el, opts)
282
+ if el.attr['href'].empty?
283
+ "[#{inner(el, opts)}]()"
284
+ elsif el.attr['href'] =~ /^(?:http|ftp)/ || el.attr['href'].count("()") > 0
285
+ index = if link_el = @linkrefs.find {|c| c.attr['href'] == el.attr['href']}
286
+ @linkrefs.index(link_el) + 1
287
+ else
288
+ @linkrefs << el
289
+ @linkrefs.size
290
+ end
291
+ "[#{inner(el, opts)}][#{index}]"
292
+ else
293
+ title = el.attr['title'].to_s.empty? ? '' : ' "' + el.attr['title'].gsub(/"/, "&quot;") + '"'
294
+ "[#{inner(el, opts)}](#{el.attr['href']}#{title})"
295
+ end
296
+ end
297
+
298
+ def convert_img(el, opts)
299
+ if el.attr['src'].empty?
300
+ "![#{el.attr['alt']}]()"
301
+ else
302
+ title = (el.attr['title'] ? ' "' + el.attr['title'].gsub(/"/, "&quot;") + '"' : '')
303
+ link = if el.attr['src'].count("()") > 0
304
+ "<#{el.attr['src']}>"
305
+ else
306
+ el.attr['src']
307
+ end
308
+ "![#{el.attr['alt']}](#{link}#{title})"
309
+ end
310
+ end
311
+
312
+ def convert_codespan(el, opts)
313
+ delim = (el.value.scan(/`+/).max || '') + '`'
314
+ "#{delim}#{' ' if delim.size > 1}#{el.value}#{' ' if delim.size > 1}#{delim}"
315
+ end
316
+
317
+ def convert_footnote(el, opts)
318
+ @footnotes << [el.options[:name], @doc.parse_infos[:footnotes][el.options[:name]]]
319
+ "[^#{el.options[:name]}]"
320
+ end
321
+
322
+ def convert_raw(el, opts)
323
+ attr = (el.options[:type] || []).join(' ')
324
+ attr = " type=\"#{attr}\"" if attr.length > 0
325
+ if @stack.last.type == :html_element
326
+ el.value
327
+ elsif el.options[:category] == :block
328
+ "{::nomarkdown#{attr}}\n#{el.value}\n{:/}\n"
329
+ else
330
+ "{::nomarkdown#{attr}}#{el.value}{:/}"
331
+ end
332
+ end
333
+
334
+ def convert_em(el, opts)
335
+ "*#{inner(el, opts)}*"
336
+ end
337
+
338
+ def convert_strong(el, opts)
339
+ "**#{inner(el, opts)}**"
340
+ end
341
+
342
+ def convert_entity(el, opts)
343
+ entity_to_str(el.value, el.options[:original])
344
+ end
345
+
346
+ TYPOGRAPHIC_SYMS = {
347
+ :mdash => '---', :ndash => '--', :qdash_space => '--- ', :qdash => '---', :hellip => '...',
348
+ :laquo_space => '<< ', :raquo_space => ' >>',
349
+ :laquo => '<<', :raquo => '>>'
350
+ }
351
+ def convert_typographic_sym(el, opts)
352
+ TYPOGRAPHIC_SYMS[el.value]
353
+ end
354
+
355
+ def convert_smart_quote(el, opts)
356
+ el.value.to_s =~ /[rl]dquo/ ? "\"" : "'"
357
+ end
358
+
359
+ def convert_math(el, opts)
360
+ (@stack.last.type == :p && opts[:prev].nil? ? "\\" : '') + "$$#{el.value}$$" + (el.options[:category] == :block ? "\n" : '')
361
+ end
362
+
363
+ def convert_abbreviation(el, opts)
364
+ el.value
365
+ end
366
+
367
+ def convert_root(el, opts)
368
+ res = inner(el, opts)
369
+ res << create_link_defs
370
+ res << create_footnote_defs
371
+ res << create_abbrev_defs
372
+ res
373
+ end
374
+
375
+ def create_link_defs
376
+ res = ''
377
+ res << "\n\n" if @linkrefs.size > 0
378
+ @linkrefs.each_with_index do |el, i|
379
+ title = el.attr['title']
380
+ res << "[#{i+1}]: #{el.attr['href']} #{title ? '"' + title.gsub(/"/, "&quot;") + '"' : ''}\n"
381
+ end
382
+ res
383
+ end
384
+
385
+ def create_footnote_defs
386
+ res = ''
387
+ @footnotes.each do |name, data|
388
+ res << "[^#{name}]:\n"
389
+ res << inner(data[:content]).chomp.split(/\n/).map {|l| " #{l}"}.join("\n") + "\n\n"
390
+ end
391
+ res
392
+ end
393
+
394
+ def create_abbrev_defs
395
+ return '' unless @doc.parse_infos[:abbrev_defs]
396
+ res = ''
397
+ @doc.parse_infos[:abbrev_defs].each do |name, text|
398
+ res << "*[#{name}]: #{text}\n"
399
+ end
400
+ res
401
+ end
402
+
403
+ # Return the IAL containing the attributes of the element +el+.
404
+ def ial_for_element(el)
405
+ res = el.attr.map do |k,v|
406
+ next if [:img, :a].include?(el.type) && ['href', 'src', 'alt', 'title'].include?(k)
407
+ next if el.type == :header && k == 'id'
408
+ if v.nil?
409
+ ''
410
+ elsif k == 'class'
411
+ " " + v.split(/\s+/).map {|w| ".#{w}"}.join(" ")
412
+ elsif k == 'id'
413
+ " ##{v}"
414
+ else
415
+ " #{k}=\"#{v.to_s}\""
416
+ end
417
+ end.compact.join('')
418
+ res = "toc" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) &&
419
+ (el.options[:ial][:refs].include?('toc') rescue nil)
420
+ res.strip.empty? ? nil : "{:#{res}}"
421
+ end
422
+
423
+ end
424
+
425
+ end
426
+ end
@@ -0,0 +1,426 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ #--
4
+ # Copyright (C) 2009-2010 Thomas Leitner <t_leitner@gmx.at>
5
+ #
6
+ # This file is part of newstile.
7
+ #
8
+ # newstile 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
+
23
+ require 'rexml/parsers/baseparser'
24
+
25
+ module Newstile
26
+
27
+ module Converter
28
+
29
+ # Converts a Newstile::Document to the newstile format.
30
+ class Newstile < Base
31
+
32
+ # :stopdoc:
33
+
34
+ include ::Newstile::Utils::HTML
35
+
36
+ def initialize(doc)
37
+ super
38
+ @linkrefs = []
39
+ @footnotes = []
40
+ @abbrevs = []
41
+ @stack = []
42
+ end
43
+
44
+ def convert(el, opts = {:indent => 0})
45
+ res = send("convert_#{el.type}", el, opts)
46
+ if el.type != :html_element && el.type != :li && el.type != :dd && (ial = ial_for_element(el))
47
+ res << ial
48
+ res << "\n\n" if el.options[:category] == :block
49
+ elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] &&
50
+ ([el.type, :codeblock].include?(opts[:next].type) ||
51
+ (opts[:next].type == :blank && opts[:nnext] && [el.type, :codeblock].include?(opts[:nnext].type)))
52
+ res << "^\n\n"
53
+ elsif el.options[:category] == :block && ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) &&
54
+ (el.type != :p || !el.options[:transparent])
55
+ res << "\n"
56
+ end
57
+ res
58
+ end
59
+
60
+ def inner(el, opts = {:indent => 0})
61
+ @stack.push(el)
62
+ result = ''
63
+ el.children.each_with_index do |inner_el, index|
64
+ options = opts.dup
65
+ options[:index] = index
66
+ options[:prev] = (index == 0 ? nil : el.children[index-1])
67
+ options[:pprev] = (index <= 1 ? nil : el.children[index-2])
68
+ options[:next] = (index == el.children.length - 1 ? nil : el.children[index+1])
69
+ options[:nnext] = (index >= el.children.length - 2 ? nil : el.children[index+2])
70
+ result << convert(inner_el, options)
71
+ end
72
+ @stack.pop
73
+ result
74
+ end
75
+
76
+ def convert_blank(el, opts)
77
+ ""
78
+ end
79
+
80
+ ESCAPED_CHAR_RE = /(\$\$|[\\*_`\[\]\{"'])|^[ ]{0,3}(:)/
81
+
82
+ def convert_text(el, opts)
83
+ if opts[:raw_text]
84
+ el.value
85
+ else
86
+ el.value.gsub(/\A\n/) do
87
+ opts[:prev] && opts[:prev].type == :br ? '' : "\n"
88
+ end.gsub(/\s+/, ' ').gsub(ESCAPED_CHAR_RE) { "\\#{$1 || $2}" }
89
+ end
90
+ end
91
+
92
+ def convert_p(el, opts)
93
+ w = @doc.options[:line_width] - opts[:indent].to_s.to_i
94
+ first, second, *rest = inner(el, opts).strip.gsub(/(.{1,#{w}})( +|$\n?)/, "\\1\n").split(/\n/)
95
+ first.gsub!(/^(?:(#)|(\d+)\.|([+-]\s))/) { $1 || $3 ? "\\#{$1 || $3}" : "#{$2}\\."}
96
+ first.gsub!(/\|/, '\\|')
97
+ second.gsub!(/^([=-]+\s*?)$/, "\\\1") if second
98
+ [first, second, *rest].compact.join("\n") + "\n"
99
+ end
100
+
101
+
102
+ def convert_codeblock(el, opts)
103
+ el.value.split(/\n/).map {|l| l.empty? ? " " : " #{l}"}.join("\n") + "\n"
104
+ end
105
+
106
+ def convert_blockquote(el, opts)
107
+ opts[:indent] += 2
108
+ inner(el, opts).chomp.split(/\n/).map {|l| "> #{l}"}.join("\n") << "\n"
109
+ end
110
+
111
+ def convert_summary(el, opts)
112
+ opts[:indent] += 2
113
+ inner(el, opts).chomp.split(/\n/).map {|l| "//. #{l}"}.join("\n") << "\n"
114
+ end
115
+
116
+ def convert_header(el, opts)
117
+ res = ''
118
+ res << "#{'!' * el.options[:level]} #{inner(el, opts)}"
119
+ res << " {##{el.attr['id']}}" if el.attr['id']
120
+ res << "\n"
121
+ end
122
+
123
+ def convert_hr(el, opts)
124
+ "* * *\n"
125
+ end
126
+
127
+ def convert_ul(el, opts)
128
+ inner(el, opts).sub(/\n+\Z/, "\n")
129
+ end
130
+ alias :convert_ol :convert_ul
131
+ alias :convert_dl :convert_ul
132
+
133
+ def convert_li(el, opts)
134
+ sym, width = if @stack.last.type == :ul
135
+ ['* ', el.children.first.type == :codeblock ? 4 : 2]
136
+ else
137
+ ["#{opts[:index] + 1}.".ljust(4), 4]
138
+ end
139
+ if ial = ial_for_element(el)
140
+ sym += ial + " "
141
+ end
142
+
143
+ opts[:indent] += width
144
+ text = inner(el, opts)
145
+ newlines = text.scan(/\n*\Z/).first
146
+ first, *last = text.split(/\n/)
147
+ last = last.map {|l| " "*width + l}.join("\n")
148
+ text = first + (last.empty? ? "" : "\n") + last + newlines
149
+ if el.children.first.type == :p && !el.children.first.options[:transparent]
150
+ res = "#{sym}#{text}"
151
+ res << "^\n" if el.children.size == 1 && @stack.last.children.last == el &&
152
+ (@stack.last.children.any? {|c| c.children.first.type != :p} || @stack.last.children.size == 1)
153
+ res
154
+ elsif el.children.first.type == :codeblock
155
+ "#{sym}\n #{text}"
156
+ else
157
+ "#{sym}#{text}"
158
+ end
159
+ end
160
+
161
+ def convert_dd(el, opts)
162
+ sym, width = ": ", (el.children.first.type == :codeblock ? 4 : 2)
163
+ if ial = ial_for_element(el)
164
+ sym += ial + " "
165
+ end
166
+
167
+ opts[:indent] += width
168
+ text = inner(el, opts)
169
+ newlines = text.scan(/\n*\Z/).first
170
+ first, *last = text.split(/\n/)
171
+ last = last.map {|l| " "*width + l}.join("\n")
172
+ text = first + (last.empty? ? "" : "\n") + last + newlines
173
+ text.chomp! if text =~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dd
174
+ text += "\n" if text !~ /\n\n\Z/ && opts[:next] && opts[:next].type == :dt
175
+ if el.children.first.type == :p && !el.children.first.options[:transparent]
176
+ "\n#{sym}#{text}"
177
+ elsif el.children.first.type == :codeblock
178
+ "#{sym}\n #{text}"
179
+ else
180
+ "#{sym}#{text}"
181
+ end
182
+ end
183
+
184
+ def convert_dt(el, opts)
185
+ inner(el, opts) << "\n"
186
+ end
187
+
188
+ HTML_TAGS_WITH_BODY=['div', 'script', 'iframe', 'textarea']
189
+
190
+ def convert_html_element(el, opts)
191
+ markdown_attr = el.options[:category] == :block && el.children.any? do |c|
192
+ c.type != :html_element && (c.type != :p || !c.options[:transparent]) && c.options[:category] == :block
193
+ end
194
+ opts[:force_raw_text] = true if %w{script pre code}.include?(el.value)
195
+ opts[:raw_text] = opts[:force_raw_text] || opts[:block_raw_text] || (el.options[:category] != :span && !markdown_attr)
196
+ opts[:block_raw_text] = true if el.options[:category] == :block && opts[:raw_text]
197
+ res = inner(el, opts)
198
+ if el.options[:category] == :span
199
+ "<#{el.value}#{html_attributes(el)}" << (!res.empty? || HTML_TAGS_WITH_BODY.include?(el.value) ? ">#{res}</#{el.value}>" : " />")
200
+ else
201
+ output = ''
202
+ output << "<#{el.value}#{html_attributes(el)}"
203
+ output << " markdown=\"1\"" if markdown_attr
204
+ if !res.empty? && el.options[:parse_type] != :block
205
+ output << ">#{res}</#{el.value}>"
206
+ elsif !res.empty?
207
+ output << ">\n#{res}" << "</#{el.value}>"
208
+ elsif HTML_TAGS_WITH_BODY.include?(el.value)
209
+ output << "></#{el.value}>"
210
+ else
211
+ output << " />"
212
+ end
213
+ output << "\n" if @stack.last.type != :html_element || @stack.last.options[:parse_type] != :raw
214
+ output
215
+ end
216
+ end
217
+
218
+ def convert_xml_comment(el, opts)
219
+ if el.options[:category] == :block && (@stack.last.type != :html_element || @stack.last.options[:parse_type] != :raw)
220
+ el.value + "\n"
221
+ else
222
+ el.value
223
+ end
224
+ end
225
+ alias :convert_xml_pi :convert_xml_comment
226
+ alias :convert_html_doctype :convert_xml_comment
227
+
228
+ def convert_table(el, opts)
229
+ opts[:alignment] = el.options[:alignment]
230
+ inner(el, opts)
231
+ end
232
+
233
+ def convert_thead(el, opts)
234
+ rows = inner(el, opts)
235
+ if opts[:alignment].all? {|a| a == :default}
236
+ "#{rows}|" + "-"*10 + "\n"
237
+ else
238
+ "#{rows}| " + opts[:alignment].map do |a|
239
+ case a
240
+ when :left then ":-"
241
+ when :right then "-:"
242
+ when :center then ":-:"
243
+ when :default then "-"
244
+ end
245
+ end.join(' ') + "\n"
246
+ end
247
+ end
248
+
249
+ def convert_tbody(el, opts)
250
+ res = ''
251
+ res << inner(el, opts)
252
+ res << '|' << '-'*10 << "\n" if opts[:next] && opts[:next].type == :tbody
253
+ res
254
+ end
255
+
256
+ def convert_tfoot(el, opts)
257
+ "|" + "="*10 + "\n#{inner(el, opts)}"
258
+ end
259
+
260
+ def convert_tr(el, opts)
261
+ "| " + el.children.map {|c| convert(c, opts)}.join(" | ") + " |\n"
262
+ end
263
+
264
+ def convert_td(el, opts)
265
+ inner(el, opts).gsub(/\|/, '\\|')
266
+ end
267
+ alias :convert_th :convert_td
268
+
269
+ def convert_comment(el, opts)
270
+ if el.options[:category] == :block
271
+ "{::comment}\n#{el.value}\n{:/}\n"
272
+ else
273
+ "{::comment}#{el.value}{:/}"
274
+ end
275
+ end
276
+
277
+ def convert_br(el, opts)
278
+ " \n"
279
+ end
280
+
281
+ def convert_a(el, opts)
282
+ if el.attr['href'].empty?
283
+ "[#{inner(el, opts)}]()"
284
+ elsif el.attr['href'] =~ /^(?:http|ftp)/ || el.attr['href'].count("()") > 0
285
+ index = if link_el = @linkrefs.find {|c| c.attr['href'] == el.attr['href']}
286
+ @linkrefs.index(link_el) + 1
287
+ else
288
+ @linkrefs << el
289
+ @linkrefs.size
290
+ end
291
+ "[#{inner(el, opts)}][#{index}]"
292
+ else
293
+ title = el.attr['title'].to_s.empty? ? '' : ' "' + el.attr['title'].gsub(/"/, "&quot;") + '"'
294
+ "[#{inner(el, opts)}](#{el.attr['href']}#{title})"
295
+ end
296
+ end
297
+
298
+ def convert_img(el, opts)
299
+ if el.attr['src'].empty?
300
+ "![#{el.attr['alt']}]()"
301
+ else
302
+ title = (el.attr['title'] ? ' "' + el.attr['title'].gsub(/"/, "&quot;") + '"' : '')
303
+ link = if el.attr['src'].count("()") > 0
304
+ "<#{el.attr['src']}>"
305
+ else
306
+ el.attr['src']
307
+ end
308
+ "![#{el.attr['alt']}](#{link}#{title})"
309
+ end
310
+ end
311
+
312
+ def convert_codespan(el, opts)
313
+ delim = (el.value.scan(/`+/).max || '') + '`'
314
+ "#{delim}#{' ' if delim.size > 1}#{el.value}#{' ' if delim.size > 1}#{delim}"
315
+ end
316
+
317
+ def convert_footnote(el, opts)
318
+ @footnotes << [el.options[:name], @doc.parse_infos[:footnotes][el.options[:name]]]
319
+ "[^#{el.options[:name]}]"
320
+ end
321
+
322
+ def convert_raw(el, opts)
323
+ attr = (el.options[:type] || []).join(' ')
324
+ attr = " type=\"#{attr}\"" if attr.length > 0
325
+ if @stack.last.type == :html_element
326
+ el.value
327
+ elsif el.options[:category] == :block
328
+ "{::nomarkdown#{attr}}\n#{el.value}\n{:/}\n"
329
+ else
330
+ "{::nomarkdown#{attr}}#{el.value}{:/}"
331
+ end
332
+ end
333
+
334
+ def convert_em(el, opts)
335
+ "*#{inner(el, opts)}*"
336
+ end
337
+
338
+ def convert_strong(el, opts)
339
+ "**#{inner(el, opts)}**"
340
+ end
341
+
342
+ def convert_entity(el, opts)
343
+ entity_to_str(el.value, el.options[:original])
344
+ end
345
+
346
+ TYPOGRAPHIC_SYMS = {
347
+ :mdash => '---', :ndash => '--', :qdash_space => '-. ', :qdash => '-.', :hellip => '...',
348
+ :laquo_space => '<< ', :raquo_space => ' >>',
349
+ :laquo => '<<', :raquo => '>>'
350
+ }
351
+ def convert_typographic_sym(el, opts)
352
+ TYPOGRAPHIC_SYMS[el.value]
353
+ end
354
+
355
+ def convert_smart_quote(el, opts)
356
+ el.value.to_s =~ /[rl]dquo/ ? "\"" : "'"
357
+ end
358
+
359
+ def convert_math(el, opts)
360
+ (@stack.last.type == :p && opts[:prev].nil? ? "\\" : '') + "$$#{el.value}$$" + (el.options[:category] == :block ? "\n" : '')
361
+ end
362
+
363
+ def convert_abbreviation(el, opts)
364
+ el.value
365
+ end
366
+
367
+ def convert_root(el, opts)
368
+ res = inner(el, opts)
369
+ res << create_link_defs
370
+ res << create_footnote_defs
371
+ res << create_abbrev_defs
372
+ res
373
+ end
374
+
375
+ def create_link_defs
376
+ res = ''
377
+ res << "\n\n" if @linkrefs.size > 0
378
+ @linkrefs.each_with_index do |el, i|
379
+ title = el.attr['title']
380
+ res << "[#{i+1}]: #{el.attr['href']} #{title ? '"' + title.gsub(/"/, "&quot;") + '"' : ''}\n"
381
+ end
382
+ res
383
+ end
384
+
385
+ def create_footnote_defs
386
+ res = ''
387
+ @footnotes.each do |name, data|
388
+ res << "[^#{name}]:\n"
389
+ res << inner(data[:content]).chomp.split(/\n/).map {|l| " #{l}"}.join("\n") + "\n\n"
390
+ end
391
+ res
392
+ end
393
+
394
+ def create_abbrev_defs
395
+ return '' unless @doc.parse_infos[:abbrev_defs]
396
+ res = ''
397
+ @doc.parse_infos[:abbrev_defs].each do |name, text|
398
+ res << "*[#{name}]: #{text}\n"
399
+ end
400
+ res
401
+ end
402
+
403
+ # Return the IAL containing the attributes of the element +el+.
404
+ def ial_for_element(el)
405
+ res = el.attr.map do |k,v|
406
+ next if [:img, :a].include?(el.type) && ['href', 'src', 'alt', 'title'].include?(k)
407
+ next if el.type == :header && k == 'id'
408
+ if v.nil?
409
+ ''
410
+ elsif k == 'class'
411
+ " " + v.split(/\s+/).map {|w| ".#{w}"}.join(" ")
412
+ elsif k == 'id'
413
+ " ##{v}"
414
+ else
415
+ " #{k}=\"#{v.to_s}\""
416
+ end
417
+ end.compact.join('')
418
+ res = "toc" + (res.strip.empty? ? '' : " #{res}") if (el.type == :ul || el.type == :ol) &&
419
+ (el.options[:ial][:refs].include?('toc') rescue nil)
420
+ res.strip.empty? ? nil : "{:#{res}}"
421
+ end
422
+
423
+ end
424
+
425
+ end
426
+ end