maruku 0.4.2.1 → 0.5.0

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 (85) hide show
  1. data/bin/maruku +66 -20
  2. data/bin/marutest +12 -2
  3. data/docs/changelog.html +188 -23
  4. data/docs/changelog.md +128 -5
  5. data/docs/entity_test.html +245 -240
  6. data/docs/entity_test.md +2 -0
  7. data/docs/exd.html +181 -23
  8. data/docs/index.html +130 -349
  9. data/docs/markdown_syntax.html +55 -51
  10. data/docs/maruku.html +130 -349
  11. data/docs/maruku.md +154 -339
  12. data/docs/math.md +143 -0
  13. data/docs/proposal.html +16 -12
  14. data/lib/maruku.rb +6 -3
  15. data/lib/maruku/attributes.rb +7 -2
  16. data/lib/maruku/defaults.rb +27 -27
  17. data/lib/maruku/errors_management.rb +10 -9
  18. data/lib/maruku/ext/diagrams/diagrams.rb +8 -0
  19. data/lib/maruku/ext/diagrams/grid.rb +78 -0
  20. data/lib/maruku/ext/diagrams/inspect.rb +11 -0
  21. data/lib/maruku/ext/diagrams/layout.rb +105 -0
  22. data/lib/maruku/ext/diagrams/parser.rb +219 -0
  23. data/lib/maruku/ext/diagrams/structures.rb +168 -0
  24. data/lib/maruku/ext/diagrams/to_html.rb +37 -0
  25. data/lib/maruku/ext/diagrams/to_latex.rb +308 -0
  26. data/lib/maruku/ext/diagrams/unittest.rb +123 -0
  27. data/lib/maruku/ext/math.rb +11 -0
  28. data/lib/maruku/ext/math/elements.rb +26 -0
  29. data/lib/maruku/ext/math/mathml_engines/blahtex.rb +108 -0
  30. data/lib/maruku/ext/math/mathml_engines/itex2mml.rb +29 -0
  31. data/lib/maruku/ext/math/mathml_engines/none.rb +20 -0
  32. data/lib/maruku/ext/math/mathml_engines/ritex.rb +24 -0
  33. data/lib/maruku/ext/math/parsing.rb +82 -0
  34. data/lib/maruku/ext/math/to_html.rb +178 -0
  35. data/lib/maruku/ext/math/to_latex.rb +21 -0
  36. data/lib/maruku/helpers.rb +11 -0
  37. data/lib/maruku/input/charsource.rb +1 -1
  38. data/lib/maruku/input/extensions.rb +68 -0
  39. data/lib/maruku/input/html_helper.rb +91 -60
  40. data/lib/maruku/input/parse_block.rb +10 -9
  41. data/lib/maruku/input/parse_doc.rb +21 -13
  42. data/lib/maruku/input/parse_span_better.rb +19 -8
  43. data/lib/maruku/input/type_detection.rb +5 -3
  44. data/lib/maruku/output/to_html.rb +236 -67
  45. data/lib/maruku/output/to_latex.rb +69 -26
  46. data/lib/maruku/output/to_latex_entities.rb +14 -2
  47. data/lib/maruku/output/to_s.rb +8 -0
  48. data/lib/maruku/structures.rb +1 -1
  49. data/lib/maruku/tests/benchmark.rb +2 -2
  50. data/lib/maruku/tests/new_parser.rb +13 -5
  51. data/lib/maruku/version.rb +1 -1
  52. data/lib/sort_prof.rb +22 -0
  53. data/tests/diagrams/diagrams.md +54 -0
  54. data/tests/math/syntax.md +46 -0
  55. data/tests/math_usage/document.md +13 -0
  56. data/tests/unittest/attributes/attributes.md +50 -6
  57. data/tests/unittest/easy.md +1 -1
  58. data/tests/unittest/email.md +3 -3
  59. data/tests/unittest/entities.md +12 -7
  60. data/tests/unittest/escaping.md +4 -4
  61. data/tests/unittest/extra_table1.md +3 -1
  62. data/tests/unittest/footnotes.md +5 -5
  63. data/tests/unittest/headers.md +3 -3
  64. data/tests/unittest/images.md +7 -7
  65. data/tests/unittest/inline_html.md +51 -5
  66. data/tests/unittest/links.md +7 -7
  67. data/tests/unittest/list2.md +1 -1
  68. data/tests/unittest/lists.md +1 -1
  69. data/tests/unittest/lists_after_paragraph.md +1 -1
  70. data/tests/unittest/lists_ol.md +1 -1
  71. data/tests/unittest/math/equations.md +82 -0
  72. data/tests/unittest/math/inline.md +80 -0
  73. data/tests/unittest/math/table.md +51 -0
  74. data/tests/unittest/math/table2.md +67 -0
  75. data/tests/unittest/misc_sw.md +24 -24
  76. data/tests/unittest/notyet/ticks.md +1 -1
  77. data/tests/unittest/references/long_example.md +2 -2
  78. data/tests/unittest/smartypants.md +4 -4
  79. data/tests/unittest/xml.md +68 -0
  80. data/tests/unittest/xml2.md +36 -0
  81. data/tests/unittest/xml3.md +52 -0
  82. data/tests/unittest/xml_instruction.md +5 -5
  83. metadata +33 -4
  84. data/docs/a.html +0 -6
  85. data/docs/char.html +0 -1924
@@ -0,0 +1,11 @@
1
+
2
+
3
+ require 'maruku/ext/math/elements'
4
+ require 'maruku/ext/math/parsing'
5
+ require 'maruku/ext/math/to_latex'
6
+ require 'maruku/ext/math/to_html'
7
+
8
+ require 'maruku/ext/math/mathml_engines/none'
9
+ require 'maruku/ext/math/mathml_engines/ritex'
10
+ require 'maruku/ext/math/mathml_engines/itex2mml'
11
+ require 'maruku/ext/math/mathml_engines/blahtex'
@@ -0,0 +1,26 @@
1
+ module MaRuKu; class MDElement
2
+
3
+ def md_inline_math(math)
4
+ self.md_el(:inline_math, [], meta={:math=>math})
5
+ end
6
+
7
+ def md_equation(math, label=nil)
8
+ reglabel= /\\label\{(\w+)\}/
9
+ if math =~ reglabel
10
+ label = $1
11
+ math.gsub!(reglabel,'')
12
+ end
13
+ # puts "Found label = #{label} math #{math.inspect} "
14
+ num = nil
15
+ if label && @doc #take number
16
+ @doc.eqid2eq ||= {}
17
+ num = @doc.eqid2eq.size + 1
18
+ end
19
+ e = self.md_el(:equation, [], meta={:math=>math, :label=>label,:num=>num})
20
+ if label && @doc #take number
21
+ @doc.eqid2eq[label] = e
22
+ end
23
+ e
24
+ end
25
+
26
+ end end
@@ -0,0 +1,108 @@
1
+
2
+ require 'tempfile'
3
+ require 'fileutils'
4
+ require 'digest/md5'
5
+ require 'pstore'
6
+
7
+ module MaRuKu; module Out; module HTML
8
+
9
+ PNG = Struct.new(:src,:depth,:height)
10
+
11
+ def convert_to_png_blahtex(kind, tex)
12
+ begin
13
+ FileUtils::mkdir_p MaRuKu::Globals[:html_png_dir]
14
+
15
+ # first, we check whether this image has already been processed
16
+ md5sum = Digest::MD5.hexdigest(tex+" params: ")
17
+ result_file = File.join(MaRuKu::Globals[:html_png_dir], md5sum+".txt")
18
+
19
+ if not File.exists?(result_file)
20
+ tmp_in = Tempfile.new('maruku_blahtex')
21
+ f = tmp_in.open
22
+ f.write tex
23
+ f.close
24
+
25
+ resolution = get_setting(:html_png_resolution)
26
+
27
+ options = "--png --use-preview-package --shell-dvipng 'dvipng -D #{resolution}' "
28
+ options += ("--png-directory '%s'" % MaRuKu::Globals[:html_png_dir])
29
+
30
+ cmd = "blahtex #{options} < #{tmp_in.path} > #{result_file}"
31
+ $stderr.puts "$ #{cmd}"
32
+ system cmd
33
+ tmp_in.delete
34
+
35
+ end
36
+
37
+ result = nil
38
+ f = File.open(result_file)
39
+ result = f.read
40
+ f.close
41
+
42
+
43
+ doc = Document.new(result, {:respect_whitespace =>:all})
44
+ png = doc.root.elements[1]
45
+ if png.name != 'png'
46
+ maruku_error "Blahtex error: \n#{doc}"
47
+ return nil
48
+ end
49
+ depth = png.elements['depth'] || (raise "No depth element in:\n #{doc}")
50
+ height = png.elements['height'] || (raise "No height element in:\n #{doc}")
51
+ md5 = png.elements['md5'] || (raise "No md5 element in:\n #{doc}")
52
+
53
+ depth = depth.text.to_f
54
+ height = height.text.to_f # XXX check != 0
55
+ md5 = md5.text
56
+
57
+ dir_url = MaRuKu::Globals[:html_png_url]
58
+ return PNG.new("#{dir_url}#{md5}.png", depth, height)
59
+
60
+ rescue Exception => e
61
+ maruku_error "Error: #{e}"
62
+ end
63
+ nil
64
+ end
65
+
66
+ BlahtexCache = PStore.new("blahtex_cache.pstore")
67
+
68
+ def convert_to_mathml_blahtex(kind, tex)
69
+ begin
70
+ BlahtexCache.transaction do
71
+ if BlahtexCache[tex].nil?
72
+ tmp_in = Tempfile.new('maruku_blahtex')
73
+ f = tmp_in.open
74
+ f.write tex
75
+ f.close
76
+ tmp_out = Tempfile.new('maruku_blahtex')
77
+
78
+ options = "--mathml"
79
+ cmd = "blahtex #{options} < #{tmp_in.path} > #{tmp_out.path}"
80
+ $stderr.puts "$ #{cmd}"
81
+ system cmd
82
+ tmp_in.delete
83
+
84
+ result = nil
85
+ File.open(tmp_out.path) do |f| result=f.read end
86
+ puts result
87
+
88
+ BlahtexCache[tex] = result
89
+ end
90
+
91
+ blahtex = BlahtexCache[tex]
92
+ doc = Document.new(blahtex, {:respect_whitespace =>:all})
93
+ mathml = doc.root.elements['mathml']
94
+ if not mathml
95
+ maruku_error "Blahtex error: \n#{doc}"
96
+ return nil
97
+ else
98
+ return mathml
99
+ end
100
+ end
101
+
102
+ rescue Exception => e
103
+ maruku_error "Error: #{e}"
104
+ end
105
+ nil
106
+ end
107
+
108
+ end end end
@@ -0,0 +1,29 @@
1
+
2
+ module MaRuKu; module Out; module HTML
3
+
4
+ def convert_to_mathml_itex2mml(kind, tex)
5
+ begin
6
+ if not $itex2mml_parser
7
+ require 'itextomml'
8
+ $itex2mml_parser = Itex2MML::Parser.new
9
+ end
10
+
11
+ itex_method = {:equation=>:block_filter,:inline=>:inline_filter}
12
+
13
+ mathml = $itex2mml_parser.send(itex_method[kind], tex)
14
+ doc = Document.new(mathml, {:respect_whitespace =>:all}).root
15
+ return doc
16
+ rescue LoadError => e
17
+ maruku_error "Could not load package 'itex2mml'.\n"+
18
+ "Please install it."
19
+ rescue REXML::ParseException => e
20
+ maruku_error "Invalid MathML TeX: \n#{add_tabs(tex,1,'tex>')}"+
21
+ "\n\n #{e.inspect}"
22
+ rescue
23
+ maruku_error "Could not produce MathML TeX: \n#{tex}"+
24
+ "\n\n #{e.inspect}"
25
+ end
26
+ nil
27
+ end
28
+
29
+ end end end
@@ -0,0 +1,20 @@
1
+ module MaRuKu; module Out; module HTML
2
+
3
+ def convert_to_mathml_none(kind, tex)
4
+ # You can: either return a REXML::Element
5
+ # return Element.new 'div'
6
+ # or return an empty array on error
7
+ # return []
8
+ # or have a string parsed by REXML:
9
+ tex = tex.gsub('&','&amp;')
10
+ mathml = "<code>#{tex}</code>"
11
+ return Document.new(mathml).root
12
+ end
13
+
14
+ def convert_to_png_none(kind, tex)
15
+ return nil
16
+ end
17
+
18
+
19
+ end end end
20
+
@@ -0,0 +1,24 @@
1
+ module MaRuKu; module Out; module HTML
2
+
3
+ def convert_to_mathml_ritex(kind, tex)
4
+ begin
5
+ if not $ritex_parser
6
+ require 'ritex'
7
+ $ritex_parser = Ritex::Parser.new
8
+ end
9
+
10
+ mathml = $ritex_parser.parse(tex.strip)
11
+ doc = Document.new(mathml, {:respect_whitespace =>:all}).root
12
+ return doc
13
+ rescue LoadError => e
14
+ maruku_error "Could not load package 'ritex'.\n"+
15
+ "Please install it using:\n"+
16
+ " $ gem install ritex\n\n"+e.inspect
17
+ rescue Racc::ParseError => e
18
+ maruku_error "Could not parse TeX: \n#{tex}"+
19
+ "\n\n #{e.inspect}"
20
+ end
21
+ nil
22
+ end
23
+
24
+ end end end
@@ -0,0 +1,82 @@
1
+ module MaRuKu
2
+ class MDDocument
3
+ # Hash equation id (String) to equation element (MDElement)
4
+ attr_accessor :eqid2eq
5
+ end
6
+ end
7
+
8
+
9
+ # At least one slash inside
10
+ #RegInlineMath1 = /\$([^\$]*[\\][^\$]*)\$/
11
+ # No spaces around the delimiters
12
+ #RegInlineMath2 = /\$([^\s\$](?:[^\$]*[^\s\$])?)\$/
13
+ #RegInlineMath = Regexp::union(RegInlineMath1,RegInlineMath2)
14
+
15
+ # Everything goes; takes care of escaping the "\$" inside the expression
16
+ RegInlineMath = /\${1}((?:[^\$]|\\\$)+)\$/
17
+
18
+ MaRuKu::In::Markdown::
19
+ register_span_extension(:chars => ?$, :regexp => RegInlineMath) do
20
+ |doc, src, con|
21
+ if m = src.read_regexp(RegInlineMath)
22
+ math = m.captures.compact.first
23
+ con.push doc.md_inline_math(math)
24
+ true
25
+ else
26
+ #puts "not math: #{src.cur_chars 10}"
27
+ false
28
+ end
29
+ end
30
+
31
+ EquationStart = /^[ ]{0,3}(?:\\\[|\$\$)(.*)$/
32
+
33
+ EqLabel = /(?:\((\w+)\))/
34
+ OneLineEquation = /^[ ]{0,3}(?:\\\[|\$\$)(.*)(?:\\\]|\$\$)\s*#{EqLabel}?\s*$/
35
+ EquationEnd = /^(.*)(?:\\\]|\$\$)\s*#{EqLabel}?\s*$/
36
+
37
+ MaRuKu::In::Markdown::
38
+ register_block_extension(:regexp => EquationStart) do |doc, src, con|
39
+ # puts "Equation :#{self}"
40
+ first = src.shift_line
41
+ if first =~ OneLineEquation
42
+ math = $1
43
+ label = $2
44
+ con.push doc.md_equation($1, $2)
45
+ else
46
+ first =~ EquationStart
47
+ math = $1
48
+ label = nil
49
+ while true
50
+ if not src.cur_line
51
+ maruku_error "Stream finished while reading equation\n\n"+
52
+ add_tabs(math,1,'$> '), src, con
53
+ break
54
+ end
55
+ line = src.shift_line
56
+ if line =~ EquationEnd
57
+ math += $1 + "\n"
58
+ label = $2 if $2
59
+ break
60
+ else
61
+ math += line + "\n"
62
+ end
63
+ end
64
+ con.push doc.md_equation(math, label)
65
+ end
66
+ true
67
+ end
68
+
69
+
70
+ # This adds support for \eqref
71
+ RegEqrefLatex = /\\eqref\{(\w+)\}/
72
+ RegEqPar = /\(eq:(\w+)\)/
73
+ RegEqref = Regexp::union(RegEqrefLatex, RegEqPar)
74
+
75
+ MaRuKu::In::Markdown::
76
+ register_span_extension(:chars => [?\\, ?(], :regexp => RegEqref) do
77
+ |doc, src, con|
78
+ eqid = src.read_regexp(RegEqref).captures.compact.first
79
+ r = doc.md_el(:eqref, [], meta={:eqid=>eqid})
80
+ con.push r
81
+ true
82
+ end
@@ -0,0 +1,178 @@
1
+
2
+ =begin maruku_doc
3
+ Extension: math
4
+ Attribute: html_math_engine
5
+ Scope: document, element
6
+ Output: html
7
+ Summary: Select the rendering engine for MathML.
8
+ Default: <?mrk Globals[:html_math_engine].to_s ?>
9
+
10
+ Select the rendering engine for math.
11
+
12
+ If you want to use your custom engine `foo`, then set:
13
+
14
+ HTML math engine: foo
15
+ {:lang=markdown}
16
+
17
+ and then implement two functions:
18
+
19
+ def convert_to_mathml_foo(kind, tex)
20
+ ...
21
+ end
22
+ =end
23
+
24
+ =begin maruku_doc
25
+ Extension: math
26
+ Attribute: html_png_engine
27
+ Scope: document, element
28
+ Output: html
29
+ Summary: Select the rendering engine for math.
30
+ Default: <?mrk Globals[:html_math_engine].to_s ?>
31
+
32
+ Same thing as `html_math_engine`, only for PNG output.
33
+
34
+ def convert_to_png_foo(kind, tex)
35
+ # same thing
36
+ ...
37
+ end
38
+ {:lang=ruby}
39
+
40
+ =end
41
+
42
+ module MaRuKu; module Out; module HTML
43
+
44
+
45
+ def add_class_to(el, cl)
46
+ el.attributes['class'] =
47
+ if already = el.attributes['class']
48
+ already + " " + cl
49
+ else
50
+ cl
51
+ end
52
+ end
53
+
54
+ # Creates an xml Mathml document of self.math
55
+ def render_mathml(kind, tex)
56
+ engine = get_setting(:html_math_engine)
57
+ method = "convert_to_mathml_#{engine}".to_sym
58
+ if self.respond_to? method
59
+ mathml = self.send(method, kind, tex)
60
+ return mathml || convert_to_mathml_none(kind, tex)
61
+ else
62
+ puts "A method called #{method} should be defined."
63
+ return convert_to_mathml_none(kind, tex)
64
+ end
65
+ end
66
+
67
+ # Creates an xml Mathml document of self.math
68
+ def render_png(kind, tex)
69
+ engine = get_setting(:html_png_engine)
70
+ method = "convert_to_png_#{engine}".to_sym
71
+ if self.respond_to? method
72
+ return self.send(method, kind, tex)
73
+ else
74
+ puts "A method called #{method} should be defined."
75
+ return nil
76
+ end
77
+ end
78
+
79
+ def pixels_per_ex
80
+ if not $pixels_per_ex
81
+ x = render_png(:inline, "x")
82
+ $pixels_per_ex = x.height # + x.depth
83
+ end
84
+ $pixels_per_ex
85
+ end
86
+
87
+ def adjust_png(png, use_depth)
88
+ src = png.src
89
+
90
+ height_in_px = png.height
91
+ depth_in_px = png.depth
92
+ height_in_ex = height_in_px / pixels_per_ex
93
+ depth_in_ex = depth_in_px / pixels_per_ex
94
+ total_height_in_ex = height_in_ex + depth_in_ex
95
+ style = ""
96
+ style += "vertical-align: -#{depth_in_ex}ex;" if use_depth
97
+ style += "height: #{total_height_in_ex}ex;"
98
+ img = Element.new 'img'
99
+ img.attributes['src'] = src
100
+ img.attributes['style'] = style
101
+ img.attributes['alt'] = "equation"
102
+ img
103
+ end
104
+
105
+ def to_html_inline_math
106
+ mathml = render_mathml(:inline, self.math)
107
+ png = render_png(:inline, self.math)
108
+
109
+ span = create_html_element 'span'
110
+ add_class_to(span, 'maruku-inline')
111
+
112
+ if mathml
113
+ add_class_to(mathml, 'maruku-mathml')
114
+ span << mathml
115
+ end
116
+
117
+ if png
118
+ img = adjust_png(png, use_depth=true)
119
+ add_class_to(img, 'maruku-png')
120
+ span << img
121
+ end
122
+ span
123
+
124
+ end
125
+
126
+ def to_html_equation
127
+ mathml = render_mathml(:equation, self.math)
128
+ png = render_png(:equation, self.math)
129
+
130
+ div = create_html_element 'div'
131
+ add_class_to(div, 'maruku-equation')
132
+ if self.label # then numerate
133
+ span = Element.new 'span'
134
+ span.attributes['class'] = 'maruku-eq-number'
135
+ num = self.num
136
+ span << Text.new("(#{num})")
137
+ div << span
138
+ div.attributes['id'] = "eq:#{self.label}"
139
+ end
140
+
141
+ if mathml
142
+ add_class_to(mathml, 'maruku-mathml')
143
+ div << mathml
144
+ end
145
+
146
+ if png
147
+ img = adjust_png(png, use_depth=false)
148
+ add_class_to(img, 'maruku-png')
149
+ div << img
150
+ end
151
+
152
+ source_div = Element.new 'div'
153
+ add_class_to(source_div, 'maruku-eq-tex')
154
+ code = convert_to_mathml_none(:equation, self.math)
155
+ code.attributes['style'] = 'display: none'
156
+ source_div << code
157
+ div << source_div
158
+ div
159
+ end
160
+
161
+ def to_html_eqref
162
+ if eq = self.doc.eqid2eq[self.eqid]
163
+ num = eq.num
164
+ a = Element.new 'a'
165
+ a.attributes['class'] = 'maruku-eqref'
166
+ a.attributes['href'] = "#eq:#{self.eqid}"
167
+ a << Text.new("(#{num})")
168
+ a
169
+ else
170
+ maruku_error "Cannot find equation #{self.eqid.inspect}"
171
+ Text.new "(eq:#{self.eqid})"
172
+ end
173
+ end
174
+
175
+
176
+ end end end
177
+
178
+