maiku 0.6.1.maiku

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 (44) hide show
  1. data/lib/maruku.rb +141 -0
  2. data/lib/maruku/attributes.rb +175 -0
  3. data/lib/maruku/defaults.rb +71 -0
  4. data/lib/maruku/errors_management.rb +92 -0
  5. data/lib/maruku/ext/div.rb +133 -0
  6. data/lib/maruku/ext/math.rb +41 -0
  7. data/lib/maruku/ext/math/elements.rb +27 -0
  8. data/lib/maruku/ext/math/latex_fix.rb +12 -0
  9. data/lib/maruku/ext/math/mathml_engines/blahtex.rb +107 -0
  10. data/lib/maruku/ext/math/mathml_engines/itex2mml.rb +29 -0
  11. data/lib/maruku/ext/math/mathml_engines/none.rb +20 -0
  12. data/lib/maruku/ext/math/mathml_engines/ritex.rb +24 -0
  13. data/lib/maruku/ext/math/parsing.rb +119 -0
  14. data/lib/maruku/ext/math/to_html.rb +187 -0
  15. data/lib/maruku/ext/math/to_latex.rb +26 -0
  16. data/lib/maruku/helpers.rb +260 -0
  17. data/lib/maruku/input/charsource.rb +326 -0
  18. data/lib/maruku/input/extensions.rb +69 -0
  19. data/lib/maruku/input/html_helper.rb +189 -0
  20. data/lib/maruku/input/linesource.rb +111 -0
  21. data/lib/maruku/input/parse_block.rb +616 -0
  22. data/lib/maruku/input/parse_doc.rb +232 -0
  23. data/lib/maruku/input/parse_span_better.rb +746 -0
  24. data/lib/maruku/input/rubypants.rb +225 -0
  25. data/lib/maruku/input/type_detection.rb +147 -0
  26. data/lib/maruku/input_textile2/t2_parser.rb +163 -0
  27. data/lib/maruku/maruku.rb +33 -0
  28. data/lib/maruku/output/s5/fancy.rb +756 -0
  29. data/lib/maruku/output/s5/to_s5.rb +138 -0
  30. data/lib/maruku/output/to_html.rb +991 -0
  31. data/lib/maruku/output/to_latex.rb +590 -0
  32. data/lib/maruku/output/to_latex_entities.rb +367 -0
  33. data/lib/maruku/output/to_latex_strings.rb +64 -0
  34. data/lib/maruku/output/to_markdown.rb +164 -0
  35. data/lib/maruku/output/to_s.rb +56 -0
  36. data/lib/maruku/string_utils.rb +201 -0
  37. data/lib/maruku/structures.rb +167 -0
  38. data/lib/maruku/structures_inspect.rb +87 -0
  39. data/lib/maruku/structures_iterators.rb +61 -0
  40. data/lib/maruku/textile2.rb +1 -0
  41. data/lib/maruku/toc.rb +199 -0
  42. data/lib/maruku/usage/example1.rb +33 -0
  43. data/lib/maruku/version.rb +39 -0
  44. metadata +167 -0
@@ -0,0 +1,133 @@
1
+
2
+
3
+ #+-----------------------------------{.warning}------
4
+ #| this is the last warning!
5
+ #|
6
+ #| please, go away!
7
+ #|
8
+ #| +------------------------------------- {.menace} --
9
+ #| | or else terrible things will happen
10
+ #| +--------------------------------------------------
11
+ #+---------------------------------------------------
12
+
13
+ OpenDiv = /^[ ]{0,3}\+\-\-+\s*(\{([^{}]*|".*"|'.*')*\})?\s*\-*\s*$/
14
+ CloseDiv = /^[ ]{0,3}\=\-\-+\s*(\{([^{}]*|".*"|'.*')*\})?\s*\-*\s*$/
15
+ # note these are not enough for parsing the above example:
16
+ #OpenDiv = /^[ ]{0,3}\+\-\-+\s*(.*)$/
17
+ #CloseDiv = /^[ ]{0,3}\=\-\-+\s*(.*)$/
18
+ StartPipe = /^[ ]{0,3}\|(.*)$/ # $1 is rest of line
19
+ DecorativeClosing = OpenDiv
20
+
21
+ MaRuKu::In::Markdown::register_block_extension(
22
+ :regexp => OpenDiv,
23
+ :handler => lambda { |doc, src, context|
24
+ # return false if not doc.is_math_enabled?
25
+ first = src.shift_line
26
+ first =~ OpenDiv
27
+ ial_at_beginning = $1
28
+ ial_at_end = nil
29
+
30
+ lines = []
31
+ # if second line starts with "|"
32
+ if src.cur_line =~ StartPipe
33
+ # then we read until no more "|"
34
+ while src.cur_line && (src.cur_line =~ StartPipe)
35
+ content = $1
36
+ lines.push content
37
+ src.shift_line
38
+ end
39
+ if src.cur_line =~ DecorativeClosing
40
+ ial_at_end = $1
41
+ src.shift_line
42
+ end
43
+ else
44
+ # else we read until CloseDiv
45
+ divs_open = 1
46
+ while src.cur_line && (divs_open>0)
47
+ if src.cur_line =~ CloseDiv
48
+ divs_open -= 1
49
+ if divs_open == 0
50
+ ial_at_end = $1
51
+ src.shift_line
52
+ break
53
+ else
54
+ lines.push src.shift_line
55
+ end
56
+ else
57
+ if src.cur_line =~ OpenDiv
58
+ divs_open += 1
59
+ end
60
+ lines.push src.shift_line
61
+ end
62
+ end
63
+
64
+ if divs_open > 0
65
+ e = "At end of input, I still have #{divs_open} DIVs open."
66
+ doc.maruku_error(e, src, context)
67
+ return true
68
+ end
69
+ end
70
+
71
+ ial_at_beginning = nil unless
72
+ (ial_at_beginning&&ial_at_beginning.size > 0)
73
+ ial_at_end = nil unless (ial_at_end && ial_at_end.size > 0)
74
+
75
+ if ial_at_beginning && ial_at_end
76
+ e = "Found two conflicting IALs: #{ial_at_beginning.inspect} and #{ial_at_end.inspect}"
77
+ doc.maruku_error(e, src, context)
78
+ end
79
+
80
+ al_string = ial_at_beginning || ial_at_end
81
+ al = nil
82
+
83
+ if al_string =~ /^\{(.*)\}\s*$/
84
+ inside = $1
85
+ cs = MaRuKu::In::Markdown::SpanLevelParser::CharSource
86
+ al = al_string &&
87
+ doc.read_attribute_list(cs.new(inside), its_context=nil, break_on=[nil])
88
+ end
89
+
90
+ src = MaRuKu::In::Markdown::BlockLevelParser::LineSource.new(lines)
91
+ children = doc.parse_blocks(src)
92
+
93
+ context.push doc.md_div(children, al)
94
+ true
95
+ })
96
+
97
+
98
+ module MaRuKu; class MDElement
99
+
100
+ def md_div(children, al=nil)
101
+ type = label = num = nil
102
+ doc.refid2ref ||= {}
103
+ if al
104
+ al.each do |k, v|
105
+ case k
106
+ when :class
107
+ type = $1 if v =~ /^num_(\w*)/
108
+ when :id
109
+ label = v
110
+ end
111
+ end
112
+ end
113
+ if type
114
+ doc.refid2ref[type] ||= {}
115
+ num = doc.refid2ref[type].length + 1 || 1
116
+ end
117
+ e = self.md_el(:div, children, meta={:label => label, :type => type, :num => num}, al)
118
+ if type && label
119
+ doc.refid2ref[type].update({label => e})
120
+ end
121
+ e
122
+ end
123
+
124
+ end end
125
+
126
+
127
+ module MaRuKu; module Out; module HTML
128
+
129
+ def to_html_div
130
+ add_ws wrap_as_element('div')
131
+ end
132
+
133
+ end end end
@@ -0,0 +1,41 @@
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'
12
+
13
+
14
+ =begin maruku_doc
15
+ Attribute: math_enabled
16
+ Scope: global, document
17
+ Summary: Enables parsing of LaTeX math
18
+
19
+ To explicitly disable the math parsing:
20
+
21
+ Maruku.new(string, {:math_enabled => false})
22
+ {:ruby}
23
+
24
+ =end
25
+
26
+ MaRuKu::Globals[:math_enabled] = true
27
+
28
+
29
+ =begin maruku_doc
30
+ Attribute: math_numbered
31
+ Scope: global, document
32
+ Summary: Math openings which should be numerated
33
+
34
+ Array containing any of `'\\['`, `'\\begin{equation}'`, `'$$'`.
35
+
36
+ MaRuKu::Globals[:math_numbered] = ['\\[']
37
+
38
+ =end
39
+
40
+
41
+ MaRuKu::Globals[:math_numbered] = []
@@ -0,0 +1,27 @@
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, numerate)
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 || numerate) && @doc #take number
16
+ @doc.eqid2eq ||= {}
17
+ num = @doc.eqid2eq.size + 1
18
+ label = "eq#{num}" if not label # FIXME do id for document
19
+ end
20
+ e = self.md_el(:equation, [], meta={:math=>math, :label=>label,:num=>num})
21
+ if label && @doc #take number
22
+ @doc.eqid2eq[label] = e
23
+ end
24
+ e
25
+ end
26
+
27
+ end end
@@ -0,0 +1,12 @@
1
+ class String
2
+ # fix some LaTeX command-name clashes
3
+ def fix_latex
4
+ if #{html_math_engine} == 'itex2mml'
5
+ s = self.gsub("\\mathop{", "\\operatorname{")
6
+ s.gsub!(/\\begin\{svg\}.*?\\end\{svg\}/m, " ")
7
+ s.gsub("\\space{", "\\itexspace{")
8
+ else
9
+ self
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,107 @@
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 get_setting(: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(get_setting(: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 += "--displaymath " if kind == :equation
29
+ options += ("--temp-directory '%s' " % get_setting(:html_png_dir))
30
+ options += ("--png-directory '%s'" % get_setting(:html_png_dir))
31
+
32
+ cmd = "blahtex #{options} < #{tmp_in.path} > #{result_file}"
33
+ #$stderr.puts "$ #{cmd}"
34
+ system cmd
35
+ tmp_in.delete
36
+ end
37
+
38
+ result = File.read(result_file)
39
+ if result.nil? || result.empty?
40
+ raise "Blahtex error: empty output"
41
+ end
42
+
43
+ doc = Document.new(result, {:respect_whitespace =>:all})
44
+ png = doc.root.elements[1]
45
+ if png.name != 'png'
46
+ raise "Blahtex error: \n#{doc}"
47
+ end
48
+ depth = png.elements['depth'] || (raise "No depth element in:\n #{doc}")
49
+ height = png.elements['height'] || (raise "No height element in:\n #{doc}")
50
+ md5 = png.elements['md5'] || (raise "No md5 element in:\n #{doc}")
51
+
52
+ depth = depth.text.to_f
53
+ height = height.text.to_f # XXX check != 0
54
+ md5 = md5.text
55
+
56
+ dir_url = get_setting(:html_png_url)
57
+ return PNG.new("#{dir_url}#{md5}.png", depth, height)
58
+ rescue Exception => e
59
+ maruku_error "Error: #{e}"
60
+ end
61
+ nil
62
+ end
63
+
64
+
65
+ def convert_to_mathml_blahtex(kind, tex)
66
+ @@BlahtexCache = PStore.new(get_setting(:latex_cache_file))
67
+
68
+ begin
69
+ @@BlahtexCache.transaction do
70
+ if @@BlahtexCache[tex].nil?
71
+ tmp_in = Tempfile.new('maruku_blahtex')
72
+ f = tmp_in.open
73
+ f.write tex
74
+ f.close
75
+ tmp_out = Tempfile.new('maruku_blahtex')
76
+
77
+ options = "--mathml"
78
+ cmd = "blahtex #{options} < #{tmp_in.path} > #{tmp_out.path}"
79
+ #$stderr.puts "$ #{cmd}"
80
+ system cmd
81
+ tmp_in.delete
82
+
83
+ result = nil
84
+ File.open(tmp_out.path) do |f| result=f.read end
85
+ puts result
86
+
87
+ @@BlahtexCache[tex] = result
88
+ end
89
+
90
+ blahtex = @@BlahtexCache[tex]
91
+ doc = Document.new(blahtex, {:respect_whitespace =>:all})
92
+ mathml = doc.root.elements['mathml']
93
+ if not mathml
94
+ maruku_error "Blahtex error: \n#{doc}"
95
+ return nil
96
+ else
97
+ return mathml
98
+ end
99
+ end
100
+
101
+ rescue Exception => e
102
+ maruku_error "Error: #{e}"
103
+ end
104
+ nil
105
+ end
106
+
107
+ 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"+ "Please install it." unless $already_warned_itex2mml
18
+ $already_warned_itex2mml = true
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,119 @@
1
+ module MaRuKu
2
+
3
+ class MDDocument
4
+ # Hash equation id (String) to equation element (MDElement)
5
+ safe_attr_accessor :eqid2eq, Hash
6
+
7
+ def is_math_enabled?
8
+ get_setting :math_enabled
9
+ end
10
+ end
11
+ end
12
+
13
+
14
+ # Everything goes; takes care of escaping the "\$" inside the expression
15
+ RegInlineMath = /\${1}((?:[^\$]|\\\$)+)\$/
16
+
17
+ MaRuKu::In::Markdown::register_span_extension(
18
+ :chars => ?$,
19
+ :regexp => RegInlineMath,
20
+ :handler => lambda { |doc, src, con|
21
+ return false if not doc.is_math_enabled?
22
+
23
+ if m = src.read_regexp(RegInlineMath)
24
+ math = m.captures.compact.first
25
+ con.push doc.md_inline_math(math)
26
+ true
27
+ else
28
+ #puts "not math: #{src.cur_chars 10}"
29
+ false
30
+ end
31
+ }
32
+ )
33
+
34
+
35
+ MathOpen1 = Regexp.escape('\\begin{equation}')
36
+ MathClose1 = Regexp.escape('\\end{equation}')
37
+ MathOpen2 = Regexp.escape('\\[')
38
+ MathClose2 = Regexp.escape('\\]')
39
+ MathOpen3 = Regexp.escape('$$')
40
+ MathClose3 = Regexp.escape('$$')
41
+
42
+ EqLabel = /(?:\((\w+)\))/
43
+ EquationOpen = /#{MathOpen1}|#{MathOpen2}|#{MathOpen3}/
44
+ EquationClose = /#{MathClose1}|#{MathClose2}|#{MathClose3}/
45
+
46
+ # $1 is opening, $2 is tex
47
+ EquationStart = /^[ ]{0,3}(#{EquationOpen})(.*)$/
48
+ # $1 is tex, $2 is closing, $3 is tex
49
+ EquationEnd = /^(.*)(#{EquationClose})\s*#{EqLabel}?\s*$/
50
+ # $1 is opening, $2 is tex, $3 is closing, $4 is label
51
+ OneLineEquation = /^[ ]{0,3}(#{EquationOpen})(.*)(#{EquationClose})\s*#{EqLabel}?\s*$/
52
+
53
+ MaRuKu::In::Markdown::register_block_extension(
54
+ :regexp => EquationStart,
55
+ :handler => lambda { |doc, src, con|
56
+ return false if not doc.is_math_enabled?
57
+ first = src.shift_line
58
+ if first =~ OneLineEquation
59
+ opening, tex, closing, label = $1, $2, $3, $4
60
+ numerate = doc.get_setting(:math_numbered).include?(opening)
61
+ con.push doc.md_equation(tex, label, numerate)
62
+ else
63
+ first =~ EquationStart
64
+ opening, tex = $1, $2
65
+
66
+ numerate = doc.get_setting(:math_numbered).include?(opening)
67
+ label = nil
68
+ while true
69
+ if not src.cur_line
70
+ doc.maruku_error("Stream finished while reading equation\n\n"+
71
+ doc.add_tabs(tex,1,'$> '), src, con)
72
+ break
73
+ end
74
+ line = src.shift_line
75
+ if line =~ EquationEnd
76
+ tex_line, closing = $1, $2
77
+ label = $3 if $3
78
+ tex += tex_line + "\n"
79
+ break
80
+ else
81
+ tex += line + "\n"
82
+ end
83
+ end
84
+ con.push doc.md_equation(tex, label, numerate)
85
+ end
86
+ true
87
+ })
88
+
89
+
90
+ # This adds support for \eqref
91
+ RegEqrefLatex = /\\eqref\{(\w+)\}/
92
+ RegEqPar = /\(eq:(\w+)\)/
93
+ RegEqref = Regexp::union(RegEqrefLatex, RegEqPar)
94
+
95
+ MaRuKu::In::Markdown::register_span_extension(
96
+ :chars => [?\\, ?(],
97
+ :regexp => RegEqref,
98
+ :handler => lambda { |doc, src, con|
99
+ return false if not doc.is_math_enabled?
100
+ eqid = src.read_regexp(RegEqref).captures.compact.first
101
+ r = doc.md_el(:eqref, [], meta={:eqid=>eqid})
102
+ con.push r
103
+ true
104
+ }
105
+ )
106
+
107
+ # This adds support for \ref
108
+ RegRef = /\\ref\{(\w*)\}/
109
+ MaRuKu::In::Markdown::register_span_extension(
110
+ :chars => [?\\, ?(],
111
+ :regexp => RegRef,
112
+ :handler => lambda { |doc, src, con|
113
+ return false if not doc.is_math_enabled?
114
+ refid = src.read_regexp(RegRef).captures.compact.first
115
+ r = doc.md_el(:divref, [], meta={:refid=>refid})
116
+ con.push r
117
+ true
118
+ }
119
+ )