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 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