polytexnic 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c16ad8d5728f4ac2d87b81744b76c4a854e26d88
4
- data.tar.gz: 5859a31e6722957809d2fd080c5170a05be7b5e1
3
+ metadata.gz: d8e7de21594c8b7389b2644e15ea5cf098edff39
4
+ data.tar.gz: 49867ac88a23d41ddf48903ada6f0269dd84d940
5
5
  SHA512:
6
- metadata.gz: 12e8c475ee247533ce1dcf0b1db8ad7cf3806a2cf81cf5726b935fbc0d23ac60ccc1998e7e38c5a234911be9ff370abdac44f6782caf5b5f1f28a3608240f3b2
7
- data.tar.gz: 54b074f7a0df5e183cf333a52ceb5d4fa1b7addc3085c5b082da3c15f693a7afe03fba5295a8b140b85d48dfece737a8e74d258a021420935d497301007e584c
6
+ metadata.gz: 0c58db6f0f1661a51c11c216c624960f4d9f405eaf2b201f88e810c9276c94e30539b322100c71cd9c36163480f43229d271fcb2520ffdd715889451db977ef7
7
+ data.tar.gz: 015ba8b5a3034d4b2765b509d2fa9a58f1fc8f5f4a897c0a2724b7048e4f912deec4cd18c0d4635a5c5b98ab95c356be1c79ded81802f839fb804ad7650b7d47
@@ -1,5 +1,6 @@
1
1
  module Polytexnic
2
2
  module Literal
3
+ extend self
3
4
 
4
5
  # Matches the line for syntax highlighting.
5
6
  # %= lang:<language>
@@ -21,6 +22,22 @@ module Polytexnic
21
22
  output.join("\n")
22
23
  end
23
24
 
25
+ # Returns supported math environments.
26
+ # Note that the custom AMS-TeX environments are supported
27
+ # in addition to the LaTeX defaults.
28
+ def math_environments
29
+ %w[align align*
30
+ eqnarray eqnarray* equation equation*
31
+ gather gather* gathered
32
+ multline multline*
33
+ ]
34
+ end
35
+
36
+ # Returns a list of all literal types.
37
+ def literal_types
38
+ %w[verbatim Vertatim code metadcode] + math_environments
39
+ end
40
+
24
41
  # Handles environments that should be passed through the pipeline intact.
25
42
  # The includes verbatim environments ('verbatim', 'Verbatim') and all the
26
43
  # equation environments handled by MathJax ('equation', 'align', etc.).
@@ -40,7 +57,7 @@ module Polytexnic
40
57
  # and even then I've failed to get it to work. Thus, it shall for now
41
58
  # follow the "ball of mud" pattern. (The only saving grace is that it's
42
59
  # very thoroughly tested.)
43
- def cache_literal_environments(lines, output, format)
60
+ def cache_literal_environments(lines, output, format, cache = nil)
44
61
  latex = (format == :latex)
45
62
  language = nil
46
63
  in_verbatim = false
@@ -241,18 +258,9 @@ module Polytexnic
241
258
  end
242
259
  end
243
260
 
244
- # Returns supported math environments.
245
- # Note that the custom AMS-TeX environments are supported
246
- # in addition to the LaTeX defaults.
247
- def math_environments
248
- %w[align align*
249
- eqnarray eqnarray* equation equation*
250
- gather gather* gathered
251
- multline multline*
252
- ]
253
- end
254
261
 
255
262
  class String
263
+ include Polytexnic::Literal
256
264
 
257
265
  # Returns true if self matches \begin{...} where ... is a literal environment.
258
266
  # Note: Support for the 'metacode' environment exists solely to allow
@@ -294,6 +302,8 @@ class String
294
302
 
295
303
  # Returns a regex matching valid math environments.
296
304
  def math_environment_regex
297
- math_environments.map { |s| Regexp.escape(s) }.join('|')
305
+ Polytexnic::Literal.math_environments.map do |s|
306
+ Regexp.escape(s)
307
+ end.join('|')
298
308
  end
299
309
  end
@@ -2,6 +2,7 @@
2
2
  module Polytexnic
3
3
  module Preprocessor
4
4
  module Polytex
5
+ include Polytexnic::Literal
5
6
 
6
7
  # Converts Markdown to PolyTeX.
7
8
  # We adopt a unified approach: rather than convert "Markdown" (I use
@@ -23,17 +24,83 @@ module Polytexnic
23
24
  # marketing term.</rant>
24
25
  def to_polytex
25
26
  require 'Kramdown'
27
+ cache = {}
28
+ math_cache = {}
26
29
  cleaned_markdown = cache_code_environments
27
30
  cleaned_markdown.tap do |markdown|
28
31
  convert_code_inclusion(markdown)
32
+ cache_latex_literal(markdown, cache)
33
+ cache_raw_latex(markdown, cache)
34
+ cache_math(markdown, math_cache)
29
35
  end
30
- math_cache = cache_math(cleaned_markdown)
31
36
  # Override the header ordering, which starts with 'section' by default.
32
37
  lh = 'chapter,section,subsection,subsubsection,paragraph,subparagraph'
33
38
  kramdown = Kramdown::Document.new(cleaned_markdown, latex_headers: lh)
34
39
  @source = restore_inclusion(restore_math(kramdown.to_latex, math_cache))
40
+ restore_raw_latex(@source, cache)
41
+ end
42
+
43
+ # Adds support for <<(path/to/code) inclusion.
44
+ # Yes, this is a bit of a hack, but it works.
45
+ def convert_code_inclusion(text)
46
+ text.gsub!(/^\s*<<(\(.*?\))/) { "<!-- inclusion= <<#{$1}-->" }
47
+ end
48
+ def restore_inclusion(text)
49
+ text.gsub(/% <!-- inclusion= (.*?)-->/) { "%= #{$1}" }
50
+ end
51
+
52
+ # Caches literal LaTeX environments.
53
+ def cache_latex_literal(markdown, cache)
54
+ Polytexnic::Literal.literal_types.each do |literal|
55
+ regex = /(\\begin\{#{Regexp.escape(literal)}\}
56
+ .*?
57
+ \\end\{#{Regexp.escape(literal)}\})
58
+ /xm
59
+ markdown.gsub!(regex) do
60
+ key = digest($1)
61
+ cache[key] = $1
62
+ key
63
+ end
64
+ end
65
+ end
66
+
67
+ # Caches raw LaTeX commands to be passed through the pipeline.
68
+ def cache_raw_latex(markdown, cache)
69
+ command_regex = /(
70
+ ~\\ref\{.*?\} # reference with a tie
71
+ |
72
+ ~\\eqref\{.*?\} # eq reference with a tie
73
+ |
74
+ \\\w+\{.*?\} # command with one arg
75
+ |
76
+ \\\w+ # normal command
77
+ |
78
+ \\[ %&$#@] # space or special character
79
+ )
80
+ /x
81
+ markdown.gsub!(command_regex) do
82
+ key = digest($1)
83
+ cache[key] = $1
84
+ key
85
+ end
86
+ end
87
+
88
+ # Restores raw LaTeX from the cache
89
+ def restore_raw_latex(text, cache)
90
+ cache.each do |key, value|
91
+ if value == '\&'
92
+ # Bizarrely, the default code doesn't work for '\&'.
93
+ # I actually suspect it may be a bug in Ruby. This hacks around it.
94
+ text.gsub!(key, value.sub(/\\/, '\\\\\\'))
95
+ else
96
+ text.gsub!(key, value)
97
+ end
98
+ end
35
99
  end
36
100
 
101
+ # Caches Markdown code environments.
102
+ # Included are indented environments, Leanpub-style indented environments,
103
+ # and GitHub-style code fencing.
37
104
  def cache_code_environments
38
105
  output = []
39
106
  lines = @source.split("\n")
@@ -72,7 +139,7 @@ module Polytexnic
72
139
  output.join("\n")
73
140
  end
74
141
 
75
- # Caches Leanpub-style math.
142
+ # Caches math.
76
143
  # Leanpub uses the notation {$$}...{/$$} for both inline and block math,
77
144
  # with the only difference being the presences of newlines:
78
145
  # {$$} x^2 {/$$} % inline
@@ -80,21 +147,19 @@ module Polytexnic
80
147
  # {$$}
81
148
  # x^2 % block
82
149
  # {/$$}
83
- # I personally hate this notation and convention, but anyone who really
84
- # cares should just use PolyTeX instead of Markdown.
85
- def cache_math(text)
86
- cache = {}
87
- text.gsub!(/\{\$\$\}\n(.*?)\n\{\/\$\$\}/) do
88
- key = digest($1)
89
- cache[[:block, key]] = $1
150
+ # I personally hate this notation and convention, so we also support
151
+ # LaTeX-style \( x \) and \[ x^2 - 2 = 0 \] notation.
152
+ def cache_math(text, cache)
153
+ text.gsub!(/(?:\{\$\$\}\n(.*?)\n\{\/\$\$\}|\\\[(.*?)\\\])/) do
154
+ key = digest($1 || $2)
155
+ cache[[:block, key]] = $1 || $2
90
156
  key
91
157
  end
92
- text.gsub!(/\{\$\$\}(.*?)\{\/\$\$\}/) do
93
- key = digest($1)
94
- cache[[:inline, key]] = $1
158
+ text.gsub!(/(?:\{\$\$\}(.*?)\{\/\$\$\}|\\\((.*?)\\\))/) do
159
+ key = digest($1 || $2)
160
+ cache[[:inline, key]] = $1 || $2
95
161
  key
96
162
  end
97
- cache
98
163
  end
99
164
 
100
165
  # Restores the Markdown math.
@@ -115,13 +180,5 @@ module Polytexnic
115
180
  text
116
181
  end
117
182
  end
118
-
119
- # Adds support for <<(path/to/code) inclusion.
120
- def convert_code_inclusion(text)
121
- text.gsub!(/^\s*<<(\(.*?\))/) { "<!-- inclusion= <<#{$1}-->" }
122
- end
123
- def restore_inclusion(text)
124
- text.gsub(/% <!-- inclusion= (.*?)-->/) { "%= #{$1}" }
125
- end
126
183
  end
127
184
  end
@@ -1,3 +1,3 @@
1
1
  module Polytexnic
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -87,6 +87,78 @@ That is it. You can keep writing your text after the footnote content.
87
87
  end
88
88
  end
89
89
 
90
+ context "with LaTeX containing" do
91
+
92
+ context "a normal command" do
93
+ let(:source) { 'This is a command: \foobar' }
94
+ it { should include source }
95
+ end
96
+
97
+ context "backslash space" do
98
+ let(:source) { 'Dr.\ No' }
99
+ it { should include source }
100
+ end
101
+
102
+ context "escaped special characters" do
103
+ let(:source) { '\% \& \$ \# \@ \_' }
104
+ it { should include source }
105
+ end
106
+
107
+ context "a label and cross-reference" do
108
+ let(:source) do <<-'EOS'
109
+ # Chapter One
110
+ \label{cha:one}
111
+
112
+ Chapter~\ref{cha:one}
113
+ EOS
114
+ end
115
+ it { should include '\label{cha:one}' }
116
+ it { should include 'Chapter~\ref{cha:one}' }
117
+ end
118
+
119
+ context "an inline equation" do
120
+ let(:source) { '\( x \) is a variable' }
121
+ it { should include source }
122
+ end
123
+
124
+ context "a centered equation" do
125
+ let(:source) { '\[ x^2 - 2 = 0 \] is an equation' }
126
+ it { should resemble source }
127
+ end
128
+
129
+ context "an equation environment" do
130
+ let(:source) do <<-'EOS'
131
+ foo
132
+
133
+ \begin{equation}
134
+ \label{eq:phi}
135
+ \phi = \frac{1+\sqrt{5}}{2}
136
+ \end{equation}
137
+
138
+ bar
139
+ EOS
140
+ end
141
+ it { should resemble source }
142
+ end
143
+
144
+ context "a codelisting environment" do
145
+ let(:source) do <<-'EOS'
146
+ \begin{codelisting}
147
+ \codecaption{Lorem ipsum.}
148
+ \label{code:lorem}
149
+ ```ruby
150
+ def foo; "bar"; end
151
+ ```
152
+ \end{codelisting}
153
+ EOS
154
+ end
155
+ it { should resemble '\begin{codelisting}' }
156
+ it { should resemble '\codecaption{Lorem ipsum.}' }
157
+ it { should resemble '\label{code:lorem}' }
158
+ it { should resemble '\end{codelisting}' }
159
+ end
160
+ end
161
+
90
162
  describe "source code" do
91
163
  context "without highlighting" do
92
164
  let(:source) do <<-EOS
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polytexnic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Hartl
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-13 00:00:00.000000000 Z
12
+ date: 2013-11-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri