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