vfl 0.0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in vfl.gemspec
4
+ gemspec
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!