polytexnic 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +37 -0
  3. data/.pull_requests/1371777257 +0 -0
  4. data/.pull_requests/1371927975 +0 -0
  5. data/.pull_requests/1372804345 +0 -0
  6. data/.pull_requests/1374784075 +0 -0
  7. data/.pull_requests/1375304853 +0 -0
  8. data/.pull_requests/1375408308 +0 -0
  9. data/.pull_requests/1375409462 +0 -0
  10. data/.pull_requests/1375410668 +0 -0
  11. data/.pull_requests/1375472132 +0 -0
  12. data/.pull_requests/1375485496 +0 -0
  13. data/.pull_requests/1375487548 +0 -0
  14. data/.pull_requests/1375492835 +0 -0
  15. data/.pull_requests/1375497765 +0 -0
  16. data/.pull_requests/1375559547 +0 -0
  17. data/.pull_requests/1375589063 +0 -0
  18. data/.pull_requests/1375841786 +0 -0
  19. data/.pull_requests/1376352634 +0 -0
  20. data/.pull_requests/1376353299 +0 -0
  21. data/.pull_requests/1376449284 +0 -0
  22. data/.pull_requests/1376452696 +0 -0
  23. data/.pull_requests/1376454166 +0 -0
  24. data/.pull_requests/1376532291 +0 -0
  25. data/.pull_requests/1376625487 +0 -0
  26. data/.pull_requests/1376690108 +0 -0
  27. data/.pull_requests/1376699046 +0 -0
  28. data/.pull_requests/1376707642 +0 -0
  29. data/.pull_requests/1377230284 +0 -0
  30. data/.pull_requests/1379118478 +0 -0
  31. data/.pull_requests/1379123150 +0 -0
  32. data/.pull_requests/1380221847 +0 -0
  33. data/.pull_requests/1380589654 +0 -0
  34. data/.pull_requests/1380673142 +0 -0
  35. data/.pull_requests/1380850800 +0 -0
  36. data/.pull_requests/1381001264 +0 -0
  37. data/.pull_requests/1381005204 +0 -0
  38. data/.pull_requests/1381103022 +0 -0
  39. data/.pull_requests/1381252832 +0 -0
  40. data/.pull_requests/1381276624 +0 -0
  41. data/.pull_requests/1381344234 +0 -0
  42. data/.pull_requests/1381385297 +0 -0
  43. data/.pull_requests/1381427498 +0 -0
  44. data/.pull_requests/1381429761 +0 -0
  45. data/.pull_requests/1381873684 +0 -0
  46. data/.pull_requests/1382045490 +0 -0
  47. data/.pull_requests/1382056384 +0 -0
  48. data/.pull_requests/1382405223 +0 -0
  49. data/.pull_requests/1382478400 +0 -0
  50. data/.pull_requests/1382479780 +0 -0
  51. data/.pull_requests/1382485483 +0 -0
  52. data/.pull_requests/1382569911 +0 -0
  53. data/.pull_requests/1382646199 +0 -0
  54. data/.pull_requests/1382649778 +0 -0
  55. data/.pull_requests/1382660987 +0 -0
  56. data/.pull_requests/1382743927 +0 -0
  57. data/.pull_requests/1382840347 +0 -0
  58. data/.pull_requests/1383077676 +0 -0
  59. data/.pull_requests/1383086948 +0 -0
  60. data/.pull_requests/1383161978 +0 -0
  61. data/.pull_requests/1383263695 +0 -0
  62. data/.pull_requests/1383274008 +0 -0
  63. data/.pull_requests/1383327328 +0 -0
  64. data/.rspec +2 -0
  65. data/.ruby-gemset +1 -0
  66. data/.ruby-version +1 -0
  67. data/Gemfile +15 -0
  68. data/Guardfile +15 -0
  69. data/LICENSE.txt +22 -0
  70. data/README.md +21 -0
  71. data/Rakefile +2 -0
  72. data/lib/polytexnic/literal.rb +299 -0
  73. data/lib/polytexnic/postprocessor.rb +28 -0
  74. data/lib/polytexnic/postprocessors/html.rb +1139 -0
  75. data/lib/polytexnic/postprocessors/latex.rb +18 -0
  76. data/lib/polytexnic/postprocessors/polytex.rb +44 -0
  77. data/lib/polytexnic/preprocessor.rb +23 -0
  78. data/lib/polytexnic/preprocessors/html.rb +349 -0
  79. data/lib/polytexnic/preprocessors/latex.rb +43 -0
  80. data/lib/polytexnic/preprocessors/polytex.rb +127 -0
  81. data/lib/polytexnic/utils.rb +176 -0
  82. data/lib/polytexnic/version.rb +3 -0
  83. data/lib/polytexnic.rb +92 -0
  84. data/notes/pandoc.md +41 -0
  85. data/polytexnic.gemspec +28 -0
  86. data/polytexnic_commands.sty +5 -0
  87. data/precompiled_binaries/tralics +0 -0
  88. data/spec/fixtures/code_listing.tex +14 -0
  89. data/spec/fixtures/figures.tex +8 -0
  90. data/spec/fixtures/inline_math.html +4 -0
  91. data/spec/fixtures/inline_math.tex +3 -0
  92. data/spec/fixtures/math_environments.html +50 -0
  93. data/spec/fixtures/math_environments.tex +56 -0
  94. data/spec/fixtures/section_xrefs.tex +9 -0
  95. data/spec/fixtures/sidebar.tex +10 -0
  96. data/spec/fixtures/tables.tex +8 -0
  97. data/spec/fixtures/verbatim_environments.html +11 -0
  98. data/spec/fixtures/verbatim_environments.tex +13 -0
  99. data/spec/integration_spec.rb +34 -0
  100. data/spec/markdown_to_polytex_spec.rb +192 -0
  101. data/spec/resemble_matcher_spec.rb +69 -0
  102. data/spec/spec_helper.rb +38 -0
  103. data/spec/support/resemble_matcher.rb +100 -0
  104. data/spec/to_html/asides_spec.rb +42 -0
  105. data/spec/to_html/chapters_and_sections_spec.rb +268 -0
  106. data/spec/to_html/characters_and_punctuation_spec.rb +138 -0
  107. data/spec/to_html/codelistings_spec.rb +70 -0
  108. data/spec/to_html/core_spec.rb +227 -0
  109. data/spec/to_html/eqref_spec.rb +32 -0
  110. data/spec/to_html/footnote_spec.rb +164 -0
  111. data/spec/to_html/graphics_and_figures_spec.rb +358 -0
  112. data/spec/to_html/lists_spec.rb +103 -0
  113. data/spec/to_html/literal_environments/code_spec.rb +141 -0
  114. data/spec/to_html/literal_environments/math_spec.rb +255 -0
  115. data/spec/to_html/literal_environments/unicode_spec.rb +12 -0
  116. data/spec/to_html/literal_environments/verbatim_spec.rb +168 -0
  117. data/spec/to_html/quotations_and_verse_spec.rb +86 -0
  118. data/spec/to_html/table_of_contents_spec.rb +93 -0
  119. data/spec/to_html/table_spec.rb +269 -0
  120. data/spec/to_html/text_formatting_spec.rb +50 -0
  121. data/spec/to_latex_spec.rb +197 -0
  122. data/tasks/bin/ruby_tests +41 -0
  123. data/tasks/run_tests_with_both_rubies.rake +5 -0
  124. data/tmp/.gitkeep +0 -0
  125. metadata +286 -0
@@ -0,0 +1,192 @@
1
+ # encoding=utf-8
2
+ require 'spec_helper'
3
+
4
+ describe Polytexnic::Pipeline do
5
+
6
+ before(:all) do
7
+ FileUtils.rm('.highlight_cache') if File.exist?('.highlight_cache')
8
+ end
9
+
10
+ describe '#to_polytex' do
11
+ subject(:processed_text) do
12
+ Polytexnic::Pipeline.new(source, source: :markdown).polytex
13
+ end
14
+
15
+ context "for vanilla Markdown" do
16
+ let(:source) { '*foo* **bar**' }
17
+ it { should include '\emph{foo} \textbf{bar}' }
18
+ it { should_not include '\begin{document}' }
19
+ end
20
+
21
+ context "for multiline Markdown" do
22
+ let(:source) do <<-EOS
23
+ # A chapter
24
+
25
+ Hello, *world*!
26
+
27
+ ## A section
28
+
29
+ Lorem ipsum
30
+ EOS
31
+ end
32
+ it { should include '\chapter{A chapter}' }
33
+ it { should include '\section{A section}' }
34
+ it { should_not include '\hypertarget' }
35
+ end
36
+
37
+ describe "with math" do
38
+ subject do
39
+ Polytexnic::Pipeline.new(markdown, source: :markdown).polytex
40
+ end
41
+
42
+ context "inline math" do
43
+ let(:markdown) do <<-'EOS'
44
+ This is inline math: {$$} x^2 {/$$}.
45
+ EOS
46
+ end
47
+
48
+ it { should include '\( x^2 \)' }
49
+ end
50
+
51
+ context "block math" do
52
+ let(:markdown) do <<-'EOS'
53
+ This is block math:
54
+ {$$}
55
+ x^2
56
+ {/$$}.
57
+ EOS
58
+ end
59
+
60
+ it { should resemble '\[ x^2 \]' }
61
+ end
62
+ end
63
+
64
+ describe "footnotes" do
65
+ subject do
66
+ Polytexnic::Pipeline.new(markdown, source: :markdown).polytex
67
+ end
68
+
69
+ context "first chapter with footnotes" do
70
+ let(:markdown) do <<-'EOS'
71
+ To add a footnote, you insert a footnote tag like this.[^foo]
72
+
73
+ Then you add the footnote content later in the text, using the same tag,
74
+ with a colon and a space:[^foo2]
75
+
76
+ [^foo]: This is the footnote content.
77
+
78
+ That is it. You can keep writing your text after the footnote content.
79
+
80
+ [^foo2]: This is the footnote text. We are now going to add a second line
81
+ after typing in four spaces.
82
+ EOS
83
+ end
84
+
85
+ it { should include '\footnote{This is the footnote content.}' }
86
+ it { should include 'after typing in four spaces.}' }
87
+ end
88
+ end
89
+
90
+ describe "source code" do
91
+ context "without highlighting" do
92
+ let(:source) do <<-EOS
93
+ def foo
94
+ "bar"
95
+ end
96
+ EOS
97
+ end
98
+ let(:output) do <<-'EOS'
99
+ \begin{verbatim}
100
+ def foo
101
+ "bar"
102
+ end
103
+ \end{verbatim}
104
+ EOS
105
+ end
106
+ it { should eq output }
107
+ end
108
+
109
+ context "with highlighting" do
110
+ let(:source) do <<-EOS
111
+ {lang="ruby"}
112
+ def foo
113
+ "bar"
114
+ end
115
+ lorem
116
+ EOS
117
+ end
118
+ let(:output) do <<-'EOS'
119
+ %= lang:ruby
120
+ \begin{code}
121
+ def foo
122
+ "bar"
123
+ end
124
+ \end{code}
125
+ lorem
126
+ EOS
127
+ end
128
+ it { should resemble output }
129
+ end
130
+
131
+ describe "code inclusion" do
132
+ let(:source) { '<<(/path/to/code)' }
133
+ it { should resemble '%= <<(/path/to/code)' }
134
+
135
+ context "with an alternate lang" do
136
+ let(:source) { '<<(/path/to/code.md, lang: text)' }
137
+ it { should resemble '%= <<(/path/to/code.md, lang: text)' }
138
+ end
139
+ end
140
+
141
+ describe "GitHub-flavored code fencing" do
142
+
143
+ context "without highlighting" do
144
+ let(:source) do <<-EOS
145
+ ```
146
+ def foo
147
+ "bar"
148
+ end
149
+ ```
150
+ lorem
151
+ EOS
152
+ end
153
+
154
+ let(:output) do <<-'EOS'
155
+ \begin{verbatim}
156
+ def foo
157
+ "bar"
158
+ end
159
+ \end{verbatim}
160
+ lorem
161
+ EOS
162
+ end
163
+ it { should resemble output }
164
+ end
165
+
166
+ context "with highlighting" do
167
+ let(:source) do <<-EOS
168
+ ```ruby
169
+ def foo
170
+ "bar"
171
+ end
172
+ ```
173
+ lorem
174
+ EOS
175
+ end
176
+
177
+ let(:output) do <<-'EOS'
178
+ %= lang:ruby
179
+ \begin{code}
180
+ def foo
181
+ "bar"
182
+ end
183
+ \end{code}
184
+ lorem
185
+ EOS
186
+ end
187
+ it { should resemble output }
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,69 @@
1
+ # encoding=utf-8
2
+ require 'spec_helper'
3
+
4
+ describe String do
5
+ let(:string) { "foo\t bar\n\nbaz quux\nderp" }
6
+ let(:compressed_string) { "foo bar baz quux derp" }
7
+ subject { string }
8
+
9
+ it { should respond_to(:compress) }
10
+
11
+ describe '#compress' do
12
+ subject { string.compress }
13
+ it { should eq compressed_string }
14
+ end
15
+ end
16
+
17
+ describe "custom 'resemble' matcher" do
18
+
19
+ it "should pass if two strings agree up to whitespace" do
20
+ expect("foo bar").to resemble " foo \t\tbar "
21
+ end
22
+
23
+ it "should work for regexes" do
24
+ expect("foo 628_tau bar").to resemble /foo \d+\w* bar/
25
+ end
26
+
27
+ it "should work if the actual string contains the right substring" do
28
+ expect("baz quux foo bar derp").to resemble " foo \t\tbar "
29
+ end
30
+
31
+ it "should work with backslashes" do
32
+ expect('\emph{foo bar}').to resemble '\emph{foo bar}'
33
+ end
34
+
35
+ let(:nbsp) { ' ' }
36
+
37
+ it "should work with Unicode nonbreak spaces" do
38
+ expect('foo' + nbsp + nbsp + 'bar').to resemble 'foo bar'
39
+ end
40
+
41
+ it "should work with a mix of characters and codes" do
42
+ expect('“foo bar&#8221;').to resemble '&#8220;foo bar”'
43
+ end
44
+
45
+ it "should work with multiline strings" do
46
+ foo = <<-'EOS'
47
+ <ul>
48
+ <li>alpha</li>
49
+ <li>bravo</li>
50
+ <li>charlie</li>
51
+ </ul>
52
+ EOS
53
+ bar = <<-'EOS'
54
+ <ul>
55
+ <li>alpha</li>
56
+ <li>bravo</li>
57
+ <li>charlie</li>
58
+ </ul>
59
+ EOS
60
+
61
+ expect(foo).to resemble bar
62
+ end
63
+
64
+ it "should handle HTML fragments identical up to whitespace" do
65
+ foo = "<em> foobar\n</em>"
66
+ bar = "<em>foobar</em>"
67
+ expect(foo).to resemble bar
68
+ end
69
+ end
@@ -0,0 +1,38 @@
1
+ require 'simplecov'
2
+ require 'json'
3
+ require 'coveralls'
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ SimpleCov::Formatter::HTMLFormatter,
7
+ Coveralls::SimpleCov::Formatter
8
+ ]
9
+ SimpleCov.start
10
+
11
+ require 'polytexnic'
12
+
13
+ # Load support files.
14
+ Dir.glob(File.join(File.dirname(__FILE__), "./support/**/*.rb")).each do |f|
15
+ require_relative(f)
16
+ end
17
+
18
+ RSpec.configure do |config|
19
+ config.treat_symbols_as_metadata_keys_with_true_values = true
20
+ config.run_all_when_everything_filtered = true
21
+ config.filter_run :focus
22
+
23
+ Polytexnic::Utils.set_test_mode!
24
+ config.before do
25
+ Polytexnic::Utils.set_test_mode!
26
+ end
27
+
28
+ # Disallow the old-style 'object.should' syntax.
29
+ config.expect_with :rspec do |c|
30
+ c.syntax = :expect
31
+ end
32
+
33
+ # Run specs in random order to surface order dependencies. If you find an
34
+ # order dependency and want to debug it, you can fix the order by providing
35
+ # the seed, which is printed after each run.
36
+ # --seed 1234
37
+ config.order = 'random'
38
+ end
@@ -0,0 +1,100 @@
1
+ # encoding=utf-8
2
+ require 'polytexnic'
3
+
4
+ RSpec::Matchers.define :resemble do |expected|
5
+ match do |actual|
6
+ if expected.is_a?(String)
7
+ regex = %r{#{Regexp.escape(expected.robust)}}
8
+ elsif expected.is_a?(Regexp)
9
+ regex = %r{#{expected.to_s.robust}}
10
+ end
11
+
12
+ failure_message_for_should do |actual|
13
+ debug_output(expected, actual)
14
+ "expected #{actual} to resemble #{expected}"
15
+ end
16
+
17
+ failure_message_for_should_not do |actual|
18
+ debug_output(expected, actual)
19
+ "expected #{actual} not to resemble #{expected}"
20
+ end
21
+
22
+ expect(actual.robust).to match_regex(regex)
23
+ end
24
+ end
25
+
26
+ def debug_output(expected, actual)
27
+ print_output expected, actual if Polytexnic::Utils.debug?
28
+ end
29
+
30
+ # Prints the robust versions of the two strings
31
+ # The output is hugely useful in visually diffing, e.g., HTML output.
32
+ def print_output(expected, actual)
33
+ puts "expect: " + expected.robust
34
+ puts "actual: " + actual.robust
35
+ end
36
+
37
+ class String
38
+
39
+ # Prepares a string for robust comparison.
40
+ def robust
41
+ apply_character_equivalences.compress.remove_tag_whitespace
42
+ end
43
+
44
+ # Applies UTF-8 character code equivalences.
45
+ # For example, '&#133;' and '…' are the same character (horizontal ellipsis),
46
+ # and depending on the version of Ruby and other factors the string might
47
+ # contain either or both.
48
+ # We want to be robust to the differences, to gsub them out.
49
+ # For clarity, we standardize on the characters that look literally correct,
50
+ # e.g., '…'.
51
+ # Rather than be exhaustive, we of course only check the ones actually
52
+ # used in the tests. Browsers, etc., display them the same.
53
+ def apply_character_equivalences
54
+ equivalences = [ ['&#8216;', '‘'],
55
+ ['&#8217;', '’'],
56
+ ['&#8220;', '“'],
57
+ ['&#8221;', '”'],
58
+ ['&#160;', ' '], # nonbreaking space
59
+ ['&thinsp;',' '], # thin space
60
+ ['&#133;', '…'],
61
+ ['&#8230;', '…'],
62
+ ['&#8617', '↩']
63
+ ]
64
+ tap do
65
+ equivalences.each do |code, character|
66
+ gsub!(code, character)
67
+ end
68
+ end
69
+ end
70
+
71
+ def remove_tag_whitespace
72
+ gsub(/\s*</, '<').gsub(/>\s*/, '>')
73
+ end
74
+
75
+ # Compress whitespace
76
+ # Eliminates repeating whitespace (spaces, tabs, or Unicode nbsp),
77
+ # converting everthing to ordinary spaces, while stripping leading
78
+ # and trailing whitespace.
79
+ # >> "foo\t bar\n\nbaz quux\nderp".compress
80
+ # => "foo bar baz quux derp"
81
+ #
82
+ # Spaces surround each line are stripped entirely, so that
83
+ # <ul>
84
+ # <li>alpha</li>
85
+ # <li>bravo</li>
86
+ # <li>charlie</li>
87
+ # </ul>
88
+ # becomes
89
+ # <ul>
90
+ # <li>alpha</li>
91
+ # <li>bravo</li>
92
+ # <li>charlie</li>
93
+ # </ul>
94
+ def compress
95
+ unicode_nbsp = ' '
96
+ result = gsub(unicode_nbsp, ' ')
97
+ stripped_result = result.split("\n").map(&:strip).join("\n")
98
+ stripped_result.gsub("\n", ' ').gsub(/[ \t]{2,}/, ' ')
99
+ end
100
+ end
@@ -0,0 +1,42 @@
1
+ # encoding=utf-8
2
+ require 'spec_helper'
3
+
4
+ describe 'Polytexnic::Pipeline#to_html' do
5
+
6
+ subject(:processed_text) { Polytexnic::Pipeline.new(polytex).to_html }
7
+
8
+ describe "code listings" do
9
+ let(:polytex) do <<-'EOS'
10
+ \chapter{Foo bar}
11
+
12
+ \begin{aside}
13
+ \heading{Lorem ipsum.}
14
+ \label{aside:lorem}
15
+
16
+ lorem ipsum
17
+
18
+ dolor sit amet
19
+
20
+ \end{aside}
21
+
22
+ Box~\ref{aside:lorem}
23
+ EOS
24
+ end
25
+
26
+ it do
27
+ should resemble <<-'EOS'
28
+ <div id="cid1" data-tralics-id="cid1" class="chapter" data-number="1"><h1><a href="#cid1" class="heading"><span class="number">Chapter 1 </span>Foo bar</a></h1>
29
+ <div class="aside" id="aside-lorem" data-tralics-id="uid1" data-number="1.1">
30
+ <div class="heading">
31
+ <span class="number">Box 1.1.</span>
32
+ <span class="description">Lorem ipsum.</span>
33
+ </div>
34
+ <p>lorem ipsum</p>
35
+ <p>dolor sit amet</p>
36
+ </div>
37
+ <p><a href="#aside-lorem" class="hyperref">Box <span class="ref">1.1</span></a></p>
38
+ </div>
39
+ EOS
40
+ end
41
+ end
42
+ end