class ReVIEW::PDFMaker

Attributes

basedir[RW]
basehookdir[RW]
config[RW]

Public Class Methods

execute(*args) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 80
def self.execute(*args)
  self.new.execute(*args)
end
new() click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 31
def initialize
  @basedir = nil
  @basehookdir = nil
  @logger = ReVIEW.logger
  @input_files = Hash.new { |h, key| h[key] = '' }
end

Public Instance Methods

build_path() click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 59
def build_path
  if @config['debug']
    path = "#{@config['bookname']}-pdf"
    FileUtils.rm_rf(path, secure: true) if File.exist?(path)
    Dir.mkdir(path)
    path
  else
    Dir.mktmpdir("#{@config['bookname']}-pdf-")
  end
end
build_pdf() click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 151
def build_pdf
  template = template_content
  Dir.chdir(@path) do
    File.open('./book.tex', 'wb') { |f| f.write(template) }

    call_hook('hook_beforetexcompile')

    ## do compile
    if ENV['REVIEW_SAFE_MODE'].to_i & 4 > 0
      warn 'command configuration is prohibited in safe mode. ignored.'
      texcommand = ReVIEW::Configure.values['texcommand']
      dvicommand = ReVIEW::Configure.values['dvicommand']
      dvioptions = ReVIEW::Configure.values['dvioptions']
      texoptions = ReVIEW::Configure.values['texoptions']
      makeindex_command = ReVIEW::Configure.values['pdfmaker']['makeindex_command']
      makeindex_options = ReVIEW::Configure.values['pdfmaker']['makeindex_options']
      makeindex_sty = ReVIEW::Configure.values['pdfmaker']['makeindex_sty']
      makeindex_dic = ReVIEW::Configure.values['pdfmaker']['makeindex_dic']
    else
      texcommand = @config['texcommand'] if @config['texcommand']
      dvicommand = @config['dvicommand'] if @config['dvicommand']
      dvioptions = @config['dvioptions'] if @config['dvioptions']
      texoptions = @config['texoptions'] if @config['texoptions']
      makeindex_command = @config['pdfmaker']['makeindex_command']
      makeindex_options = @config['pdfmaker']['makeindex_options']
      makeindex_sty = @config['pdfmaker']['makeindex_sty']
      makeindex_dic = @config['pdfmaker']['makeindex_dic']
    end

    if makeindex_sty.present?
      makeindex_sty = File.absolute_path(makeindex_sty, @basedir)
      makeindex_options += " -s #{makeindex_sty}" if File.exist?(makeindex_sty)
    end
    if makeindex_dic.present?
      makeindex_dic = File.absolute_path(makeindex_dic, @basedir)
      makeindex_options += " -d #{makeindex_dic}" if File.exist?(makeindex_dic)
    end

    2.times do
      system_or_raise("#{texcommand} #{texoptions} book.tex")
    end

    call_hook('hook_beforemakeindex')
    system_or_raise("#{makeindex_command} #{makeindex_options} book") if @config['pdfmaker']['makeindex'] && File.exist?('book.idx')
    call_hook('hook_aftermakeindex')

    system_or_raise("#{texcommand} #{texoptions} book.tex")
    call_hook('hook_aftertexcompile')

    if File.exist?('book.dvi')
      system_or_raise("#{dvicommand} #{dvioptions} book.dvi")
      call_hook('hook_afterdvipdf')
    end
  end
end
call_hook(hookname) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 406
def call_hook(hookname)
  return if !@config['pdfmaker'].is_a?(Hash) || @config['pdfmaker'][hookname].nil?
  hook = File.absolute_path(@config['pdfmaker'][hookname], @basehookdir)
  if ENV['REVIEW_SAFE_MODE'].to_i & 1 > 0
    warn 'hook configuration is prohibited in safe mode. ignored.'
  else
    system_or_raise("#{hook} #{Dir.pwd} #{@basehookdir}")
  end
end
check_compile_status(ignore_errors) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 70
def check_compile_status(ignore_errors)
  return unless @compile_errors

  if ignore_errors
    $stderr.puts 'compile error, but try to generate PDF file'
  else
    error 'compile error, No PDF file output.'
  end
end
copy_images(from, to) click to toggle source

#copy_images should copy image files AND execute extractbb (or ebb).

# File ../../../../../lib/review/pdfmaker.rb, line 251
def copy_images(from, to)
  return unless File.exist?(from)
  Dir.mkdir(to)
  ReVIEW::MakerHelper.copy_images_to_dir(from, to)
  Dir.chdir(to) do
    images = Dir.glob('**/*').find_all { |f| File.file?(f) and f =~ /\.(jpg|jpeg|png|pdf|ai|eps|tif)\z/ }
    break if images.empty?
    system('extractbb', *images)
    system_or_raise('ebb', *images) unless system('extractbb', '-m', *images)
  end
end
copy_sty(dirname, copybase, extname = 'sty') click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 390
def copy_sty(dirname, copybase, extname = 'sty')
  unless File.directory?(dirname)
    warn "No such directory - #{dirname}"
    return
  end

  Dir.open(dirname) do |dir|
    dir.each do |fname|
      if File.extname(fname).downcase == '.' + extname
        FileUtils.mkdir_p(copybase)
        FileUtils.cp File.join(dirname, fname), copybase
      end
    end
  end
end
date_to_s(date) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 333
def date_to_s(date)
  require 'date'
  d = Date.parse(date)
  d.strftime(ReVIEW::I18n.t('date_format'))
end
error(msg) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 42
def error(msg)
  @logger.error "#{File.basename($PROGRAM_NAME, '.*')}: #{msg}"
  exit 1
end
execute(*args) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 106
def execute(*args)
  @config = ReVIEW::Configure.values
  @config.maker = 'pdfmaker'
  cmd_config, yamlfile = parse_opts(args)
  loader = ReVIEW::YAMLLoader.new
  @config.deep_merge!(loader.load_file(yamlfile))
  # YAML configs will be overridden by command line options.
  @config.merge!(cmd_config)
  I18n.setup(@config['language'])
  @basedir = File.dirname(yamlfile)
  @basehookdir = File.absolute_path(File.dirname(yamlfile))

  begin
    @config.check_version(ReVIEW::VERSION)
  rescue ReVIEW::ConfigError => e
    warn e.message
  end
  generate_pdf(yamlfile)
end
generate_pdf(yamlfile) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 207
def generate_pdf(yamlfile)
  remove_old_file
  @path = build_path
  begin
    @compile_errors = nil

    book = ReVIEW::Book.load(@basedir)
    book.config = @config
    @converter = ReVIEW::Converter.new(book, ReVIEW::LATEXBuilder.new)

    @input_files = make_input_files(book, yamlfile)

    check_compile_status(@config['ignore-errors'])

    @config['usepackage'] = ''
    @config['usepackage'] = "\\usepackage{#{@config['texstyle']}}" if @config['texstyle']

    copy_images(@config['imagedir'], File.join(@path, @config['imagedir']))
    copy_sty(File.join(Dir.pwd, 'sty'), @path)
    copy_sty(File.join(Dir.pwd, 'sty'), @path, 'fd')
    copy_sty(File.join(Dir.pwd, 'sty'), @path, 'cls')
    copy_sty(Dir.pwd, @path, 'tex')

    build_pdf

    FileUtils.cp(File.join(@path, 'book.pdf'), pdf_filepath)
  ensure
    remove_entry_secure @path unless @config['debug']
  end
end
join_with_separator(value, sep) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 269
def join_with_separator(value, sep)
  if value.is_a?(Array)
    value.join(sep)
  else
    value
  end
end
make_authors() click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 292
def make_authors
  authors = ''
  if @config['aut'].present?
    author_names = join_with_separator(@config.names_of('aut').map { |s| escape_latex(s) }, ReVIEW::I18n.t('names_splitter'))
    authors = ReVIEW::I18n.t('author_with_label', author_names)
  end
  if @config['csl'].present?
    csl_names = join_with_separator(@config.names_of('csl').map { |s| escape_latex(s) }, ReVIEW::I18n.t('names_splitter'))
    authors += " \\\\\n" + ReVIEW::I18n.t('supervisor_with_label', csl_names)
  end
  if @config['trl'].present?
    trl_names = join_with_separator(@config.names_of('trl').map { |s| escape_latex(s) }, ReVIEW::I18n.t('names_splitter'))
    authors += " \\\\\n" + ReVIEW::I18n.t('translator_with_label', trl_names)
  end
  authors
end
make_colophon() click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 286
def make_colophon
  colophon = ''
  @config['colophon_order'].each { |role| colophon += make_colophon_role(role) }
  colophon
end
make_colophon_role(role) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 277
def make_colophon_role(role)
  if @config[role].present?
    initialize_metachars(@config['texcommand'])
    "#{ReVIEW::I18n.t(role)} & #{escape_latex(join_with_separator(@config.names_of(role), ReVIEW::I18n.t('names_splitter')))} \\\\\n"
  else
    ''
  end
end
make_custom_page(file) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 263
def make_custom_page(file)
  file_sty = file.to_s.sub(/\.[^.]+\Z/, '.tex')
  return File.read(file_sty) if File.exist?(file_sty)
  nil
end
make_history_list() click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 309
def make_history_list
  buf = []
  if @config['history']
    @config['history'].each_with_index do |items, edit|
      items.each_with_index do |item, rev|
        editstr = edit == 0 ? ReVIEW::I18n.t('first_edition') : ReVIEW::I18n.t('nth_edition', (edit + 1).to_s)
        revstr = ReVIEW::I18n.t('nth_impression', (rev + 1).to_s)
        if item =~ /\A\d+\-\d+\-\d+\Z/
          buf << ReVIEW::I18n.t('published_by1', [date_to_s(item), editstr + revstr])
        elsif item =~ /\A(\d+\-\d+\-\d+)[\s ](.+)/
          # custom date with string
          item.match(/\A(\d+\-\d+\-\d+)[\s ](.+)/) { |m| buf << ReVIEW::I18n.t('published_by3', [date_to_s(m[1]), m[2]]) }
        else
          # free format
          buf << item
        end
      end
    end
  elsif @config['date']
    buf << ReVIEW::I18n.t('published_by2', date_to_s(@config['date']))
  end
  buf
end
make_input_files(book, yamlfile) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 126
def make_input_files(book, yamlfile)
  input_files = Hash.new { |h, key| h[key] = '' }
  book.parts.each do |part|
    if part.name.present?
      if part.file?
        output_chaps(part.name, yamlfile)
        input_files['CHAPS'] << %Q(\\input{#{part.name}.tex}\n)
      else
        input_files['CHAPS'] << %Q(\\part{#{part.name}}\n)
      end
    end

    part.chapters.each do |chap|
      filename = File.basename(chap.path, '.*')
      output_chaps(filename, yamlfile)
      input_files['PREDEF'] << "\\input{#{filename}.tex}\n" if chap.on_predef?
      input_files['CHAPS'] << "\\input{#{filename}.tex}\n" if chap.on_chaps?
      input_files['APPENDIX'] << "\\input{#{filename}.tex}\n" if chap.on_appendix?
      input_files['POSTDEF'] << "\\input{#{filename}.tex}\n" if chap.on_postdef?
    end
  end

  input_files
end
output_chaps(filename, _yamlfile) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 238
def output_chaps(filename, _yamlfile)
  $stderr.puts "compiling #{filename}.tex"
  begin
    @converter.convert(filename + '.re', File.join(@path, filename + '.tex'))
  rescue => e
    @compile_errors = true
    warn "compile error in #{filename}.tex (#{e.class})"
    warn e.message
  end
end
parse_opts(args) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 84
def parse_opts(args)
  cmd_config = {}
  opts = OptionParser.new

  opts.banner = 'Usage: review-pdfmaker configfile'
  opts.version = ReVIEW::VERSION
  opts.on('--help', 'Prints this message and quit.') do
    puts opts.help
    exit 0
  end
  opts.on('--[no-]debug', 'Keep temporary files.') { |debug| cmd_config['debug'] = debug }
  opts.on('--ignore-errors', 'Ignore review-compile errors.') { cmd_config['ignore-errors'] = true }

  opts.parse!(args)
  if args.size != 1
    puts opts.help
    exit 0
  end

  [cmd_config, args[0]]
end
pdf_filepath() click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 51
def pdf_filepath
  File.join(@basedir, @config['bookname'] + '.pdf')
end
remove_old_file() click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 55
def remove_old_file
  FileUtils.rm_f(pdf_filepath)
end
system_or_raise(*args) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 38
def system_or_raise(*args)
  Kernel.system(*args) or raise("failed to run command: #{args.join(' ')}")
end
template_content() click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 339
def template_content
  dclass = @config['texdocumentclass'] || []
  @documentclass = dclass[0] || 'jsbook'
  @documentclassoption = dclass[1] || 'uplatex,oneside'

  @okuduke = make_colophon
  @authors = make_authors

  @custom_titlepage = make_custom_page(@config['cover']) || make_custom_page(@config['coverfile'])
  @custom_originaltitlepage = make_custom_page(@config['originaltitlefile'])
  @custom_creditpage = make_custom_page(@config['creditfile'])

  @custom_profilepage = make_custom_page(@config['profile'])
  @custom_advfilepage = make_custom_page(@config['advfile'])
  @custom_colophonpage = make_custom_page(@config['colophon']) if @config['colophon'] && @config['colophon'].is_a?(String)
  @custom_backcoverpage = make_custom_page(@config['backcover'])

  if @config['pubhistory']
    warn 'pubhistory is oboleted. use history.'
  else
    @config['pubhistory'] = make_history_list.join("\n")
  end

  @coverimageoption =
    if @documentclass == 'ubook' || @documentclass == 'utbook'
      'width=\\textheight,height=\\textwidth,keepaspectratio,angle=90'
    else
      'width=\\textwidth,height=\\textheight,keepaspectratio'
    end

  @locale_latex = {}
  part_tuple = I18n.get('part').split(/\%[A-Za-z]{1,3}/, 2)
  chapter_tuple = I18n.get('chapter').split(/\%[A-Za-z]{1,3}/, 2)
  appendix_tuple = I18n.get('appendix').split(/\%[A-Za-z]{1,3}/, 2)
  @locale_latex['prepartname'] = part_tuple[0]
  @locale_latex['postpartname'] = part_tuple[1]
  @locale_latex['prechaptername'] = chapter_tuple[0]
  @locale_latex['postchaptername'] = chapter_tuple[1]
  @locale_latex['preappendixname'] = appendix_tuple[0]
  @locale_latex['postappendixname'] = appendix_tuple[1]

  template = File.expand_path('./latex/layout.tex.erb', ReVIEW::Template::TEMPLATE_DIR)
  layout_file = File.join(@basedir, 'layouts', 'layout.tex.erb')
  template = layout_file if File.exist?(layout_file)

  @texcompiler = File.basename(@config['texcommand'], '.*')

  erb = ReVIEW::Template.load(template, '-')
  erb.result(binding)
end
warn(msg) click to toggle source
# File ../../../../../lib/review/pdfmaker.rb, line 47
def warn(msg)
  @logger.warn "#{File.basename($PROGRAM_NAME, '.*')}: #{msg}"
end