vfl 0.0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/VanillaGithub.jpg +0 -0
- data/bin/vanilla +1821 -0
- data/documentation.pdf +0 -0
- data/documentation.tex +366 -0
- data/documentation.texpack +6 -0
- data/lib/vfl.rb +5 -0
- data/lib/vfl/version.rb +3 -0
- data/src/vanilla.rb +1819 -0
- data/vfl.gemspec +23 -0
- metadata +95 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 Adhithya Rajasekaran
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Vanilla
|
|
2
|
+
|
|
3
|
+
Vanilla is a small yet powerful LaTex preprocessor written in Ruby. It reduces verbosity and improves productivity when using LaTex.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
You can install Vanilla yourself by running:
|
|
8
|
+
|
|
9
|
+
$ gem install vfl
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
To compile a **Vanilla Flavored Latex** file, just run
|
|
14
|
+
|
|
15
|
+
$ vanilla --compile file.latex
|
|
16
|
+
|
|
17
|
+
## Documentation
|
|
18
|
+
|
|
19
|
+
You can read the documentation of the preprocessor in the file named **"Documentation.pdf"**. The source of the documentation is written in Vanilla itself and provided as a reference.
|
|
20
|
+
|
|
21
|
+
## Contributing
|
|
22
|
+
|
|
23
|
+
1. Fork it
|
|
24
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
25
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
26
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
27
|
+
5. Create new Pull Request
|
|
28
|
+
|
|
29
|
+
## License
|
|
30
|
+
|
|
31
|
+
The project is released under MIT License.
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
data/VanillaGithub.jpg
ADDED
|
Binary file
|
data/bin/vanilla
ADDED
|
@@ -0,0 +1,1821 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
#Vanilla is a simple yet powerful preprocessor for LaTex
|
|
4
|
+
#
|
|
5
|
+
#The project is hosted at http://github.com/adhithyan15/vanilla
|
|
6
|
+
#
|
|
7
|
+
#This compiler is a translation of the original compiler written in Python. But a lot of algorithmic structure has been
|
|
8
|
+
#modified to give optimum performance.Some parts may be rewritten in the upcoming releases.
|
|
9
|
+
#
|
|
10
|
+
#The prototype compilers written in Matlab and Python are now available in the Old Compiler Prototypes directory
|
|
11
|
+
#
|
|
12
|
+
#Authors: Adhithya Rajasekaran and Sri Madhavi Rajasekaran
|
|
13
|
+
#
|
|
14
|
+
#To know more about the features implemented in this compiler, please read the documentation.
|
|
15
|
+
#
|
|
16
|
+
#Abbrevations: VAL => Vanilla Flavored LaTex
|
|
17
|
+
|
|
18
|
+
require 'FileUtils'
|
|
19
|
+
|
|
20
|
+
require 'optparse'
|
|
21
|
+
|
|
22
|
+
def start_compile(input_val_file) #This method starts the compilation process
|
|
23
|
+
|
|
24
|
+
def read_file_line_by_line(input_path)
|
|
25
|
+
|
|
26
|
+
#This method returns each line of the VAL file as a list
|
|
27
|
+
|
|
28
|
+
file_id = open(input_path)
|
|
29
|
+
|
|
30
|
+
file_line_by_line = file_id.readlines()
|
|
31
|
+
|
|
32
|
+
file_id.close
|
|
33
|
+
|
|
34
|
+
return file_line_by_line
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
#The following are undocumented features mostly written to write the documentation.
|
|
39
|
+
|
|
40
|
+
def replace_fenced_code_block(input_file_contents,input_val_file)
|
|
41
|
+
|
|
42
|
+
#Latex offers Verbatim mode through verbatim package to prevent code from execution.Fence code block extends the verbatim mode to include
|
|
43
|
+
#VAL code also. Verbatim package is a part of our default pack so you don't have to manually import and use it.
|
|
44
|
+
|
|
45
|
+
#This method replaces all the declared fenced code blocks with @@fenced_code_block[identifier]
|
|
46
|
+
#This is done to prevent compile time error prevention.
|
|
47
|
+
|
|
48
|
+
def find_all_matching_indices(input_string,pattern)
|
|
49
|
+
|
|
50
|
+
locations = []
|
|
51
|
+
|
|
52
|
+
index = input_string.index(pattern)
|
|
53
|
+
|
|
54
|
+
while index != nil
|
|
55
|
+
|
|
56
|
+
locations << index
|
|
57
|
+
|
|
58
|
+
index = input_string.index(pattern,index+1)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
return locations
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def find_val_file_path(input_path)
|
|
69
|
+
|
|
70
|
+
#This method is utilized to extract the path of the VAL file.
|
|
71
|
+
|
|
72
|
+
extension_remover = input_path.split(".tex")
|
|
73
|
+
|
|
74
|
+
remaining_string = extension_remover[0].reverse
|
|
75
|
+
|
|
76
|
+
path_finder = remaining_string.index("/")
|
|
77
|
+
|
|
78
|
+
remaining_string = remaining_string.reverse
|
|
79
|
+
|
|
80
|
+
return remaining_string[0...remaining_string.length-path_finder]
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
input_file_as_string = input_file_contents.join
|
|
85
|
+
|
|
86
|
+
modified_input_string = input_file_as_string.dup
|
|
87
|
+
|
|
88
|
+
preferred_directory = find_val_file_path(input_val_file)
|
|
89
|
+
|
|
90
|
+
locate_fenced_code_block = find_all_matching_indices(input_file_as_string,"###")
|
|
91
|
+
|
|
92
|
+
fenced_code_block = []
|
|
93
|
+
|
|
94
|
+
start_location = 0
|
|
95
|
+
|
|
96
|
+
end_location = 1
|
|
97
|
+
|
|
98
|
+
if locate_fenced_code_block.length.modulo(2) == 0
|
|
99
|
+
|
|
100
|
+
for x in 0...locate_fenced_code_block.length/2
|
|
101
|
+
|
|
102
|
+
fenced_code_block_string = input_file_as_string[locate_fenced_code_block[start_location]..locate_fenced_code_block[end_location]+2]
|
|
103
|
+
|
|
104
|
+
fenced_code_block << fenced_code_block_string
|
|
105
|
+
|
|
106
|
+
replacement_string = "@@fenced_code_block[#{x+1}]"
|
|
107
|
+
|
|
108
|
+
modified_input_string = modified_input_string.sub(fenced_code_block_string,replacement_string)
|
|
109
|
+
|
|
110
|
+
start_location = start_location + 2
|
|
111
|
+
|
|
112
|
+
end_location = end_location + 2
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
temporary_file_path = find_val_file_path(input_val_file) + "temp.tex"
|
|
119
|
+
|
|
120
|
+
file_id = open(temporary_file_path, 'w')
|
|
121
|
+
|
|
122
|
+
file_id.write(modified_input_string)
|
|
123
|
+
|
|
124
|
+
file_id.close()
|
|
125
|
+
|
|
126
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
127
|
+
|
|
128
|
+
return line_by_line_contents, temporary_file_path, fenced_code_block,preferred_directory
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def replace_inline_fenced_code(input_file_contents,temporary_file_path)
|
|
133
|
+
|
|
134
|
+
#This method will prevent inline VAL code from being compiled. This will only prevent VAL code from being
|
|
135
|
+
#compiled. If the inline code contains LaTex code, then LaTex compiler will compile it into PDF.
|
|
136
|
+
#This method was mainly written for presenting VAL code in the Vanilla documentation.
|
|
137
|
+
|
|
138
|
+
#This uses the same methodology as the fenced code block. Tt replaces inline code blocks with
|
|
139
|
+
#@@inline_code_bloc[identifier]
|
|
140
|
+
|
|
141
|
+
def find_all_matching_indices(input_string,pattern)
|
|
142
|
+
|
|
143
|
+
locations = []
|
|
144
|
+
|
|
145
|
+
index = input_string.index(pattern)
|
|
146
|
+
|
|
147
|
+
while index != nil
|
|
148
|
+
|
|
149
|
+
locations << index
|
|
150
|
+
|
|
151
|
+
index = input_string.index(pattern,index+1)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
return locations
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
input_file_as_string = input_file_contents.join
|
|
162
|
+
|
|
163
|
+
modified_input_string = input_file_as_string.dup
|
|
164
|
+
|
|
165
|
+
locate_inline_code_block = find_all_matching_indices(input_file_as_string,"%%")
|
|
166
|
+
|
|
167
|
+
inline_code_block = []
|
|
168
|
+
|
|
169
|
+
start_location = 0
|
|
170
|
+
|
|
171
|
+
end_location = 1
|
|
172
|
+
|
|
173
|
+
if locate_inline_code_block.length.modulo(2) == 0
|
|
174
|
+
|
|
175
|
+
for x in 0...locate_inline_code_block.length/2
|
|
176
|
+
|
|
177
|
+
inline_code_block_string = input_file_as_string[locate_inline_code_block[start_location]..locate_inline_code_block[end_location]+1]
|
|
178
|
+
|
|
179
|
+
inline_code_block << inline_code_block_string
|
|
180
|
+
|
|
181
|
+
replacement_string = "@@inline_code_block[#{x+1}]"
|
|
182
|
+
|
|
183
|
+
modified_input_string = modified_input_string.sub(inline_code_block_string,replacement_string)
|
|
184
|
+
|
|
185
|
+
start_location = start_location + 2
|
|
186
|
+
|
|
187
|
+
end_location = end_location + 2
|
|
188
|
+
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
file_id = open(temporary_file_path, 'w')
|
|
194
|
+
|
|
195
|
+
file_id.write(modified_input_string)
|
|
196
|
+
|
|
197
|
+
file_id.close()
|
|
198
|
+
|
|
199
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
200
|
+
|
|
201
|
+
return line_by_line_contents, temporary_file_path, inline_code_block
|
|
202
|
+
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
#The following features are documented features.
|
|
206
|
+
|
|
207
|
+
def resolve_comments(input_file_contents,temporary_file_path)
|
|
208
|
+
|
|
209
|
+
#Latex does offer support for multiline comments. But VAL makes the process easier. This method compiles
|
|
210
|
+
#VAL multiline comments into several single line latex comments.Latex comments are still valid in VAL.
|
|
211
|
+
|
|
212
|
+
def find_all_matching_indices(input_string,pattern)
|
|
213
|
+
|
|
214
|
+
locations = []
|
|
215
|
+
|
|
216
|
+
index = input_string.index(pattern)
|
|
217
|
+
|
|
218
|
+
while index != nil
|
|
219
|
+
|
|
220
|
+
locations << index
|
|
221
|
+
|
|
222
|
+
index = input_string.index(pattern,index+1)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
return locations
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
input_file_as_string = input_file_contents.join
|
|
233
|
+
|
|
234
|
+
modified_input_string = input_file_as_string.dup
|
|
235
|
+
|
|
236
|
+
location_of_multiline_comments_start = find_all_matching_indices(input_file_as_string,"%{")
|
|
237
|
+
|
|
238
|
+
location_of_multiline_comments_end = find_all_matching_indices(input_file_as_string,"}%")
|
|
239
|
+
|
|
240
|
+
if location_of_multiline_comments_start.length == location_of_multiline_comments_end.length
|
|
241
|
+
|
|
242
|
+
for x in 0...location_of_multiline_comments_start.length
|
|
243
|
+
|
|
244
|
+
multiline_comment = input_file_as_string[location_of_multiline_comments_start[x]..location_of_multiline_comments_end[x]+1]
|
|
245
|
+
|
|
246
|
+
replacement_comment = multiline_comment.sub("%{","")
|
|
247
|
+
|
|
248
|
+
replacement_comment = replacement_comment.sub("}%","")
|
|
249
|
+
|
|
250
|
+
multiline_comment_split = replacement_comment.split("\n")
|
|
251
|
+
|
|
252
|
+
for y in 0...multiline_comment_split.length
|
|
253
|
+
|
|
254
|
+
multiline_comment_split[y] = "%" + multiline_comment_split[y]
|
|
255
|
+
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
replacement_comment = multiline_comment_split.join("\n")
|
|
259
|
+
|
|
260
|
+
modified_input_string = modified_input_string.sub(multiline_comment,replacement_comment)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
file_id = open(temporary_file_path, 'w')
|
|
268
|
+
|
|
269
|
+
file_id.write(modified_input_string)
|
|
270
|
+
|
|
271
|
+
file_id.close()
|
|
272
|
+
|
|
273
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
274
|
+
|
|
275
|
+
return line_by_line_contents, temporary_file_path
|
|
276
|
+
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def resolve_constants(input_file_contents, temporary_file_path)
|
|
280
|
+
|
|
281
|
+
#Latex does offer support for declaring constants. But VAL greatly simplifies the process of declaring those constants.
|
|
282
|
+
#You can still use latex constants.
|
|
283
|
+
|
|
284
|
+
#Note:VAL constants are not transformed into Latex constants. Constants stand for what they mean.They are immutable.
|
|
285
|
+
#Pure mutable variables may be available in VAL in the future. Lexical Scoping of constants is similar to that in
|
|
286
|
+
#programming languages. This would be imminent in the code block resolution method.
|
|
287
|
+
|
|
288
|
+
#Updates 2/16/2012 -> Constants now support what our user called "Computed Properties". So users can now include
|
|
289
|
+
#calculations and reference other constants while declaring constants.
|
|
290
|
+
|
|
291
|
+
def retrieve_constants(input_file_contents)
|
|
292
|
+
|
|
293
|
+
#This method looks into the preamble of the document and picks up all the constant declarations. Then it splits and
|
|
294
|
+
#produces an array of constant names and constant values.
|
|
295
|
+
|
|
296
|
+
end_of_preamble = 0
|
|
297
|
+
|
|
298
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
299
|
+
|
|
300
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
301
|
+
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
preamble = input_file_contents[0...end_of_preamble]
|
|
305
|
+
|
|
306
|
+
modified_preamble = preamble.dup
|
|
307
|
+
|
|
308
|
+
length_of_preamble = preamble.length
|
|
309
|
+
|
|
310
|
+
variable_list = []
|
|
311
|
+
|
|
312
|
+
for x in 0...length_of_preamble
|
|
313
|
+
|
|
314
|
+
current_row = preamble[x]
|
|
315
|
+
|
|
316
|
+
if !current_row.include?("%")
|
|
317
|
+
|
|
318
|
+
if !current_row.include?("#")
|
|
319
|
+
|
|
320
|
+
if current_row.include?("@")
|
|
321
|
+
|
|
322
|
+
if current_row.index("@") == 0
|
|
323
|
+
|
|
324
|
+
if current_row.split("=").length() == 2
|
|
325
|
+
|
|
326
|
+
modified_preamble.delete(current_row)
|
|
327
|
+
|
|
328
|
+
variable_list << current_row.strip
|
|
329
|
+
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
else
|
|
339
|
+
|
|
340
|
+
inline_comment_finder = current_row.index("%")
|
|
341
|
+
|
|
342
|
+
operating_string = current_row[0...inline_comment_finder]
|
|
343
|
+
|
|
344
|
+
if !operating_string.include?("#")
|
|
345
|
+
|
|
346
|
+
if operating_string.include?("@")
|
|
347
|
+
|
|
348
|
+
if operating_string.index("@") == 0
|
|
349
|
+
|
|
350
|
+
if operating_string.split("=").length() == 2
|
|
351
|
+
|
|
352
|
+
modified_preamble.delete(current_row)
|
|
353
|
+
|
|
354
|
+
variable_list << operating_string.strip
|
|
355
|
+
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
variable_names = []
|
|
369
|
+
|
|
370
|
+
variable_values = []
|
|
371
|
+
|
|
372
|
+
for y in 0...variable_list.length
|
|
373
|
+
|
|
374
|
+
current_row = variable_list[y]
|
|
375
|
+
|
|
376
|
+
variable_name_and_value = current_row.split("=")
|
|
377
|
+
|
|
378
|
+
variable_names << variable_name_and_value[0].strip
|
|
379
|
+
|
|
380
|
+
variable_values << variable_name_and_value[1].strip
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
modified_variable_values = []
|
|
386
|
+
|
|
387
|
+
variable_values.each do |value|
|
|
388
|
+
|
|
389
|
+
if value.include? "@("
|
|
390
|
+
|
|
391
|
+
new_value = value.dup
|
|
392
|
+
|
|
393
|
+
variable_names.each do |name|
|
|
394
|
+
|
|
395
|
+
if new_value.include? name
|
|
396
|
+
|
|
397
|
+
new_value = new_value.sub(name,variable_values[variable_names.index(name)])
|
|
398
|
+
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
ruby_binding = binding
|
|
404
|
+
|
|
405
|
+
val = ruby_binding.eval(new_value).to_s
|
|
406
|
+
|
|
407
|
+
modified_variable_values << val
|
|
408
|
+
|
|
409
|
+
else
|
|
410
|
+
|
|
411
|
+
modified_variable_values << value
|
|
412
|
+
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
return variable_names, modified_variable_values, modified_preamble
|
|
418
|
+
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
variable_names, variable_values, preamble = retrieve_constants(input_file_contents)
|
|
422
|
+
|
|
423
|
+
end_of_preamble = 0
|
|
424
|
+
|
|
425
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
426
|
+
|
|
427
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
428
|
+
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
document_body = input_file_contents[end_of_preamble..-1].join
|
|
432
|
+
|
|
433
|
+
for x in 0...variable_names.length
|
|
434
|
+
|
|
435
|
+
current_variable = variable_names[x]
|
|
436
|
+
|
|
437
|
+
document_body = document_body.gsub(current_variable, variable_values[x])
|
|
438
|
+
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
file_id = open(temporary_file_path, 'w')
|
|
442
|
+
|
|
443
|
+
file_id.write(preamble.join+document_body)
|
|
444
|
+
|
|
445
|
+
file_id.close()
|
|
446
|
+
|
|
447
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
448
|
+
|
|
449
|
+
return line_by_line_contents, temporary_file_path
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def resolve_formatted_text_blocks(input_file_contents,temporary_file_path)
|
|
455
|
+
|
|
456
|
+
#This method will resolve formatted text blocks. The idea of formatted code blocks was inspired by Lesscss' parametric mixins.
|
|
457
|
+
|
|
458
|
+
#Latex doesn't offer support for formatted text blocks. So VAL provides support for it.
|
|
459
|
+
|
|
460
|
+
def retrieve_formatted_text_blocks(input_file_contents)
|
|
461
|
+
|
|
462
|
+
#This method will go through the preamble and will retrieve a list of declared formatted text blocks
|
|
463
|
+
|
|
464
|
+
def remove_comments(input_string)
|
|
465
|
+
|
|
466
|
+
#This method will remove comments from a string.This method is part of a large rewrite operation to reduce the clutter
|
|
467
|
+
#in the code and also to increase performance
|
|
468
|
+
|
|
469
|
+
if input_string.include?("%")
|
|
470
|
+
|
|
471
|
+
output_string = input_string[0...input_string.index("%")]
|
|
472
|
+
|
|
473
|
+
else
|
|
474
|
+
|
|
475
|
+
output_string = input_string
|
|
476
|
+
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
return output_string
|
|
480
|
+
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
end_of_preamble = 0
|
|
484
|
+
|
|
485
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
486
|
+
|
|
487
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
488
|
+
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
preamble = input_file_contents[0...end_of_preamble]
|
|
492
|
+
|
|
493
|
+
modified_preamble = preamble.dup
|
|
494
|
+
|
|
495
|
+
length_of_preamble = preamble.length
|
|
496
|
+
|
|
497
|
+
text_blocks_list = []
|
|
498
|
+
|
|
499
|
+
for x in 0...preamble.length
|
|
500
|
+
|
|
501
|
+
current_row = preamble[x]
|
|
502
|
+
|
|
503
|
+
if current_row.include?("#")
|
|
504
|
+
|
|
505
|
+
if current_row.include?("%")
|
|
506
|
+
|
|
507
|
+
operating_string = current_row[0...current_row.index("%")]
|
|
508
|
+
|
|
509
|
+
comment_string = current_row[current_row.index("%")..-1]
|
|
510
|
+
|
|
511
|
+
else
|
|
512
|
+
|
|
513
|
+
operating_string = current_row
|
|
514
|
+
|
|
515
|
+
comment_string = ""
|
|
516
|
+
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
text_block_finder = operating_string.split("=")
|
|
520
|
+
|
|
521
|
+
if text_block_finder.length > 1
|
|
522
|
+
|
|
523
|
+
if text_block_finder[1].include?("[")
|
|
524
|
+
|
|
525
|
+
if text_block_finder[1].include?("]")
|
|
526
|
+
|
|
527
|
+
code_block = [operating_string]
|
|
528
|
+
|
|
529
|
+
modified_preamble.delete(operating_string+comment_string)
|
|
530
|
+
|
|
531
|
+
text_blocks_list << code_block.join("")
|
|
532
|
+
|
|
533
|
+
else
|
|
534
|
+
|
|
535
|
+
next_index = x
|
|
536
|
+
|
|
537
|
+
code_block = []
|
|
538
|
+
|
|
539
|
+
text_block_end_finder = text_block_finder[1].include?("]")
|
|
540
|
+
|
|
541
|
+
while text_block_end_finder == false
|
|
542
|
+
|
|
543
|
+
code_block << preamble[next_index]
|
|
544
|
+
|
|
545
|
+
modified_preamble.delete(preamble[next_index])
|
|
546
|
+
|
|
547
|
+
next_index = next_index + 1
|
|
548
|
+
|
|
549
|
+
text_block_end_finder = preamble[next_index].include?("]")
|
|
550
|
+
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
code_block << remove_comments(preamble[next_index])
|
|
554
|
+
|
|
555
|
+
modified_preamble.delete(preamble[next_index])
|
|
556
|
+
|
|
557
|
+
text_blocks_list << code_block.join("")
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
end
|
|
567
|
+
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
code_block_names = []
|
|
571
|
+
|
|
572
|
+
code_block_values = []
|
|
573
|
+
|
|
574
|
+
for x in 0...text_blocks_list.length
|
|
575
|
+
|
|
576
|
+
current_text_block = text_blocks_list[x]
|
|
577
|
+
|
|
578
|
+
text_block_name_and_value = current_text_block.split("=")
|
|
579
|
+
|
|
580
|
+
code_block_names << text_block_name_and_value[0].strip
|
|
581
|
+
|
|
582
|
+
code_block_values << text_block_name_and_value[1].strip
|
|
583
|
+
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
return code_block_names,code_block_values,modified_preamble
|
|
587
|
+
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
def extract_parameters(names_with_params)
|
|
591
|
+
|
|
592
|
+
code_block_names = []
|
|
593
|
+
|
|
594
|
+
code_block_params = []
|
|
595
|
+
|
|
596
|
+
for x in 0...names_with_params.length
|
|
597
|
+
|
|
598
|
+
current_code_block_name = names_with_params[x]
|
|
599
|
+
|
|
600
|
+
params_split = current_code_block_name.split("[")
|
|
601
|
+
|
|
602
|
+
code_block_names << params_split[0]
|
|
603
|
+
|
|
604
|
+
params_list = params_split[1]
|
|
605
|
+
|
|
606
|
+
params_list = params_list[0...-1]
|
|
607
|
+
|
|
608
|
+
code_block_params << params_list
|
|
609
|
+
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
return code_block_names,code_block_params
|
|
613
|
+
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def find_all_matching_indices(input_string,pattern)
|
|
617
|
+
|
|
618
|
+
locations = []
|
|
619
|
+
|
|
620
|
+
index = input_string.index(pattern)
|
|
621
|
+
|
|
622
|
+
while index != nil
|
|
623
|
+
|
|
624
|
+
locations << index
|
|
625
|
+
|
|
626
|
+
index = input_string.index(pattern,index+1)
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
return locations
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
block_names_params,code_block_values,preamble = retrieve_formatted_text_blocks(input_file_contents)
|
|
637
|
+
|
|
638
|
+
code_block_names,code_block_params = extract_parameters(block_names_params)
|
|
639
|
+
|
|
640
|
+
end_of_preamble = 0
|
|
641
|
+
|
|
642
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
643
|
+
|
|
644
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
645
|
+
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
document_body = input_file_contents[end_of_preamble..-1]
|
|
649
|
+
|
|
650
|
+
document_body_as_string = document_body.join("")
|
|
651
|
+
|
|
652
|
+
modified_document_as_string = document_body_as_string.dup
|
|
653
|
+
|
|
654
|
+
for x in 0...code_block_names.length
|
|
655
|
+
|
|
656
|
+
current_code_block_name = code_block_names[x]
|
|
657
|
+
|
|
658
|
+
current_code_block_params = code_block_params[x]
|
|
659
|
+
|
|
660
|
+
current_code_block_params = current_code_block_params.split(",")
|
|
661
|
+
|
|
662
|
+
current_code_block_value = code_block_values[x]
|
|
663
|
+
|
|
664
|
+
current_code_block_value = current_code_block_value[1...-1]
|
|
665
|
+
|
|
666
|
+
location_of_code_block = find_all_matching_indices(document_body_as_string,current_code_block_name)
|
|
667
|
+
|
|
668
|
+
for y in 0...location_of_code_block.length
|
|
669
|
+
|
|
670
|
+
code_block_end_finder = document_body_as_string.index("]",location_of_code_block[y])
|
|
671
|
+
|
|
672
|
+
text_block_string = document_body_as_string[location_of_code_block[y]..code_block_end_finder]
|
|
673
|
+
|
|
674
|
+
param_split = text_block_string.split("[")
|
|
675
|
+
|
|
676
|
+
text_block_params = param_split[1]
|
|
677
|
+
|
|
678
|
+
text_block_params = text_block_params[0...-1]
|
|
679
|
+
|
|
680
|
+
text_block_params = text_block_params.split(",")
|
|
681
|
+
|
|
682
|
+
if text_block_params.length == current_code_block_params.length
|
|
683
|
+
|
|
684
|
+
parameter_map = Hash[*current_code_block_params.zip(text_block_params).flatten]
|
|
685
|
+
|
|
686
|
+
replacement_string = current_code_block_value
|
|
687
|
+
|
|
688
|
+
for z in 0...parameter_map.length
|
|
689
|
+
|
|
690
|
+
replacement_string = replacement_string.gsub(current_code_block_params[z],parameter_map[current_code_block_params[z]])
|
|
691
|
+
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
modified_document_as_string = modified_document_as_string.sub(text_block_string,replacement_string)
|
|
695
|
+
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
file_id = open(temporary_file_path, 'w')
|
|
703
|
+
|
|
704
|
+
file_id.write(preamble.join+modified_document_as_string)
|
|
705
|
+
|
|
706
|
+
file_id.close()
|
|
707
|
+
|
|
708
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
709
|
+
|
|
710
|
+
return line_by_line_contents, temporary_file_path
|
|
711
|
+
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
def resolve_formulas(input_file_contents,temporary_file_path)
|
|
715
|
+
|
|
716
|
+
#VAL Formulas are easy way to achieve certain things which are very difficult to achieve in Latex. Writing matrices
|
|
717
|
+
#is very difficult in latex. As time progresses, more formulas will be added to simplify latex typesetting.
|
|
718
|
+
|
|
719
|
+
def find_all_matching_indices(input_string,pattern)
|
|
720
|
+
|
|
721
|
+
locations = []
|
|
722
|
+
|
|
723
|
+
index = input_string.index(pattern)
|
|
724
|
+
|
|
725
|
+
while index != nil
|
|
726
|
+
|
|
727
|
+
locations << index
|
|
728
|
+
|
|
729
|
+
index = input_string.index(pattern,index+1)
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
return locations
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
def convert_to_matrix(input_list)
|
|
740
|
+
|
|
741
|
+
#This method converts the input list to latex's bmatrix environment offered through amsmath package.
|
|
742
|
+
|
|
743
|
+
start_string = "$\\begin{bmatrix}"
|
|
744
|
+
|
|
745
|
+
end_string = "\\end{bmatrix}$"
|
|
746
|
+
|
|
747
|
+
rows = []
|
|
748
|
+
|
|
749
|
+
for x in 0...input_list.length
|
|
750
|
+
|
|
751
|
+
current_row = input_list[x]
|
|
752
|
+
|
|
753
|
+
current_row_string = current_row.split.join(" & ")
|
|
754
|
+
|
|
755
|
+
rows << current_row_string
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
matrix = rows.join(" \\\\\\\\\\\\\\\\ ")
|
|
761
|
+
|
|
762
|
+
matrix = "$" + start_string + matrix + end_string + "$"
|
|
763
|
+
|
|
764
|
+
return matrix
|
|
765
|
+
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
def convert_to_determinant(input_list)
|
|
769
|
+
|
|
770
|
+
#This method converts the input list to latex's vmatrix environment offered through amsmath package.
|
|
771
|
+
|
|
772
|
+
start_string = "\\begin{vmatrix}"
|
|
773
|
+
|
|
774
|
+
end_string = "\\end{vmatrix}"
|
|
775
|
+
|
|
776
|
+
rows = []
|
|
777
|
+
|
|
778
|
+
for x in 0...input_list.length
|
|
779
|
+
|
|
780
|
+
current_row = input_list[x]
|
|
781
|
+
|
|
782
|
+
current_row_string = current_row.split.join(" & ")
|
|
783
|
+
|
|
784
|
+
rows << current_row_string
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
determinant = rows.join(" \\\\\\\\\\\\\\\\ ")
|
|
790
|
+
|
|
791
|
+
determinant = "$" + start_string + determinant + end_string + "$"
|
|
792
|
+
|
|
793
|
+
return determinant
|
|
794
|
+
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
def capitalize(input_string)
|
|
798
|
+
|
|
799
|
+
#This method will capitalize every single word in a string
|
|
800
|
+
|
|
801
|
+
input_string_split = input_string.split
|
|
802
|
+
|
|
803
|
+
for x in 0...input_string_split.length
|
|
804
|
+
|
|
805
|
+
current_word = input_string_split[x]
|
|
806
|
+
|
|
807
|
+
if current_word.length > 1
|
|
808
|
+
|
|
809
|
+
current_word = current_word[0].upcase + current_word[1..-1]
|
|
810
|
+
|
|
811
|
+
else
|
|
812
|
+
|
|
813
|
+
current_word = current_word.upcase
|
|
814
|
+
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
input_string_split[x] = current_word
|
|
818
|
+
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
return input_string_split.join(" ")
|
|
822
|
+
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
def image(input_string_split,temp_file_path)
|
|
826
|
+
|
|
827
|
+
def find_file_path(input_path,file_extension)
|
|
828
|
+
|
|
829
|
+
extension_remover = input_path.split(file_extension)
|
|
830
|
+
|
|
831
|
+
remaining_string = extension_remover[0].reverse
|
|
832
|
+
|
|
833
|
+
if remaining_string.include?("\\")
|
|
834
|
+
|
|
835
|
+
path_finder = remaining_string.index("\\")
|
|
836
|
+
|
|
837
|
+
elsif remaining_string.include?("/")
|
|
838
|
+
|
|
839
|
+
path_finder = remaining_string.index("/")
|
|
840
|
+
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
remaining_string = remaining_string.reverse
|
|
844
|
+
|
|
845
|
+
return remaining_string[0...remaining_string.length-path_finder]
|
|
846
|
+
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
def find_file_name(input_path,file_extension)
|
|
850
|
+
|
|
851
|
+
extension_remover = input_path.split(file_extension)
|
|
852
|
+
|
|
853
|
+
remaining_string = extension_remover[0].reverse
|
|
854
|
+
|
|
855
|
+
path_finder = remaining_string.index("\\")
|
|
856
|
+
|
|
857
|
+
remaining_string = remaining_string.reverse
|
|
858
|
+
|
|
859
|
+
return remaining_string[remaining_string.length-path_finder..-1]
|
|
860
|
+
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
def find_file_extension(input_path)
|
|
864
|
+
|
|
865
|
+
extension_start = input_path.index(".")
|
|
866
|
+
|
|
867
|
+
return input_path[extension_start..-1]
|
|
868
|
+
|
|
869
|
+
end
|
|
870
|
+
|
|
871
|
+
available_options = ["scale","width","height","angle","page"]
|
|
872
|
+
|
|
873
|
+
image_path = input_string_split[0]
|
|
874
|
+
|
|
875
|
+
options = input_string_split[1]
|
|
876
|
+
|
|
877
|
+
current_destination = find_file_path(image_path,find_file_extension(image_path))
|
|
878
|
+
|
|
879
|
+
to_be_moved_destination = find_file_path(temp_file_path,".tex")
|
|
880
|
+
|
|
881
|
+
to_be_moved_dest = to_be_moved_destination + "/#{find_file_name(image_path,"#{find_file_extension(image_path)}")}#{find_file_extension(image_path)}"
|
|
882
|
+
|
|
883
|
+
if !current_destination.eql? to_be_moved_destination
|
|
884
|
+
|
|
885
|
+
FileUtils.cp image_path,to_be_moved_dest
|
|
886
|
+
|
|
887
|
+
eval_binding = binding
|
|
888
|
+
|
|
889
|
+
options_hash = eval_binding.eval(options)
|
|
890
|
+
|
|
891
|
+
option_values = []
|
|
892
|
+
|
|
893
|
+
available_options.each do |option|
|
|
894
|
+
|
|
895
|
+
if options_hash.has_key?(option.to_sym)
|
|
896
|
+
|
|
897
|
+
option_values << option + " = #{options_hash[option.to_sym]}"
|
|
898
|
+
|
|
899
|
+
end
|
|
900
|
+
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
return_string = "\\\\includegraphics[#{option_values.join(",")}]{#{find_file_name(image_path,"#{find_file_extension(image_path)}")}}"
|
|
904
|
+
|
|
905
|
+
else
|
|
906
|
+
|
|
907
|
+
eval_binding = binding
|
|
908
|
+
|
|
909
|
+
options_hash = eval_binding.eval(options)
|
|
910
|
+
|
|
911
|
+
option_values = []
|
|
912
|
+
|
|
913
|
+
available_options.each do |option|
|
|
914
|
+
|
|
915
|
+
option_values << option + " = #{options_hash[option.to_sym]}"
|
|
916
|
+
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
return_string = "\\\\includegraphics[#{option_values.join(",")}]{#{find_file_name(image_path,".#{find_file_extension(image_path)}")}}"
|
|
920
|
+
|
|
921
|
+
end
|
|
922
|
+
|
|
923
|
+
return return_string
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
available_formulas = ["$(matrix)","$(det)","$(cap)","$(image)"]
|
|
929
|
+
|
|
930
|
+
input_file_as_string = input_file_contents.join
|
|
931
|
+
|
|
932
|
+
modified_input_string = input_file_as_string.dup
|
|
933
|
+
|
|
934
|
+
for x in 0...available_formulas.length
|
|
935
|
+
|
|
936
|
+
current_formula = available_formulas[x]
|
|
937
|
+
|
|
938
|
+
location_of_current_formula = find_all_matching_indices(input_file_as_string,current_formula)
|
|
939
|
+
|
|
940
|
+
for y in 0...location_of_current_formula.length
|
|
941
|
+
|
|
942
|
+
replacement_string = ""
|
|
943
|
+
|
|
944
|
+
extract_string = input_file_as_string[location_of_current_formula[y]..-1]
|
|
945
|
+
|
|
946
|
+
current_formula_end = extract_string.index("]")
|
|
947
|
+
|
|
948
|
+
formula_usage_string = extract_string[0..current_formula_end]
|
|
949
|
+
|
|
950
|
+
formula_usage_string_split = formula_usage_string.split("[")
|
|
951
|
+
|
|
952
|
+
formula_usage_string_split = formula_usage_string_split[1].split("]")
|
|
953
|
+
|
|
954
|
+
if x == 0
|
|
955
|
+
|
|
956
|
+
formula_usage_string_split = formula_usage_string_split[0].split(";")
|
|
957
|
+
|
|
958
|
+
replacement_string = convert_to_matrix(formula_usage_string_split)
|
|
959
|
+
|
|
960
|
+
elsif x == 1
|
|
961
|
+
|
|
962
|
+
formula_usage_string_split = formula_usage_string_split[0].split(";")
|
|
963
|
+
|
|
964
|
+
replacement_string = convert_to_determinant(formula_usage_string_split)
|
|
965
|
+
|
|
966
|
+
elsif x == 2
|
|
967
|
+
|
|
968
|
+
replacement_string = capitalize(formula_usage_string_split[0])
|
|
969
|
+
|
|
970
|
+
|
|
971
|
+
elsif x == 3
|
|
972
|
+
|
|
973
|
+
replacement_string = image(formula_usage_string_split[0].split(","),temporary_file_path)
|
|
974
|
+
|
|
975
|
+
end
|
|
976
|
+
|
|
977
|
+
modified_input_string = modified_input_string.sub(formula_usage_string,replacement_string)
|
|
978
|
+
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
end
|
|
982
|
+
|
|
983
|
+
file_id = open(temporary_file_path, 'w')
|
|
984
|
+
|
|
985
|
+
file_id.write(modified_input_string)
|
|
986
|
+
|
|
987
|
+
file_id.close()
|
|
988
|
+
|
|
989
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
990
|
+
|
|
991
|
+
return line_by_line_contents, temporary_file_path
|
|
992
|
+
|
|
993
|
+
end
|
|
994
|
+
|
|
995
|
+
def resolve_inline_calculations(input_file_contents,temporary_file_path)
|
|
996
|
+
|
|
997
|
+
#This method is used in converting inline calculations into answers. It uses ruby's eval method to achieve this.
|
|
998
|
+
|
|
999
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1000
|
+
|
|
1001
|
+
locations = []
|
|
1002
|
+
|
|
1003
|
+
index = input_string.index(pattern)
|
|
1004
|
+
|
|
1005
|
+
while index != nil
|
|
1006
|
+
|
|
1007
|
+
locations << index
|
|
1008
|
+
|
|
1009
|
+
index = input_string.index(pattern,index+1)
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
return locations
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
end
|
|
1018
|
+
|
|
1019
|
+
for x in 0...input_file_contents.length
|
|
1020
|
+
|
|
1021
|
+
current_row = input_file_contents[x]
|
|
1022
|
+
|
|
1023
|
+
operating_row = current_row.dup
|
|
1024
|
+
|
|
1025
|
+
comment_string = ""
|
|
1026
|
+
|
|
1027
|
+
if current_row.include?("%")
|
|
1028
|
+
|
|
1029
|
+
operating_row = current_row[0...current_row.index("%")]
|
|
1030
|
+
|
|
1031
|
+
comment_string = current_row[current_row.index("%")...-1]
|
|
1032
|
+
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
inline_calculation_strings = operating_row.match /!\[.{1,}\]/
|
|
1036
|
+
|
|
1037
|
+
inline_calculation_strings = inline_calculation_strings.to_a
|
|
1038
|
+
|
|
1039
|
+
for y in 0...inline_calculation_strings.length
|
|
1040
|
+
|
|
1041
|
+
inline_calculation_string = inline_calculation_strings[y]
|
|
1042
|
+
|
|
1043
|
+
inline_calc_ruby_string = inline_calculation_string.dup
|
|
1044
|
+
|
|
1045
|
+
inline_calc_ruby_string = inline_calc_ruby_string[2...-1]
|
|
1046
|
+
|
|
1047
|
+
inline_calc_ruby_string = inline_calc_ruby_string.sub("^","**").to_s()
|
|
1048
|
+
|
|
1049
|
+
eval_binding = binding
|
|
1050
|
+
|
|
1051
|
+
inline_calculation_answer = eval_binding.eval(inline_calc_ruby_string)
|
|
1052
|
+
|
|
1053
|
+
inline_calculation_answer = inline_calculation_answer.to_s
|
|
1054
|
+
|
|
1055
|
+
if inline_calculation_answer.include?(".")
|
|
1056
|
+
|
|
1057
|
+
inline_calculation_answer = inline_calculation_answer.to_f.round(3).to_s
|
|
1058
|
+
|
|
1059
|
+
end
|
|
1060
|
+
|
|
1061
|
+
current_row = current_row.sub(inline_calculation_string,inline_calculation_answer)
|
|
1062
|
+
|
|
1063
|
+
end
|
|
1064
|
+
|
|
1065
|
+
input_file_contents[x] = current_row
|
|
1066
|
+
|
|
1067
|
+
end
|
|
1068
|
+
|
|
1069
|
+
file_id = open(temporary_file_path, 'w')
|
|
1070
|
+
|
|
1071
|
+
file_id.write(input_file_contents.join)
|
|
1072
|
+
|
|
1073
|
+
file_id.close()
|
|
1074
|
+
|
|
1075
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
1076
|
+
|
|
1077
|
+
return line_by_line_contents, temporary_file_path
|
|
1078
|
+
|
|
1079
|
+
end
|
|
1080
|
+
|
|
1081
|
+
def resolve_inline_formatting(input_file_contents,temporary_file_path)
|
|
1082
|
+
|
|
1083
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1084
|
+
|
|
1085
|
+
locations = []
|
|
1086
|
+
|
|
1087
|
+
index = input_string.index(pattern)
|
|
1088
|
+
|
|
1089
|
+
while index != nil
|
|
1090
|
+
|
|
1091
|
+
locations << index
|
|
1092
|
+
|
|
1093
|
+
index = input_string.index(pattern,index+1)
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
end
|
|
1097
|
+
|
|
1098
|
+
return locations
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
end
|
|
1102
|
+
|
|
1103
|
+
document_as_string = input_file_contents.join
|
|
1104
|
+
|
|
1105
|
+
available_formatting = ["**","///","+*","+/","___","~~~"]
|
|
1106
|
+
|
|
1107
|
+
matching_formatting = {"**" => "\\textbf{","///" => "\\emph{" , "+*" => "\\mathbf{" , "+/" => "\\mathit{", "___" => "\\underline{","~~~" => "\\sout{"}
|
|
1108
|
+
|
|
1109
|
+
for x in 0...available_formatting.length
|
|
1110
|
+
|
|
1111
|
+
current_formatting = available_formatting[x]
|
|
1112
|
+
|
|
1113
|
+
location_of_current_formatting = find_all_matching_indices(document_as_string,current_formatting)
|
|
1114
|
+
|
|
1115
|
+
if location_of_current_formatting.length.modulo(2) == 0
|
|
1116
|
+
|
|
1117
|
+
for y in 0...((location_of_current_formatting.length)/2)
|
|
1118
|
+
|
|
1119
|
+
document_as_string = document_as_string.sub(current_formatting,matching_formatting[current_formatting])
|
|
1120
|
+
|
|
1121
|
+
document_as_string = document_as_string.sub(current_formatting,"}")
|
|
1122
|
+
|
|
1123
|
+
end
|
|
1124
|
+
|
|
1125
|
+
end
|
|
1126
|
+
|
|
1127
|
+
end
|
|
1128
|
+
|
|
1129
|
+
file_id = open(temporary_file_path, 'w')
|
|
1130
|
+
|
|
1131
|
+
file_id.write(document_as_string)
|
|
1132
|
+
|
|
1133
|
+
file_id.close()
|
|
1134
|
+
|
|
1135
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
1136
|
+
|
|
1137
|
+
return line_by_line_contents, temporary_file_path
|
|
1138
|
+
|
|
1139
|
+
end
|
|
1140
|
+
|
|
1141
|
+
def resolve_fenced_code_blocks(input_file_contents,temporary_file_path,fenced_code_blocks)
|
|
1142
|
+
|
|
1143
|
+
input_file_as_string = input_file_contents.join
|
|
1144
|
+
|
|
1145
|
+
for x in 0...fenced_code_blocks.length
|
|
1146
|
+
|
|
1147
|
+
fenced_code_block_string = "@@fenced_code_block[#{x+1}]"
|
|
1148
|
+
|
|
1149
|
+
replacement_string = fenced_code_blocks[x]
|
|
1150
|
+
|
|
1151
|
+
replacement_string = replacement_string.sub("###","\\begin{verbatim}")
|
|
1152
|
+
|
|
1153
|
+
replacement_string = replacement_string.sub("###","\\end{verbatim}")
|
|
1154
|
+
|
|
1155
|
+
input_file_as_string = input_file_as_string.sub(fenced_code_block_string,replacement_string)
|
|
1156
|
+
|
|
1157
|
+
end
|
|
1158
|
+
|
|
1159
|
+
file_id = open(temporary_file_path, 'w')
|
|
1160
|
+
|
|
1161
|
+
file_id.write(input_file_as_string)
|
|
1162
|
+
|
|
1163
|
+
file_id.close()
|
|
1164
|
+
|
|
1165
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
1166
|
+
|
|
1167
|
+
return line_by_line_contents, temporary_file_path
|
|
1168
|
+
|
|
1169
|
+
|
|
1170
|
+
end
|
|
1171
|
+
|
|
1172
|
+
def resolve_inline_fenced_code(input_file_contents,temporary_file_path,inline_code_blocks)
|
|
1173
|
+
|
|
1174
|
+
input_file_as_string = input_file_contents.join
|
|
1175
|
+
|
|
1176
|
+
for x in 0...inline_code_blocks.length
|
|
1177
|
+
|
|
1178
|
+
fenced_code_block_string = "@@inline_code_block[#{x+1}]"
|
|
1179
|
+
|
|
1180
|
+
replacement_string = inline_code_blocks[x]
|
|
1181
|
+
|
|
1182
|
+
input_file_as_string = input_file_as_string.sub(fenced_code_block_string,replacement_string[2...-2])
|
|
1183
|
+
|
|
1184
|
+
end
|
|
1185
|
+
|
|
1186
|
+
file_id = open(temporary_file_path, 'w')
|
|
1187
|
+
|
|
1188
|
+
file_id.write(input_file_as_string)
|
|
1189
|
+
|
|
1190
|
+
file_id.close()
|
|
1191
|
+
|
|
1192
|
+
line_by_line_contents = read_file_line_by_line(temporary_file_path)
|
|
1193
|
+
|
|
1194
|
+
return line_by_line_contents, temporary_file_path
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
end
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
def resolve_tex_packs(input_file_contents,temporary_file,preference_directory)
|
|
1201
|
+
|
|
1202
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1203
|
+
|
|
1204
|
+
locations = []
|
|
1205
|
+
|
|
1206
|
+
index = input_string.index(pattern)
|
|
1207
|
+
|
|
1208
|
+
while index != nil
|
|
1209
|
+
|
|
1210
|
+
locations << index
|
|
1211
|
+
|
|
1212
|
+
index = input_string.index(pattern,index+1)
|
|
1213
|
+
|
|
1214
|
+
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
return locations
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
default_texpack = [
|
|
1223
|
+
"\\usepackage{amsmath,amssymb,amsthm}\n\n",
|
|
1224
|
+
"\\usepackage[a4paper,margin = 1in]{geometry}\n\n",
|
|
1225
|
+
"\\usepackage{hyperref}\n\n",
|
|
1226
|
+
"\\usepackage[normalem]{ulem}\n\n",
|
|
1227
|
+
"\\usepackage{xcolor}\n\n",
|
|
1228
|
+
"\\usepackage{verbatim}\n\n",
|
|
1229
|
+
"\\usepackage{booktabs}\n\n",
|
|
1230
|
+
"\\usepackage{graphicx}\n\n",
|
|
1231
|
+
"\\usepackage{multicol}\n\n",
|
|
1232
|
+
"\\usepackage{cleveref}\n\n",
|
|
1233
|
+
"\\usepackage{siunitx}\n"]
|
|
1234
|
+
|
|
1235
|
+
end_of_preamble = 0
|
|
1236
|
+
|
|
1237
|
+
if input_file_contents.include?("\\begin{document}\n")
|
|
1238
|
+
|
|
1239
|
+
end_of_preamble = input_file_contents.index("\\begin{document}\n")
|
|
1240
|
+
|
|
1241
|
+
end
|
|
1242
|
+
|
|
1243
|
+
preamble = input_file_contents[0...end_of_preamble]
|
|
1244
|
+
|
|
1245
|
+
document_string = input_file_contents[end_of_preamble..-1].join
|
|
1246
|
+
|
|
1247
|
+
preamble_string = preamble.join
|
|
1248
|
+
|
|
1249
|
+
if !preamble_string.include?("$(importpack)") and !preamble_string.include?("\\usepackage")
|
|
1250
|
+
|
|
1251
|
+
default_texpack_string = default_texpack.join
|
|
1252
|
+
|
|
1253
|
+
documentclass_finder = preamble_string.index("\\documentclass")
|
|
1254
|
+
|
|
1255
|
+
extract_string = preamble_string[documentclass_finder..-1]
|
|
1256
|
+
|
|
1257
|
+
documentclass_end = extract_string.index("}")
|
|
1258
|
+
|
|
1259
|
+
documentclass_string = extract_string[0..documentclass_end]
|
|
1260
|
+
|
|
1261
|
+
replacement_string = documentclass_string + "\n\n" + default_texpack_string + "\n\n"
|
|
1262
|
+
|
|
1263
|
+
preamble_string = preamble_string.sub(documentclass_string,replacement_string)
|
|
1264
|
+
|
|
1265
|
+
elsif preamble_string.include?("$(importpack)")
|
|
1266
|
+
|
|
1267
|
+
importpack_locations = find_all_matching_indices(preamble_string,"$(importpack)")
|
|
1268
|
+
|
|
1269
|
+
for x in 0...importpack_locations.length
|
|
1270
|
+
|
|
1271
|
+
current_location = importpack_locations[x]
|
|
1272
|
+
|
|
1273
|
+
extract_string = preamble_string[current_location..-1]
|
|
1274
|
+
|
|
1275
|
+
importpack_end = extract_string.index("]")
|
|
1276
|
+
|
|
1277
|
+
importpack_string = extract_string[0..importpack_end]
|
|
1278
|
+
|
|
1279
|
+
importpack_string_split = importpack_string.split("[")
|
|
1280
|
+
|
|
1281
|
+
importpack_string_split = importpack_string_split[1].split("]")
|
|
1282
|
+
|
|
1283
|
+
importpack_name = importpack_string_split[0]
|
|
1284
|
+
|
|
1285
|
+
if !importpack_name.include?("\\")
|
|
1286
|
+
|
|
1287
|
+
importpack_path = preference_directory + importpack_name + ".texpack"
|
|
1288
|
+
|
|
1289
|
+
else
|
|
1290
|
+
|
|
1291
|
+
importpack_path = importpack_name
|
|
1292
|
+
|
|
1293
|
+
end
|
|
1294
|
+
|
|
1295
|
+
texpack_file = read_file_line_by_line(importpack_path).join
|
|
1296
|
+
|
|
1297
|
+
preamble_string = preamble_string.sub(importpack_string,texpack_file)
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
end
|
|
1301
|
+
|
|
1302
|
+
end
|
|
1303
|
+
|
|
1304
|
+
file_id = open(temporary_file, 'w')
|
|
1305
|
+
|
|
1306
|
+
file_id.write(preamble_string + document_string)
|
|
1307
|
+
|
|
1308
|
+
file_id.close()
|
|
1309
|
+
|
|
1310
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1311
|
+
|
|
1312
|
+
return line_by_line_contents, temporary_file
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
end
|
|
1316
|
+
|
|
1317
|
+
def resolve_bare_urls(input_file_contents,temporary_file)
|
|
1318
|
+
|
|
1319
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1320
|
+
|
|
1321
|
+
locations = []
|
|
1322
|
+
|
|
1323
|
+
index = input_string.index(pattern)
|
|
1324
|
+
|
|
1325
|
+
while index != nil
|
|
1326
|
+
|
|
1327
|
+
locations << index
|
|
1328
|
+
|
|
1329
|
+
index = input_string.index(pattern,index+1)
|
|
1330
|
+
|
|
1331
|
+
|
|
1332
|
+
end
|
|
1333
|
+
|
|
1334
|
+
return locations
|
|
1335
|
+
|
|
1336
|
+
|
|
1337
|
+
end
|
|
1338
|
+
|
|
1339
|
+
def modify_urls(input_url_string)
|
|
1340
|
+
|
|
1341
|
+
return_string = "\\url{#{input_url_string}}"
|
|
1342
|
+
|
|
1343
|
+
return return_string
|
|
1344
|
+
|
|
1345
|
+
end
|
|
1346
|
+
|
|
1347
|
+
input_file_as_string = input_file_contents.join
|
|
1348
|
+
|
|
1349
|
+
modified_input_string = input_file_as_string.dup
|
|
1350
|
+
|
|
1351
|
+
url_identifiers = ["http","www"]
|
|
1352
|
+
|
|
1353
|
+
replacements = ["@@http[]","@@www[]"]
|
|
1354
|
+
|
|
1355
|
+
identifier_matches = []
|
|
1356
|
+
|
|
1357
|
+
replacement_strings = []
|
|
1358
|
+
|
|
1359
|
+
for x in 0...url_identifiers.length
|
|
1360
|
+
|
|
1361
|
+
current_identifier = url_identifiers[x]
|
|
1362
|
+
|
|
1363
|
+
current_replacement = replacements[x]
|
|
1364
|
+
|
|
1365
|
+
current_replacement_split = current_replacement.split("]")
|
|
1366
|
+
|
|
1367
|
+
location_of_current_identifer = find_all_matching_indices(input_file_as_string,current_identifier)
|
|
1368
|
+
|
|
1369
|
+
current_identifier_matches = []
|
|
1370
|
+
|
|
1371
|
+
current_replacement_strings = []
|
|
1372
|
+
|
|
1373
|
+
for y in 0...location_of_current_identifer.length
|
|
1374
|
+
|
|
1375
|
+
current_location = location_of_current_identifer[y]
|
|
1376
|
+
|
|
1377
|
+
extract_string = input_file_as_string[current_location..-1]
|
|
1378
|
+
|
|
1379
|
+
url_extract = extract_string.split(" ",2)
|
|
1380
|
+
|
|
1381
|
+
current_identifier_matches << url_extract[0]
|
|
1382
|
+
|
|
1383
|
+
replacement_string = current_replacement_split[0] + (y+1).to_s + "]"
|
|
1384
|
+
|
|
1385
|
+
current_replacement_strings << replacement_string
|
|
1386
|
+
|
|
1387
|
+
modified_input_string = modified_input_string.sub(url_extract[0],replacement_string)
|
|
1388
|
+
|
|
1389
|
+
end
|
|
1390
|
+
|
|
1391
|
+
identifier_matches << current_identifier_matches
|
|
1392
|
+
|
|
1393
|
+
replacement_strings << current_replacement_strings
|
|
1394
|
+
|
|
1395
|
+
end
|
|
1396
|
+
|
|
1397
|
+
for x in 0...identifier_matches.length
|
|
1398
|
+
|
|
1399
|
+
current_identifer_match = identifier_matches[x]
|
|
1400
|
+
|
|
1401
|
+
replacement_string_array = replacement_strings[x]
|
|
1402
|
+
|
|
1403
|
+
for y in 0...current_identifer_match.length
|
|
1404
|
+
|
|
1405
|
+
urls = current_identifer_match[y]
|
|
1406
|
+
|
|
1407
|
+
interim_replacement = replacement_string_array[y]
|
|
1408
|
+
|
|
1409
|
+
replacement_urls = modify_urls(urls)
|
|
1410
|
+
|
|
1411
|
+
modified_input_string = modified_input_string.sub(interim_replacement,replacement_urls)
|
|
1412
|
+
|
|
1413
|
+
|
|
1414
|
+
end
|
|
1415
|
+
|
|
1416
|
+
|
|
1417
|
+
end
|
|
1418
|
+
|
|
1419
|
+
file_id = open(temporary_file, 'w')
|
|
1420
|
+
|
|
1421
|
+
file_id.write(modified_input_string)
|
|
1422
|
+
|
|
1423
|
+
file_id.close()
|
|
1424
|
+
|
|
1425
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1426
|
+
|
|
1427
|
+
return line_by_line_contents, temporary_file
|
|
1428
|
+
|
|
1429
|
+
end
|
|
1430
|
+
|
|
1431
|
+
def replace_descriptive_urls(input_file_contents,temporary_file)
|
|
1432
|
+
|
|
1433
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1434
|
+
|
|
1435
|
+
locations = []
|
|
1436
|
+
|
|
1437
|
+
index = input_string.index(pattern)
|
|
1438
|
+
|
|
1439
|
+
while index != nil
|
|
1440
|
+
|
|
1441
|
+
locations << index
|
|
1442
|
+
|
|
1443
|
+
index = input_string.index(pattern,index+1)
|
|
1444
|
+
|
|
1445
|
+
|
|
1446
|
+
end
|
|
1447
|
+
|
|
1448
|
+
return locations
|
|
1449
|
+
|
|
1450
|
+
|
|
1451
|
+
end
|
|
1452
|
+
|
|
1453
|
+
def process_urls(input_string)
|
|
1454
|
+
|
|
1455
|
+
core_string = input_string[2...-1]
|
|
1456
|
+
|
|
1457
|
+
split_string = core_string.split("=>")
|
|
1458
|
+
|
|
1459
|
+
return "\\href{#{split_string[1].strip}}{#{split_string[0].strip}}"
|
|
1460
|
+
|
|
1461
|
+
end
|
|
1462
|
+
|
|
1463
|
+
input_file_as_string = input_file_contents.join
|
|
1464
|
+
|
|
1465
|
+
modified_input_string = input_file_as_string.dup
|
|
1466
|
+
|
|
1467
|
+
descriptive_url_locations = find_all_matching_indices(input_file_as_string,"*[")
|
|
1468
|
+
|
|
1469
|
+
replacement_string = "@@descript[]"
|
|
1470
|
+
|
|
1471
|
+
replacement_urls = []
|
|
1472
|
+
|
|
1473
|
+
replacement_strings = []
|
|
1474
|
+
|
|
1475
|
+
for x in 0...descriptive_url_locations.length
|
|
1476
|
+
|
|
1477
|
+
current_location = descriptive_url_locations[x]
|
|
1478
|
+
|
|
1479
|
+
extract_string = input_file_as_string[current_location..-1]
|
|
1480
|
+
|
|
1481
|
+
end_finder = extract_string.index("]")
|
|
1482
|
+
|
|
1483
|
+
descriptive_url = extract_string[0..end_finder]
|
|
1484
|
+
|
|
1485
|
+
replacement_url = process_urls(descriptive_url)
|
|
1486
|
+
|
|
1487
|
+
replacement_urls << replacement_url
|
|
1488
|
+
|
|
1489
|
+
current_replacement_string = replacement_string.sub("]","#{x+1}]")
|
|
1490
|
+
|
|
1491
|
+
replacement_strings << current_replacement_string
|
|
1492
|
+
|
|
1493
|
+
modified_input_string = modified_input_string.sub(descriptive_url,current_replacement_string)
|
|
1494
|
+
|
|
1495
|
+
end
|
|
1496
|
+
|
|
1497
|
+
to_be_replaced = [replacement_strings,replacement_urls]
|
|
1498
|
+
|
|
1499
|
+
file_id = open(temporary_file, 'w')
|
|
1500
|
+
|
|
1501
|
+
file_id.write(modified_input_string)
|
|
1502
|
+
|
|
1503
|
+
file_id.close()
|
|
1504
|
+
|
|
1505
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1506
|
+
|
|
1507
|
+
return line_by_line_contents, temporary_file, to_be_replaced
|
|
1508
|
+
|
|
1509
|
+
end
|
|
1510
|
+
|
|
1511
|
+
def resolve_descriptive_urls(input_file_contents,temporary_file,replacement_array)
|
|
1512
|
+
|
|
1513
|
+
input_file_as_string = input_file_contents.join
|
|
1514
|
+
|
|
1515
|
+
modified_input_string = input_file_as_string.dup
|
|
1516
|
+
|
|
1517
|
+
interim_strings = replacement_array[0]
|
|
1518
|
+
|
|
1519
|
+
descriptive_urls = replacement_array[1]
|
|
1520
|
+
|
|
1521
|
+
for x in 0...interim_strings.length
|
|
1522
|
+
|
|
1523
|
+
current_interim_string = interim_strings[x]
|
|
1524
|
+
|
|
1525
|
+
current_descriptive_url = descriptive_urls[x]
|
|
1526
|
+
|
|
1527
|
+
modified_input_string = modified_input_string.sub(current_interim_string,current_descriptive_url)
|
|
1528
|
+
|
|
1529
|
+
end
|
|
1530
|
+
|
|
1531
|
+
file_id = open(temporary_file, 'w')
|
|
1532
|
+
|
|
1533
|
+
file_id.write(modified_input_string)
|
|
1534
|
+
|
|
1535
|
+
file_id.close()
|
|
1536
|
+
|
|
1537
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1538
|
+
|
|
1539
|
+
return line_by_line_contents, temporary_file
|
|
1540
|
+
|
|
1541
|
+
end
|
|
1542
|
+
|
|
1543
|
+
#The following methods implements some features of Smarty Pants
|
|
1544
|
+
|
|
1545
|
+
#http://daringfireball.net/projects/smartypants/
|
|
1546
|
+
|
|
1547
|
+
|
|
1548
|
+
def resolve_double_quotes(input_file_contents,temporary_file)
|
|
1549
|
+
|
|
1550
|
+
#This feature implements the double quotes features in smarty pants
|
|
1551
|
+
|
|
1552
|
+
def find_all_matching_indices(input_string,pattern)
|
|
1553
|
+
|
|
1554
|
+
locations = []
|
|
1555
|
+
|
|
1556
|
+
index = input_string.index(pattern)
|
|
1557
|
+
|
|
1558
|
+
while index != nil
|
|
1559
|
+
|
|
1560
|
+
locations << index
|
|
1561
|
+
|
|
1562
|
+
index = input_string.index(pattern,index+1)
|
|
1563
|
+
|
|
1564
|
+
|
|
1565
|
+
end
|
|
1566
|
+
|
|
1567
|
+
return locations
|
|
1568
|
+
|
|
1569
|
+
|
|
1570
|
+
end
|
|
1571
|
+
|
|
1572
|
+
input_file_as_string = input_file_contents.join
|
|
1573
|
+
|
|
1574
|
+
modified_input_string = input_file_as_string.dup
|
|
1575
|
+
|
|
1576
|
+
opening_quotes_locations = find_all_matching_indices(input_file_as_string,"\"")
|
|
1577
|
+
|
|
1578
|
+
if opening_quotes_locations.length.modulo(2) == 0
|
|
1579
|
+
|
|
1580
|
+
for x in 0...(opening_quotes_locations.length)/2
|
|
1581
|
+
|
|
1582
|
+
modified_input_string = modified_input_string.sub("\"","``")
|
|
1583
|
+
|
|
1584
|
+
modified_input_string = modified_input_string.sub("\"","''")
|
|
1585
|
+
|
|
1586
|
+
end
|
|
1587
|
+
|
|
1588
|
+
end
|
|
1589
|
+
|
|
1590
|
+
file_id = open(temporary_file, 'w')
|
|
1591
|
+
|
|
1592
|
+
file_id.write(modified_input_string)
|
|
1593
|
+
|
|
1594
|
+
file_id.close()
|
|
1595
|
+
|
|
1596
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1597
|
+
|
|
1598
|
+
return line_by_line_contents, temporary_file
|
|
1599
|
+
|
|
1600
|
+
end
|
|
1601
|
+
|
|
1602
|
+
def convert_to_latex_commands(input_file_contents,temporary_file)
|
|
1603
|
+
|
|
1604
|
+
#This method is designed to be more general than just the features available in smarty pants
|
|
1605
|
+
|
|
1606
|
+
#This method currently implements ellipses
|
|
1607
|
+
|
|
1608
|
+
vanilla_commands = ["...."]
|
|
1609
|
+
|
|
1610
|
+
latex_commands = {"...." => "\\ldots"}
|
|
1611
|
+
|
|
1612
|
+
input_file_as_string = input_file_contents.join
|
|
1613
|
+
|
|
1614
|
+
modified_input_string = input_file_as_string.dup
|
|
1615
|
+
|
|
1616
|
+
vanilla_commands.each do |command|
|
|
1617
|
+
|
|
1618
|
+
modified_input_string = modified_input_string.gsub(command,latex_commands[command])
|
|
1619
|
+
|
|
1620
|
+
end
|
|
1621
|
+
|
|
1622
|
+
file_id = open(temporary_file, 'w')
|
|
1623
|
+
|
|
1624
|
+
file_id.write(modified_input_string)
|
|
1625
|
+
|
|
1626
|
+
file_id.close()
|
|
1627
|
+
|
|
1628
|
+
line_by_line_contents = read_file_line_by_line(temporary_file)
|
|
1629
|
+
|
|
1630
|
+
return line_by_line_contents, temporary_file
|
|
1631
|
+
|
|
1632
|
+
end
|
|
1633
|
+
|
|
1634
|
+
#The following methods are for writing the output LaTex code.
|
|
1635
|
+
|
|
1636
|
+
def write_latex_file(input_file_contents,temporary_file,input_val_file)
|
|
1637
|
+
|
|
1638
|
+
input_file_as_string = input_file_contents.join
|
|
1639
|
+
|
|
1640
|
+
File.delete(temporary_file)
|
|
1641
|
+
|
|
1642
|
+
output_latex_file_path = input_val_file.split(".tex")
|
|
1643
|
+
|
|
1644
|
+
output_latex_file_path = output_latex_file_path[0] + ".tex"
|
|
1645
|
+
|
|
1646
|
+
file_id = open(output_latex_file_path, 'w')
|
|
1647
|
+
|
|
1648
|
+
file_id.write(input_file_as_string)
|
|
1649
|
+
|
|
1650
|
+
file_id.close()
|
|
1651
|
+
|
|
1652
|
+
end
|
|
1653
|
+
|
|
1654
|
+
#The following method compiles the output .tex file into PDF and then overwrites the .tex file with the
|
|
1655
|
+
#original content
|
|
1656
|
+
|
|
1657
|
+
def compile_to_pdf(input_file_path,raw_file_as_string)
|
|
1658
|
+
|
|
1659
|
+
#The method first compiles the .tex file into PDF using PDFLatex
|
|
1660
|
+
|
|
1661
|
+
latex_compiler_output = `pdflatex -interaction=nonstopmode #{input_file_path}`
|
|
1662
|
+
|
|
1663
|
+
file_id = open(input_file_path,'w')
|
|
1664
|
+
|
|
1665
|
+
file_id.write(raw_file_as_string)
|
|
1666
|
+
|
|
1667
|
+
file_id.close()
|
|
1668
|
+
|
|
1669
|
+
return latex_compiler_output
|
|
1670
|
+
|
|
1671
|
+
end
|
|
1672
|
+
|
|
1673
|
+
|
|
1674
|
+
#The following methods are used only for testing and debugging purposes
|
|
1675
|
+
|
|
1676
|
+
|
|
1677
|
+
def print_list(input_list)
|
|
1678
|
+
|
|
1679
|
+
#This method will print each line of the inputted list. This method is usually used to test and see whether other parts of
|
|
1680
|
+
#the compiler are working correctly
|
|
1681
|
+
|
|
1682
|
+
length_of_list = input_list.length
|
|
1683
|
+
|
|
1684
|
+
for x in 0...length_of_list
|
|
1685
|
+
|
|
1686
|
+
current_item = input_list[x]
|
|
1687
|
+
|
|
1688
|
+
print(current_item)
|
|
1689
|
+
|
|
1690
|
+
end
|
|
1691
|
+
|
|
1692
|
+
end
|
|
1693
|
+
|
|
1694
|
+
|
|
1695
|
+
line_by_line_file = read_file_line_by_line(input_val_file)
|
|
1696
|
+
|
|
1697
|
+
raw_file = line_by_line_file.dup
|
|
1698
|
+
|
|
1699
|
+
line_by_line_file, temp_file, fenced_code_blocks, preferred_directory = replace_fenced_code_block(line_by_line_file,input_val_file)
|
|
1700
|
+
|
|
1701
|
+
line_by_line_file, temp_file, inline_code_blocks = replace_inline_fenced_code(line_by_line_file,temp_file)
|
|
1702
|
+
|
|
1703
|
+
line_by_line_file, temp_file = resolve_comments(line_by_line_file,temp_file)
|
|
1704
|
+
|
|
1705
|
+
line_by_line_file, temp_file = resolve_constants(line_by_line_file, temp_file)
|
|
1706
|
+
|
|
1707
|
+
line_by_line_file, temp_file = resolve_formatted_text_blocks(line_by_line_file,temp_file)
|
|
1708
|
+
|
|
1709
|
+
line_by_line_file, temp_file = resolve_formulas(line_by_line_file,temp_file)
|
|
1710
|
+
|
|
1711
|
+
line_by_line_file, temp_file = resolve_inline_calculations(line_by_line_file,temp_file)
|
|
1712
|
+
|
|
1713
|
+
line_by_line_file, temp_file = resolve_inline_formatting(line_by_line_file,temp_file)
|
|
1714
|
+
|
|
1715
|
+
line_by_line_file, temp_file = resolve_tex_packs(line_by_line_file,temp_file,preferred_directory)
|
|
1716
|
+
|
|
1717
|
+
line_by_line_file, temp_file, replacement_array = replace_descriptive_urls(line_by_line_file,temp_file)
|
|
1718
|
+
|
|
1719
|
+
line_by_line_file, temp_file = resolve_bare_urls(line_by_line_file,temp_file)
|
|
1720
|
+
|
|
1721
|
+
line_by_line_file, temp_file = resolve_descriptive_urls(line_by_line_file,temp_file,replacement_array)
|
|
1722
|
+
|
|
1723
|
+
line_by_line_file, temp_file = resolve_double_quotes(line_by_line_file,temp_file)
|
|
1724
|
+
|
|
1725
|
+
line_by_line_file, temp_file = convert_to_latex_commands(line_by_line_file,temp_file)
|
|
1726
|
+
|
|
1727
|
+
line_by_line_file, temp_file = resolve_fenced_code_blocks(line_by_line_file,temp_file,fenced_code_blocks)
|
|
1728
|
+
|
|
1729
|
+
line_by_line_file, temp_file = resolve_inline_fenced_code(line_by_line_file,temp_file,inline_code_blocks)
|
|
1730
|
+
|
|
1731
|
+
write_latex_file(line_by_line_file,temp_file,input_val_file)
|
|
1732
|
+
|
|
1733
|
+
pdflatex_output = compile_to_pdf(input_val_file,raw_file.join)
|
|
1734
|
+
|
|
1735
|
+
return pdflatex_output
|
|
1736
|
+
|
|
1737
|
+
end
|
|
1738
|
+
|
|
1739
|
+
#This script creates a windows executable using the Ocra gem and a mac
|
|
1740
|
+
#version using shabang syntax.
|
|
1741
|
+
|
|
1742
|
+
def create_executable(input_file)
|
|
1743
|
+
|
|
1744
|
+
def read_file_line_by_line(input_path)
|
|
1745
|
+
|
|
1746
|
+
file_id = open(input_path)
|
|
1747
|
+
|
|
1748
|
+
file_line_by_line = file_id.readlines()
|
|
1749
|
+
|
|
1750
|
+
file_id.close
|
|
1751
|
+
|
|
1752
|
+
return file_line_by_line
|
|
1753
|
+
|
|
1754
|
+
end
|
|
1755
|
+
|
|
1756
|
+
windows_output = `ocra --add-all-core #{input_file}`
|
|
1757
|
+
|
|
1758
|
+
mac_file_contents = ["#!/usr/bin/env ruby\n\n"] + read_file_line_by_line(input_file)
|
|
1759
|
+
|
|
1760
|
+
mac_file_path = input_file.sub(".rb","")
|
|
1761
|
+
|
|
1762
|
+
file_id = open(mac_file_path,"w")
|
|
1763
|
+
|
|
1764
|
+
file_id.write(mac_file_contents.join)
|
|
1765
|
+
|
|
1766
|
+
file_id.close
|
|
1767
|
+
|
|
1768
|
+
end
|
|
1769
|
+
|
|
1770
|
+
def create_mac_executable(input_file)
|
|
1771
|
+
|
|
1772
|
+
def read_file_line_by_line(input_path)
|
|
1773
|
+
|
|
1774
|
+
file_id = open(input_path)
|
|
1775
|
+
|
|
1776
|
+
file_line_by_line = file_id.readlines()
|
|
1777
|
+
|
|
1778
|
+
file_id.close
|
|
1779
|
+
|
|
1780
|
+
return file_line_by_line
|
|
1781
|
+
|
|
1782
|
+
end
|
|
1783
|
+
|
|
1784
|
+
mac_file_contents = ["#!/usr/bin/env ruby\n\n"] + read_file_line_by_line(input_file)
|
|
1785
|
+
|
|
1786
|
+
mac_file_path = input_file.sub(".rb", "")
|
|
1787
|
+
|
|
1788
|
+
file_id = open(mac_file_path, "w")
|
|
1789
|
+
|
|
1790
|
+
file_id.write(mac_file_contents.join)
|
|
1791
|
+
|
|
1792
|
+
file_id.close
|
|
1793
|
+
|
|
1794
|
+
end
|
|
1795
|
+
|
|
1796
|
+
options = {}
|
|
1797
|
+
|
|
1798
|
+
OptionParser.new do |opts|
|
|
1799
|
+
opts.banner = "Usage: vanilla [options] TEX_FILE"
|
|
1800
|
+
|
|
1801
|
+
opts.on("-c", "--compile FILE", "Compile to PDF") do |file|
|
|
1802
|
+
current_directory = Dir.pwd
|
|
1803
|
+
file_path = current_directory + "/" + file
|
|
1804
|
+
latex_compiler_output = start_compile(file_path)
|
|
1805
|
+
puts latex_compiler_output
|
|
1806
|
+
|
|
1807
|
+
end
|
|
1808
|
+
|
|
1809
|
+
opts.on("-b", "--build FILE", "Builds Itself") do |file|
|
|
1810
|
+
|
|
1811
|
+
file_path = Dir.pwd + "/src/vanilla.rb"
|
|
1812
|
+
|
|
1813
|
+
create_mac_executable(file_path)
|
|
1814
|
+
|
|
1815
|
+
FileUtils.mv("#{file_path[0...-3]}", "#{Dir.pwd}/bin/vanilla")
|
|
1816
|
+
|
|
1817
|
+
puts "Build Successful!"
|
|
1818
|
+
|
|
1819
|
+
end
|
|
1820
|
+
|
|
1821
|
+
end.parse!
|