module Lbt

LaTeX-Buildtools provides Ruby script lbt to create template, build it and do other tasks. The lbt command includes Lbt module and calls its instance methods. All the methods are instance methods and Lbt module doesn’t have any singleton methods.

Public Instance Methods

build() click to toggle source

Typeset LaTeX source files into a PDF file.

# File lib/lbt/build.rb, line 5
def build
  m = get_config[:'build_dir']
  build_dir = m ? m : "_build"
  raise "main.tex not exist." unless File.exist?('main.tex')
  mkdir build_dir unless Dir.exist?(build_dir)

  # Build main.tex
  main_tex = File.read('main.tex')
  m = /\\title(\[(.*?)\])?\s*\{(.*?)\}/.match(main_tex.remove_tex_comment)
  # Beamer has \title[short title]{title} command.
  # Other documentclasses don't have such short style option.
  title = m[2] || m[3]
  files = PCS.new.to_a
  input_commands = files.map{|f| "\\input{#{f.ext('.tex')}}\n"}.flatten.join
  main_tex = main_tex.sub(/\\end{document}/, "#{input_commands}\n\\end{document}")
  File.write("#{build_dir}/main.tex", main_tex)
  # copy or convert the files into build_dir
  cp_conv build_dir
  # Typeset
  cur_dir = Dir.pwd
  cd build_dir
  system "latexmk -lualatex -pdflualatex=\"lualatex --halt-on-error %O %S\" main.tex"
  cd cur_dir
  
  # Copy the pdf file.
  temp = "#{build_dir}/main.pdf"
  target = "#{title}.pdf"
  unless File.exist?(target) && File.mtime(temp) <= File.mtime(target)
    cp temp, target
  end
end
cp_conv(build_dir) click to toggle source

copy or convert source files into build directory.

# File lib/lbt/utils.rb, line 127
def cp_conv build_dir
  converters = get_converters
  files = Dir.children(".").reject{|f| f == build_dir || f == "main.tex"}
  cp_conv_0 ".", files, build_dir, converters
end
create(dir, document_class="book", build_dir="_build") click to toggle source

The create method creates a source file directory and put some templates in the directory.

Parameters are:

dir

The name of the source file directory

document_class

The document class of the LaTeX source file. For example, article, book and beamer.

build_dir

The working directory in which typeset is carried out.

# File lib/lbt/create.rb, line 14
  def create dir, document_class="book", build_dir="_build"
    raise "Argument error." unless dir.is_a?(String) && dir =~ /[[:^space:]]+/
    raise "#{dir} already exists." if Dir.exist?(dir)
    mkdir_p(dir)
    File.write("#{dir}/.config", "build_dir = #{build_dir}\n")
    helper_tex = <<~EOS
    \\usepackage{amsmath,amssymb}
    \\usepackage[luatex]{graphicx}
    \\usepackage{tikz}
    \\usepackage[margin=2.4cm]{geometry}
    \\usepackage[colorlinks=true,linkcolor=black]{hyperref}
    % If your source includes Markdown, you probably need the following lines.
    % It is because Pandoc generates some undefined commands.
    % The Pandoc template file shows how to define them.
    % You can see it by 'pandoc --print-default-template=latex'.
    \\providecommand{\\tightlist}{%
      \\setlength{\\itemsep}{0pt}\\setlength{\\parskip}{0pt}}
    EOS

    if ["book", "ltjsbook"].include? document_class
        main_tex = <<~EOS
        \\documentclass{#{document_class}}
        \\input{helper.tex}
        \\title{Title}
        \\author{Author}
        \\begin{document}
        \\frontmatter
        \\begin{titlepage}
        \\input{cover.tex}
        \\end{titlepage}
        \\tableofcontents
        \\mainmatter

        \\end{document}
      EOS

      cover_tex = <<~EOS
        \\newgeometry{margin=2.4cm}
        \\begin{center}
        \\begin{tikzpicture}
          \\node at (0,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (70pt,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (140pt,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (210pt,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (280pt,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (350pt,0) {\\includegraphics[width=100pt]{gecko.png}};
        \\end{tikzpicture}
        \\end{center}

        \\vspace{2cm}
        \\begin{center}
        {\\fontsize{64}{0} \\selectfont Title}
        \\end{center}
        \\vspace{1cm}
        \\begin{center}
        {\\huge Author}
        \\end{center}

        \\vspace{9cm}
        %\\vspace{6.5cm}
        %\\begin{center}
        %{\\Large Foobar University}
        %\\end{center}
        %\\begin{center}
        %{\\Large School of Foobar}
        %\\end{center}

        \\vspace{3cm}
        \\begin{center}
        \\begin{tikzpicture}
          \\node at (0,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (70pt,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (140pt,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (210pt,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (280pt,0) {\\includegraphics[width=100pt]{gecko.png}};
          \\node at (350pt,0) {\\includegraphics[width=100pt]{gecko.png}};
        \\end{tikzpicture}
        \\end{center}
        \\restoregeometry
      EOS

      File.write("#{dir}/main.tex", main_tex)
      File.write("#{dir}/helper.tex", helper_tex)
      File.write("#{dir}/cover.tex", cover_tex)
      gecko_png = __dir__+"/../../images/gecko.png"
      cp(gecko_png, "#{dir}/gecko.png")
    elsif ["article", "ltjsarticle"].include? document_class
      main_tex = <<~EOS
      \\documentclass{#{document_class}}
      \\input{helper.tex}
      \\title{Title}
      \\author{Author}
      \\begin{document}
      \\maketitle
      \\tableofcontents

      \\end{document}
      EOS
      File.write("#{dir}/main.tex", main_tex)
      File.write("#{dir}/helper.tex", helper_tex)
    elsif document_class == "beamer"
      main_tex = <<~EOS
      \\documentclass[utf8,aspectratio=169]{beamer}
      \\mode<presentation>
      {
        \\usetheme{Warsaw}
        \\setbeamercovered{transparent}
      }
      \\input{helper.tex}
      % Don't show navigation symbol => If you want to show it, comment out the following line.
      \\setbeamertemplate{navigation symbols}{}
      \\title[short\\_title] % (optional, use only with long paper titles)
      {titile}
      \\subtitle
      {substitile}
      \\author[short\\_author] % (optional, use only with lots of authors)
      {author \\\\ \\texttt{sample\\_address@email.com}}
      % - Give the names in the same order as the appear in the paper.
      % - Use the \\inst{?} command only if the authors have different
      %   affiliation.
      \\institute[short\\_institute] % (optional, but mostly needed)
      {
      %  \\inst{1}%
        Department of Mathematics and Technology\\\\
        School of Education and Humanities\\\\
        XXXX University
      }
      % - Use the \\inst command only if there are several affiliations.
      % - Keep it simple, no one is interested in your street address.
      \\date[short\\_date] % (optional, should be abbreviation of conference name)
      {XXXX meeting on Wednesday, April 27 2022}
      % - Either use conference name or its abbreviation.
      % - Not really informative to the audience, more for people (including
      %   yourself) who are reading the slides online
      \\subject{subject}
      % If you have a file called "university-logo-filename.xxx", where xxx
      % is a graphic format that can be processed by lualatex,
      % resp., then you can add a logo as follows:
      % \\pgfdeclareimage[height=0.5cm]{university-logo}{university-logo-filename}
      % \\logo{\\pgfuseimage{university-logo}}
      \\begin{document}
      \\begin{frame}
        \\titlepage
      \\end{frame}
      \\begin{frame}{Outline}
        \\tableofcontents
      %  \\begin{center}
      %    \\includegraphics[width=6cm,keepaspectratio]{photo.jpg}
      %  \\end{center}
      \\end{frame}

      \\end{document}
      EOS
      helper_tex = <<~EOS
      \\usepackage{luatexja}
      % 和文のデフォルトをゴシック体に
      \\renewcommand{\\kanjifamilydefault}{\\gtdefault}
      \\usepackage{amsmath,amssymb}
      \\usepackage{tikz}
      \\usepackage[absolute,overlay]{textpos}
      % 数式フォントを設定(これなしだとsansになる)
      \\usefonttheme{professionalfonts}
      EOS
      sec1_tex = <<~EOS
      % This is a sample latex file for the beamer documentclass.
      \\section{Section Title}
      \\begin{frame}
      \\frametitle{introduction}
      About something
      \\begin{itemize}
        \\item item 1
        \\item<2> item 2
      \\end{itemize}
      About another thing
      \\begin{enumerate}
        \\item<3> item 1
        \\item<3-4> item 2
      \\end{enumerate}
      \\alert{alert message, which is red.}
      \\end{frame}
      % Show a photo that extends to the whole slide view.
      % The aspect ratio is 16:9.
      \\begin{frame}
      \\begin{textblock*}{128mm}(0pt,0pt)
      \\includegraphics[width=160mm,height=90mm,keepaspectratio]{lagoon.jpg}
      \\end{textblock*}
      \\end{frame}
      EOS
      File.write("#{dir}/main.tex", main_tex)
      File.write("#{dir}/helper.tex", helper_tex)
      File.write("#{dir}/sec1.tex", sec1_tex)
      lagoon_jpg = __dir__+"/../../images/lagoon.jpg"
      cp(lagoon_jpg, "#{dir}/lagoon.jpg")
    else
      main_tex = <<~EOS
      \\documentclass{#{document_class}}
      \\input{helper.tex}
      \\title{Title}
      \\author{Author}
      \\begin{document}
      \\maketitle
      \\tableofcontents

      \\end{document}
      EOS
      File.write("#{dir}/main.tex", main_tex)
      File.write("#{dir}/helper.tex", helper_tex)
    end
  end
get_config() click to toggle source

Convert ‘.config’ file into a Hash

# File lib/lbt/utils.rb, line 109
def get_config
  return {} unless File.exist?(".config")
  File.read(".config").split(/\n/).map{|s| s.split('=')}.map{|key, val| [key.strip.to_sym, val.strip]}.to_h
end
get_converters() click to toggle source

Return a hash (key: extension, value: Proc object) of converters.

# File lib/lbt/utils.rb, line 115
def get_converters
  tld = get_config[:'top-level-division']
  tld = tld ? tld : "default"
  converters = {'.md':  lambda {|src, dst| system("pandoc --top-level-division=#{tld} -o #{dst} #{src}")} }
  if File.file?("converters.rb")
    c = eval(File.read("converters.rb"))
    c.each {|key, val| converters[key] = val} if c.is_a?(Hash)
  end
  converters
end
part_typeset(file_or_number) click to toggle source

Typeset one source file to check the PDF.

Parameter:

file_or_number

It can be either a filename or the number of a filename. For example, part1/chap2/sec3.tex or 1-2-3

# File lib/lbt/part_typeset.rb, line 10
def part_typeset file_or_number
  return unless file_or_number.is_a? String
  if File.file?(file_or_number)
    file = file_or_number
  else
    file = num2path(file_or_number)
    return unless File.file? file
  end

  m = get_config[:'build_dir']
  build_dir = m ? m : "_build"
  raise "main.tex not exist." unless File.exist?('main.tex')
  mkdir build_dir unless Dir.exist?(build_dir)

  main_tex = File.read('main.tex')
  main_tex = main_tex.sub(/\\end{document}/, "\\input{#{file.ext('.tex')}}\n\\end{document}")
  File.write("#{build_dir}/main.tex", main_tex)
  # copy or convert the files into build_dir
  cp_conv build_dir
  # Typeset
  cur_dir = Dir.pwd
  cd build_dir
  system "latexmk -lualatex -pdflualatex=\"lualatex --halt-on-error %O %S\" main.tex"
  cd cur_dir
end
renum() click to toggle source

Renumber the source files. For example,

  • sec1.tex, sec1.5.tex, sec2.tex => sec1.tex, sec2.tex, sec3.tex

  • chap1/sec1.tex, chap1/sec1.2.tex, chap1.3/sec10.tex => chap1/sec1.tex, chap1/sec2.tex, chap2/sec1.tex

# File lib/lbt/renumber.rb, line 6
def renum
  if Dir.children(".").select{|d| d =~ /^part\d+(\.\d+)?$/}.size > 0
    renumber "part"
  elsif Dir.children(".").select{|d| d =~ /^chap\d+(\.\d+)?$/}.size > 0
    renumber "chap"
  else
    renumber "sec"
  end
end