require 'tempfile' require 'pathname' require 'English' # Name space module for erbtex program. module ErbTeX # Perform the erubis pre-processing and the TeX processing on the input # file. def self.run(cmd_line) report_version && exit(0) if cmd_line.print_version report_help && exit(0) if cmd_line.print_help in_dir = parse_file_name(cmd_line.input_file)[:dir] tex_file = erb_to_tex(cmd_line.input_file, in_dir) if cmd_line.input_file run_tex(cmd_line.tex_command(tex_file), in_dir) end def self.report_version puts "erbtex version: #{ErbTeX::VERSION}" puts "Ruby version: #{RUBY_VERSION}" begin erubis_version = `erubis -v` rescue Errno::ENOENT warn 'Warning: erubis does not appear to be installed!' exit(1) end puts "erubis version: #{erubis_version}" true end # Display the help for erbtex. def self.report_help puts <<~HELP Usage: erbtex [erbtex_options] [tex_prog_args] [file] erbtex_options are: --version - print the version of the erbtex gem, ruby and erubis --help - print this help message --invoke= - after pre-processing, invoke on the resulting file, tex_prog is pdflatex by default All other arguments, except possibly the last, are passed unaltered to the tex_prog for interpretation. If any of these arguments starts with a '\\' or '&', then all remaining arguments are passed to tex-prog for interpretation, even the final argument. The last argument is taken as the input file name unless it or any earlier argument starts with a '\\' or '&', in which case it is also passed along as an argument to the tex-prog. HELP true end # Run the TeX program on the erubis-processed output file, which is the # input file to the TeX program. Return the exit status. def self.run_tex(cmd, in_dir = nil) # If the input file is located in another directory (in_dir), add that # directory to TEXINPUTS if its not already there so that the input file # can \include or \input files using relative file names. new_env = {} if in_dir in_dir = File.absolute_path(File.expand_path(in_dir)) ENV['TEXINPUTS'] ||= '' unless ENV['TEXINPUTS'].split(File::PATH_SEPARATOR) .reject { |p| p.strip.empty? } .any? { |p| in_dir == File.absolute_path(File.expand_path(p)) } new_env['TEXINPUTS'] = "#{in_dir}:#{ENV['TEXINPUTS']}" end end # Call cmd with the environment augmented by possibly expanded TEXINPUTS # environment variable. unless system(new_env, cmd) warn "Call to '#{cmd}' failed." exit $CHILD_STATUS end # Run a second time unless its latexmk unless cmd =~ /\A *latexmk/ unless system(new_env, cmd) warn "Call to '#{cmd}' failed." exit $CHILD_STATUS end end $CHILD_STATUS end # Pre-process the input file with erubis, adding the in_dir to the front of # the ruby load path if its not already in the load path so that requires in # the input file can be found if they are in the in_dir. Return the name of # the output file. def self.erb_to_tex(in_file, in_dir = nil) # Add input to ruby LOAD_PATH, $:,if its not already there. if File.exist?(in_dir) in_dir = File.absolute_path(File.expand_path(in_dir)) unless $LOAD_PATH .any? { |p| in_dir == File.absolute_path(File.expand_path(p)) } $LOAD_PATH.unshift(in_dir) end end # Read the input in_contents = nil File.open(in_file) do |f| in_contents = f.read end # TODO: recurse through any \input or \include commands pat = ENV['ERBTEX_PATTERN'] || '{: :}' out_file = ErbTeX.out_file_name(in_file) File.open(out_file, 'w') do |f| er = ::Erubis::Eruby.new(in_contents, pattern: pat) f.write(er.result) end out_file rescue SystemCallError => e warn "Error: #{e}" exit 1 rescue ScriptError => e warn "Erubis pre-processing failed: #{e}" exit 1 end end