erbtex 0.4.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.bundle/config +1 -1
- data/.envrc +2 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +41 -0
- data/CHANGELOG.md +55 -0
- data/CHANGELOG.org +37 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +128 -40
- data/README.md +161 -0
- data/README.org +45 -12
- data/Rakefile +23 -2
- data/bin/erbtex +23 -2
- data/erbtex.gemspec +13 -14
- data/examples/TrigTable2.tex +2 -2
- data/examples/dms.rb +35 -50
- data/examples/int_ext.rb +13 -0
- data/examples/testbind.rb +2 -1
- data/lib/erbtex/command_line.rb +22 -41
- data/lib/erbtex/file_names.rb +4 -1
- data/lib/erbtex/runner.rb +61 -29
- data/lib/erbtex/version.rb +3 -1
- data/lib/erbtex.rb +3 -1
- data/spec/erbtex/command_line_spec.rb +393 -0
- data/spec/{lib → erbtex}/file_names_spec.rb +11 -20
- data/spec/erbtex/runner_spec.rb +307 -0
- data/spec/spec_helper.rb +2 -1
- metadata +21 -16
- data/spec/lib/command_line_spec.rb +0 -150
data/bin/erbtex
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
#! /usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
2
4
|
|
|
3
5
|
require 'erbtex'
|
|
4
6
|
|
|
7
|
+
# Name space module for erbtex's ruby pre-processing of TeX and LaTeX files by
|
|
8
|
+
# ruby.
|
|
5
9
|
module ErbTeX
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
if ARGV.empty?
|
|
11
|
+
warn 'usage: erbtex [LaTex_filename]'
|
|
12
|
+
exit(1)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
begin
|
|
16
|
+
cl = CommandLine.new(ARGV)
|
|
17
|
+
status = ErbTeX.run(cl)
|
|
18
|
+
rescue OutputExists => e
|
|
19
|
+
warn "Warning: #{e}"
|
|
20
|
+
status = 1
|
|
21
|
+
rescue SystemCallError, ArgumentError, NoInputFile => e
|
|
22
|
+
warn "Error: #{e}"
|
|
23
|
+
status = 1
|
|
24
|
+
rescue ScriptError => e
|
|
25
|
+
warn "Erubis pre-processing failed: #{e}"
|
|
26
|
+
status = 1
|
|
27
|
+
end
|
|
28
|
+
exit status
|
|
8
29
|
end
|
data/erbtex.gemspec
CHANGED
|
@@ -1,33 +1,32 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require './lib/erbtex/version'
|
|
4
4
|
|
|
5
5
|
Gem::Specification.new do |gem|
|
|
6
|
-
gem.name =
|
|
6
|
+
gem.name = 'erbtex'
|
|
7
|
+
gem.license = 'MIT'
|
|
7
8
|
gem.version = ErbTeX::VERSION
|
|
8
9
|
gem.platform = Gem::Platform::RUBY
|
|
9
|
-
gem.date = %q{2012-05-13}
|
|
10
10
|
gem.homepage = 'https://github.com/ddoherty03/erbtex'
|
|
11
11
|
gem.authors = ['Daniel E. Doherty']
|
|
12
|
-
gem.email =
|
|
13
|
-
gem.summary =
|
|
14
|
-
gem.description =
|
|
12
|
+
gem.email = 'ded@ddoherty.net'
|
|
13
|
+
gem.summary = 'Preprocesses TeX and LaTeX files with erubis for ruby.'
|
|
14
|
+
gem.description = 'erbtex will act just like pdflatex except that it will
|
|
15
15
|
process ruby fragments between {: and :} markers,
|
|
16
16
|
greatly expanding the ability to generate
|
|
17
|
-
automated TeX and LaTeX documents.
|
|
18
|
-
gem.files
|
|
17
|
+
automated TeX and LaTeX documents.'
|
|
18
|
+
gem.files = %x(git ls-files).split("\n")
|
|
19
19
|
gem.files.delete_if { |f| f =~ /\.(log|etc|aux|etx|pdf|gem|tmp)$/ }
|
|
20
|
-
gem.
|
|
21
|
-
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
20
|
+
gem.executables = %x(git ls-files -- bin/*).split("\n").map { |f| File.basename(f) }
|
|
22
21
|
gem.require_paths = ['lib']
|
|
23
22
|
|
|
24
23
|
gem.add_dependency 'erubis'
|
|
25
24
|
gem.add_dependency 'fat_core'
|
|
26
|
-
gem.add_development_dependency 'rake'
|
|
27
25
|
gem.add_development_dependency 'bundler'
|
|
28
|
-
gem.add_development_dependency 'rspec'
|
|
29
26
|
gem.add_development_dependency 'minitest'
|
|
30
27
|
gem.add_development_dependency 'pry'
|
|
31
|
-
gem.add_development_dependency 'pry-doc'
|
|
32
28
|
gem.add_development_dependency 'pry-byebug'
|
|
29
|
+
gem.add_development_dependency 'pry-doc'
|
|
30
|
+
gem.add_development_dependency 'rake'
|
|
31
|
+
gem.add_development_dependency 'rspec'
|
|
33
32
|
end
|
data/examples/TrigTable2.tex
CHANGED
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
## increments of step.
|
|
56
56
|
|
|
57
57
|
require 'bigdecimal'
|
|
58
|
-
|
|
58
|
+
require_relative 'dms'
|
|
59
59
|
DMS.precision = 0
|
|
60
60
|
step = DMS.new(0, 0, 30)
|
|
61
61
|
one = BigDecimal("1.0")
|
|
@@ -130,4 +130,4 @@
|
|
|
130
130
|
\end{longtable}
|
|
131
131
|
\end{document}
|
|
132
132
|
|
|
133
|
-
% Take /that/ Charles Babbage!
|
|
133
|
+
% Take /that/ Charles Babbage!
|
data/examples/dms.rb
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
#! /usr/bin/ruby
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
require_relative "int_ext"
|
|
2
6
|
|
|
3
7
|
# A class for maipulating angles expressed as degreed, minutes,
|
|
4
8
|
# and seconds.
|
|
5
9
|
class DMS
|
|
6
10
|
include Comparable
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@@precision = 4
|
|
12
|
+
attr_accessor :degrees, :minutes, :seconds, :precision
|
|
11
13
|
|
|
12
|
-
def initialize(deg, min = 0, sec = 0.0)
|
|
14
|
+
def initialize(deg, min = 0, sec = 0.0, precision: 4)
|
|
13
15
|
@degrees = deg.to_i
|
|
14
16
|
@minutes = min.to_i
|
|
15
17
|
@seconds = sec.to_f
|
|
18
|
+
@precision = precision
|
|
16
19
|
normalize
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
def self.from_radians(rad)
|
|
20
|
-
if rad
|
|
23
|
+
if rad.negative?
|
|
21
24
|
rad = -rad
|
|
22
|
-
|
|
25
|
+
-1
|
|
23
26
|
else
|
|
24
|
-
|
|
27
|
+
1
|
|
25
28
|
end
|
|
26
29
|
deg = rad * (360.0 / (2.0 * Math::PI))
|
|
27
30
|
degrees = deg.floor
|
|
@@ -31,16 +34,12 @@ class DMS
|
|
|
31
34
|
DMS.new(degrees, minutes, seconds)
|
|
32
35
|
end
|
|
33
36
|
|
|
34
|
-
def self.precision=(p)
|
|
35
|
-
@@precision = p
|
|
36
|
-
end
|
|
37
|
-
|
|
38
37
|
def to_s
|
|
39
|
-
"#{
|
|
38
|
+
format("#{degrees}* #{minutes}' %0.*f''", precision, seconds)
|
|
40
39
|
end
|
|
41
40
|
|
|
42
41
|
def to_f
|
|
43
|
-
|
|
42
|
+
degrees.to_f + (minutes / 60.0) + (seconds / 3600.0)
|
|
44
43
|
end
|
|
45
44
|
|
|
46
45
|
def to_radians
|
|
@@ -50,13 +49,11 @@ class DMS
|
|
|
50
49
|
# If degrees are at well-known values, eppress as radians
|
|
51
50
|
# symbolically, using TeX notation
|
|
52
51
|
def to_radians_tex
|
|
53
|
-
unless @seconds == 0.0
|
|
54
|
-
return '$%0.*f$' % [@@precision, to_radians]
|
|
55
|
-
end
|
|
52
|
+
return format('$%0.*f$', precision, to_radians) unless (@seconds == 0.0) && @minutes.zero?
|
|
56
53
|
|
|
57
54
|
# This gets deg to 0 <= x <= 360, even for negative
|
|
58
55
|
# values of @degrees
|
|
59
|
-
deg =
|
|
56
|
+
deg = degrees.divmod(360)[1]
|
|
60
57
|
case deg
|
|
61
58
|
when 0
|
|
62
59
|
'$0$'
|
|
@@ -85,20 +82,20 @@ class DMS
|
|
|
85
82
|
when 360
|
|
86
83
|
'$2\\pi$'
|
|
87
84
|
else
|
|
88
|
-
'$%0.*f$'
|
|
85
|
+
format('$%0.*f$', precision, to_radians)
|
|
89
86
|
end
|
|
90
87
|
end
|
|
91
88
|
|
|
92
89
|
def to_tex
|
|
93
|
-
"$%02d^\\circ~%02d'~%02.*f''$"
|
|
90
|
+
format("$%02d^\\circ~%02d'~%02.*f''$", degrees, minutes, precision, seconds) # "
|
|
94
91
|
end
|
|
95
92
|
|
|
96
93
|
def -@
|
|
97
|
-
DMS.new(
|
|
94
|
+
DMS.new(-degrees, minutes, seconds)
|
|
98
95
|
end
|
|
99
96
|
|
|
100
97
|
def +@
|
|
101
|
-
DMS.new(
|
|
98
|
+
DMS.new(degrees, minutes, seconds)
|
|
102
99
|
end
|
|
103
100
|
|
|
104
101
|
def <=>(other)
|
|
@@ -106,23 +103,23 @@ class DMS
|
|
|
106
103
|
end
|
|
107
104
|
|
|
108
105
|
def +(other)
|
|
109
|
-
seconds
|
|
110
|
-
minutes
|
|
111
|
-
degrees
|
|
106
|
+
seconds += other.seconds
|
|
107
|
+
minutes += other.minutes
|
|
108
|
+
degrees += other.degrees
|
|
112
109
|
DMS.new(degrees, minutes, seconds)
|
|
113
110
|
end
|
|
114
111
|
|
|
115
112
|
def -(other)
|
|
116
|
-
|
|
117
|
-
DMS.new(
|
|
113
|
+
diff = (self + -other)
|
|
114
|
+
DMS.new(diff.degrees, diff.minutes, diff.seconds)
|
|
118
115
|
end
|
|
119
116
|
|
|
120
|
-
def *(
|
|
121
|
-
DMS.new(
|
|
117
|
+
def *(other)
|
|
118
|
+
DMS.new(other * degrees, other * minutes, other * seconds)
|
|
122
119
|
end
|
|
123
120
|
|
|
124
|
-
def /(
|
|
125
|
-
DMS.new(@degrees /
|
|
121
|
+
def /(other)
|
|
122
|
+
DMS.new(@degrees / other, @minutes / other, @seconds / other)
|
|
126
123
|
end
|
|
127
124
|
|
|
128
125
|
def sin
|
|
@@ -153,28 +150,16 @@ class DMS
|
|
|
153
150
|
# After normalization, only degrees can be negative,
|
|
154
151
|
# which will represent a negative quantity
|
|
155
152
|
def normalize
|
|
156
|
-
q, r =
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
q, r =
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
end
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
class Integer
|
|
166
|
-
alias times *
|
|
167
|
-
def *(other)
|
|
168
|
-
case other
|
|
169
|
-
when DMS
|
|
170
|
-
other * self
|
|
171
|
-
else
|
|
172
|
-
times(other)
|
|
173
|
-
end
|
|
153
|
+
q, r = seconds.divmod(60.0)
|
|
154
|
+
self.seconds = r
|
|
155
|
+
self.minutes += q
|
|
156
|
+
q, r = minutes.divmod(60)
|
|
157
|
+
self.minutes = r
|
|
158
|
+
self.degrees += q
|
|
174
159
|
end
|
|
175
160
|
end
|
|
176
161
|
|
|
177
|
-
if __FILE__ == $
|
|
162
|
+
if __FILE__ == $PROGRAM_NAME
|
|
178
163
|
print "Fifty seconds in radians: #{DMS.new(0, 0, 50).to_radians}\n"
|
|
179
164
|
print "One minute in radians: #{DMS.new(0, 1, 0).to_radians}\n"
|
|
180
165
|
print "Fifty seconds in degrees: #{DMS.new(0, 0, 50).to_f}\n"
|
data/examples/int_ext.rb
ADDED
data/examples/testbind.rb
CHANGED
data/lib/erbtex/command_line.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Name space for erbtex command.
|
|
4
4
|
module ErbTeX
|
|
@@ -6,61 +6,46 @@ module ErbTeX
|
|
|
6
6
|
|
|
7
7
|
# Class to record and manipulate the command line typed by the user.
|
|
8
8
|
class CommandLine
|
|
9
|
-
attr_reader :erbtex_name, :tex_program, :tex_args, :tex_commands
|
|
10
|
-
attr_reader :
|
|
9
|
+
attr_reader :erbtex_name, :tex_program, :tex_args, :tex_commands, :input_file, :print_version, :print_help
|
|
10
|
+
attr_reader :preprocess_only, :no_clobber
|
|
11
11
|
|
|
12
12
|
def initialize(argv)
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
# were quoted by the user on the command-line and need no special
|
|
16
|
-
# treatment here. For example, '~/junk' on the commandline will show up
|
|
17
|
-
# here as '/home/ded/junk'. If we see '~/junk', that means the user has
|
|
18
|
-
# quoted the ~ on the command line with something like '\~junk', so we
|
|
19
|
-
# should assume that the user wants to keep it that way. Likewise, an
|
|
20
|
-
# arg with spaces in it will have been quoted by the user to be seen as
|
|
21
|
-
# a single argument. When we output these for use by the shell in the
|
|
22
|
-
# system command, we should apply shellquote to everything so that the
|
|
23
|
-
# receiving shell sees the args in the same way.
|
|
13
|
+
# Arguments have already been split by the shell. Preserve each string
|
|
14
|
+
# unchanged and pass it directly to the TeX process.
|
|
24
15
|
|
|
25
16
|
@erbtex_name = File.basename($PROGRAM_NAME)
|
|
26
17
|
|
|
27
18
|
# Find the tex_commands
|
|
28
19
|
@tex_commands = []
|
|
29
|
-
if argv.any? { |a| a
|
|
20
|
+
if argv.any? { |a| a.start_with?('\\') }
|
|
30
21
|
# All args after first starting with '\' should be interpreted as TeX
|
|
31
22
|
# commands, even if they don't start with '\'
|
|
32
23
|
@tex_commands = argv.drop_while { |a| a !~ /\A\\/ }
|
|
33
24
|
first_tex_command_k = argv.size - @tex_commands.size
|
|
34
|
-
argv = argv
|
|
25
|
+
argv = argv.take(first_tex_command_k)
|
|
35
26
|
end
|
|
36
27
|
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
if
|
|
40
|
-
|
|
41
|
-
argv.reject! { |a| a =~ /\A--invoke=(\w+)/ }
|
|
28
|
+
# Keep the complete executable name, including paths and punctuation.
|
|
29
|
+
invoke_options = argv.select { |argument| argument.start_with?('--invoke=') }
|
|
30
|
+
if invoke_options.include?('--invoke=')
|
|
31
|
+
raise ArgumentError, '--invoke requires a nonempty executable name'
|
|
42
32
|
end
|
|
43
33
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if argv.any? { |a| a =~ /\A--version/ }
|
|
47
|
-
@print_version = true
|
|
48
|
-
argv.reject! { |a| a =~ /\A--version/ }
|
|
49
|
-
end
|
|
34
|
+
@tex_program = invoke_options.first&.delete_prefix('--invoke=') || 'pdflatex'
|
|
35
|
+
argv = argv.reject { |argument| argument.start_with?('--invoke=') }
|
|
50
36
|
|
|
51
|
-
|
|
52
|
-
@print_help =
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
37
|
+
@print_version = argv.include?('--version')
|
|
38
|
+
@print_help = argv.include?('--help')
|
|
39
|
+
@preprocess_only = argv.include?('--preprocess-only')
|
|
40
|
+
@no_clobber = argv.include?('--no-clobber')
|
|
41
|
+
argv = argv.reject { |argument| argument == '--version' || argument == '--help' }
|
|
42
|
+
argv = argv.reject { |argument| argument == '--preprocess-only' }
|
|
43
|
+
argv = argv.reject { |argument| argument == '--no-clobber' }
|
|
57
44
|
|
|
58
45
|
# The last argument, assuming it does not start with a '-' or '&', is
|
|
59
46
|
# assumed to be the name of the input_file.
|
|
60
47
|
@input_file = nil
|
|
61
|
-
if !argv.empty? && argv[-1] !~ /\A[-&]/
|
|
62
|
-
@input_file = ErbTeX.expand_input_file(argv.pop)
|
|
63
|
-
end
|
|
48
|
+
@input_file = ErbTeX.expand_input_file(argv.pop) if !argv.empty? && argv[-1] !~ /\A[-&]/
|
|
64
49
|
|
|
65
50
|
# What remains in argv should be the tex program's '-options', which
|
|
66
51
|
# should be passed through untouched. So, can form the full command line
|
|
@@ -69,11 +54,7 @@ module ErbTeX
|
|
|
69
54
|
end
|
|
70
55
|
|
|
71
56
|
def tex_command(tex_file = input_file)
|
|
72
|
-
|
|
73
|
-
"#{tex_args.shelljoin} " \
|
|
74
|
-
"#{tex_commands.shelljoin} " \
|
|
75
|
-
"#{tex_file}"
|
|
76
|
-
.strip.squeeze(' ')
|
|
57
|
+
[tex_program, *tex_args, tex_file, *tex_commands].compact
|
|
77
58
|
end
|
|
78
59
|
end
|
|
79
60
|
end
|
data/lib/erbtex/file_names.rb
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Name space module for ErbTeX.
|
|
1
4
|
module ErbTeX
|
|
2
5
|
# Given an arbitrary file name, parse it into its components in one go. It
|
|
3
6
|
# separates three parts of a filename: (1) the directory, if any, (2) the
|
|
@@ -5,7 +8,7 @@ module ErbTeX
|
|
|
5
8
|
# name rather than an extension, and (3) any extension, including a compound
|
|
6
9
|
# extension such as .tex.erb
|
|
7
10
|
def self.parse_file_name(path)
|
|
8
|
-
fn_re = %r{\A(?<dir>([
|
|
11
|
+
fn_re = %r{\A(?<dir>([^/]*/)*) (?<base>.?[^/.]*) (?<ext>\.[\w.]+)?}x
|
|
9
12
|
md = fn_re.match(path)
|
|
10
13
|
{ dir: md[:dir], base: md[:base], ext: md[:ext] }
|
|
11
14
|
end
|
data/lib/erbtex/runner.rb
CHANGED
|
@@ -1,17 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'tempfile'
|
|
2
4
|
require 'pathname'
|
|
3
5
|
require 'English'
|
|
4
6
|
|
|
5
7
|
# Name space module for erbtex program.
|
|
6
8
|
module ErbTeX
|
|
9
|
+
GENERATED_MARKER = '% Generated by erbtex. Changes may be overwritten.'
|
|
10
|
+
|
|
11
|
+
class OutputExists < StandardError; end
|
|
12
|
+
|
|
7
13
|
# Perform the erubis pre-processing and the TeX processing on the input
|
|
8
|
-
# file.
|
|
14
|
+
# file. Return an exit status; preprocessing errors propagate to the caller.
|
|
9
15
|
def self.run(cmd_line)
|
|
10
|
-
report_version
|
|
11
|
-
|
|
16
|
+
return report_version if cmd_line.print_version
|
|
17
|
+
|
|
18
|
+
if cmd_line.print_help
|
|
19
|
+
report_help
|
|
20
|
+
return 0
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
if cmd_line.preprocess_only && !cmd_line.input_file
|
|
24
|
+
raise NoInputFile, '--preprocess-only requires an input file'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
in_dir = parse_file_name(cmd_line.input_file)[:dir] if cmd_line.input_file
|
|
28
|
+
tex_file = erb_to_tex(cmd_line.input_file, in_dir, no_clobber: cmd_line.no_clobber) if cmd_line.input_file
|
|
29
|
+
return 0 if cmd_line.preprocess_only
|
|
12
30
|
|
|
13
|
-
in_dir = parse_file_name(cmd_line.input_file)[:dir]
|
|
14
|
-
tex_file = erb_to_tex(cmd_line.input_file, in_dir) if cmd_line.input_file
|
|
15
31
|
run_tex(cmd_line.tex_command(tex_file), in_dir)
|
|
16
32
|
end
|
|
17
33
|
|
|
@@ -19,13 +35,13 @@ module ErbTeX
|
|
|
19
35
|
puts "erbtex version: #{ErbTeX::VERSION}"
|
|
20
36
|
puts "Ruby version: #{RUBY_VERSION}"
|
|
21
37
|
begin
|
|
22
|
-
erubis_version =
|
|
38
|
+
erubis_version = %x(erubis -v)
|
|
23
39
|
rescue Errno::ENOENT
|
|
24
40
|
warn 'Warning: erubis does not appear to be installed!'
|
|
25
|
-
|
|
41
|
+
return 1
|
|
26
42
|
end
|
|
27
43
|
puts "erubis version: #{erubis_version}"
|
|
28
|
-
|
|
44
|
+
0
|
|
29
45
|
end
|
|
30
46
|
|
|
31
47
|
# Display the help for erbtex.
|
|
@@ -36,6 +52,9 @@ module ErbTeX
|
|
|
36
52
|
erbtex_options are:
|
|
37
53
|
--version - print the version of the erbtex gem, ruby and erubis
|
|
38
54
|
--help - print this help message
|
|
55
|
+
--no-clobber - refuse to overwrite any existing preprocessed file
|
|
56
|
+
--preprocess-only - generate the preprocessed file without invoking TeX
|
|
57
|
+
(requires an input file)
|
|
39
58
|
--invoke=<tex_prog> - after pre-processing, invoke <tex_prog> on the
|
|
40
59
|
resulting file, tex_prog is pdflatex by default
|
|
41
60
|
|
|
@@ -49,7 +68,6 @@ module ErbTeX
|
|
|
49
68
|
as an argument to the tex-prog.
|
|
50
69
|
|
|
51
70
|
HELP
|
|
52
|
-
true
|
|
53
71
|
end
|
|
54
72
|
|
|
55
73
|
# Run the TeX program on the erubis-processed output file, which is the
|
|
@@ -73,30 +91,33 @@ module ErbTeX
|
|
|
73
91
|
# Call cmd with the environment augmented by possibly expanded TEXINPUTS
|
|
74
92
|
# environment variable.
|
|
75
93
|
warn "TEXINPUTS set to: #{new_env['TEXINPUTS']}"
|
|
76
|
-
unless system(new_env, cmd)
|
|
77
|
-
warn "Call to '#{cmd}' failed."
|
|
78
|
-
|
|
94
|
+
unless system(new_env, [cmd.first, cmd.first], *cmd.drop(1))
|
|
95
|
+
warn "Call to '#{cmd.shelljoin}' failed."
|
|
96
|
+
return $CHILD_STATUS.exitstatus || 128 + $CHILD_STATUS.termsig
|
|
79
97
|
end
|
|
80
98
|
# Run a second time unless its latexmk
|
|
81
|
-
unless cmd
|
|
99
|
+
unless File.basename(cmd.first) == 'latexmk'
|
|
82
100
|
warn "TEXINPUTS set to: #{new_env['TEXINPUTS']}"
|
|
83
|
-
unless system(new_env, cmd)
|
|
84
|
-
warn "Call to '#{cmd}' failed."
|
|
85
|
-
|
|
101
|
+
unless system(new_env, [cmd.first, cmd.first], *cmd.drop(1))
|
|
102
|
+
warn "Call to '#{cmd.shelljoin}' failed."
|
|
103
|
+
return $CHILD_STATUS.exitstatus || 128 + $CHILD_STATUS.termsig
|
|
86
104
|
end
|
|
87
105
|
end
|
|
88
|
-
$CHILD_STATUS
|
|
106
|
+
$CHILD_STATUS.exitstatus
|
|
89
107
|
end
|
|
90
108
|
|
|
91
109
|
# Pre-process the input file with erubis, adding the in_dir to the front of
|
|
92
110
|
# the ruby load path if its not already in the load path so that requires in
|
|
93
111
|
# the input file can be found if they are in the in_dir. Return the name of
|
|
94
112
|
# the output file.
|
|
95
|
-
def self.erb_to_tex(in_file, in_dir = nil)
|
|
113
|
+
def self.erb_to_tex(in_file, in_dir = nil, no_clobber: false)
|
|
114
|
+
out_file = ErbTeX.out_file_name(in_file)
|
|
115
|
+
check_output_file(out_file, no_clobber: no_clobber)
|
|
116
|
+
|
|
96
117
|
warn '================================================================'
|
|
97
118
|
warn 'Erubis phase of processing ...'
|
|
98
119
|
# Add input to ruby LOAD_PATH, $:,if its not already there.
|
|
99
|
-
if File.exist?(in_dir)
|
|
120
|
+
if in_dir && File.exist?(in_dir)
|
|
100
121
|
in_dir = File.absolute_path(File.expand_path(in_dir))
|
|
101
122
|
unless $LOAD_PATH
|
|
102
123
|
.any? { |p| in_dir == File.absolute_path(File.expand_path(p)) }
|
|
@@ -114,20 +135,31 @@ module ErbTeX
|
|
|
114
135
|
|
|
115
136
|
pat = ENV['ERBTEX_PATTERN'] || '{: :}'
|
|
116
137
|
|
|
117
|
-
|
|
138
|
+
rendered = ::Erubis::Eruby.new(in_contents, pattern: pat, filename: in_file).result
|
|
118
139
|
warn " Erubis writing to #{out_file}..."
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
f.
|
|
140
|
+
# Keep the temporary file beside its destination so rename is atomic.
|
|
141
|
+
Tempfile.create([".#{File.basename(out_file)}-", '.tmp'], File.dirname(out_file)) do |f|
|
|
142
|
+
f.puts(GENERATED_MARKER)
|
|
143
|
+
f.write(rendered)
|
|
144
|
+
f.close
|
|
145
|
+
check_output_file(out_file, no_clobber: no_clobber)
|
|
146
|
+
File.rename(f.path, out_file)
|
|
122
147
|
end
|
|
123
148
|
warn 'done'
|
|
124
149
|
warn '================================================================'
|
|
125
150
|
out_file
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def self.check_output_file(out_file, no_clobber: false)
|
|
154
|
+
return unless File.exist?(out_file)
|
|
155
|
+
|
|
156
|
+
if no_clobber
|
|
157
|
+
raise OutputExists, "Refusing to overwrite #{out_file}: --no-clobber is set"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
first_line = File.open(out_file, &:gets)
|
|
161
|
+
return if first_line&.chomp == GENERATED_MARKER
|
|
162
|
+
|
|
163
|
+
raise OutputExists, "Refusing to overwrite #{out_file}: missing erbtex generated-file marker"
|
|
132
164
|
end
|
|
133
165
|
end
|
data/lib/erbtex/version.rb
CHANGED
data/lib/erbtex.rb
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Conditional added to prevent running bundler/setup twice when it already has
|
|
2
4
|
# erbtex in the LOAD_PATH. Failure to do this was causing bundler to setup for
|
|
3
5
|
# the wrong Gemfile if it was run in the development directory of another gem,
|
|
4
6
|
# for example, ydl. This only happened on saturn for some reason that I don't
|
|
5
7
|
# understand, but this kludge made it work.
|
|
6
8
|
|
|
7
|
-
require 'bundler/setup' if $LOAD_PATH.none? { |p| p
|
|
9
|
+
require 'bundler/setup' if $LOAD_PATH.none? { |p| p.include?('erbtex') }
|
|
8
10
|
|
|
9
11
|
require 'shellwords'
|
|
10
12
|
require 'erubis'
|