polytexnic 0.5.0 → 0.6.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.
- checksums.yaml +4 -4
- data/lib/polytexnic/literal.rb +22 -12
- data/lib/polytexnic/preprocessors/polytex.rb +78 -21
- data/lib/polytexnic/version.rb +1 -1
- data/spec/markdown_to_polytex_spec.rb +72 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8e7de21594c8b7389b2644e15ea5cf098edff39
|
4
|
+
data.tar.gz: 49867ac88a23d41ddf48903ada6f0269dd84d940
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c58db6f0f1661a51c11c216c624960f4d9f405eaf2b201f88e810c9276c94e30539b322100c71cd9c36163480f43229d271fcb2520ffdd715889451db977ef7
|
7
|
+
data.tar.gz: 015ba8b5a3034d4b2765b509d2fa9a58f1fc8f5f4a897c0a2724b7048e4f912deec4cd18c0d4635a5c5b98ab95c356be1c79ded81802f839fb804ad7650b7d47
|
data/lib/polytexnic/literal.rb
CHANGED
@@ -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
|
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
|
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,
|
84
|
-
#
|
85
|
-
def cache_math(text)
|
86
|
-
|
87
|
-
|
88
|
-
key =
|
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!(
|
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
|
data/lib/polytexnic/version.rb
CHANGED
@@ -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.
|
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-
|
12
|
+
date: 2013-11-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|