module Softcover::Utils

Constants

UNITS

Public Instance Methods

add_highlight_class!(pygments_css) click to toggle source

Adds a 'highlight' class for MathJax compatibility.

# File lib/softcover/utils.rb, line 168
def add_highlight_class!(pygments_css)
  pygments_css.gsub!(/^/, '.highlight ')
end
article?() click to toggle source

Returns true if document is an article.

# File lib/softcover/utils.rb, line 314
def article?
  !!File.readlines(path('config/preamble.tex')).first.match(/extarticle/)
end
as_size(number) click to toggle source
# File lib/softcover/utils.rb, line 50
def as_size(number)
  if number.to_i < 1024
    exponent = 0

  else
    max_exp  = UNITS.size - 1

    exponent = ( Math.log( number ) / Math.log( 1024 ) ).to_i
    exponent = max_exp if exponent > max_exp

    number  /= 1024 ** exponent
  end

  "#{number.round} #{UNITS[ exponent ]}"
end
book_file_lines(manifest) click to toggle source

Returns the lines of book file as an array, removing commented-out lines.

# File lib/softcover/utils.rb, line 82
def book_file_lines(manifest)
  non_comment_lines(raw_lines(manifest))
end
chapter_label(chapter_number) click to toggle source
# File lib/softcover/utils.rb, line 299
def chapter_label(chapter_number)
  if language_labels["chapter"]["order"] == "reverse"
    "#{chapter_number} #{language_labels['chapter']['word']}"
  else
    "#{language_labels['chapter']['word']} #{chapter_number}"
  end
end
commands(lines) click to toggle source

Returns the commands from the given lines. We skip comments and blank lines.

# File lib/softcover/utils.rb, line 240
def commands(lines)
  skip = /(^\s*#|^\s*$)/
  lines.reject { |line| line =~ skip }.join("\n")
end
current_book() click to toggle source
# File lib/softcover/utils.rb, line 4
def current_book
  # using module level variable because it should be context independent
  @@current_book ||= begin
    in_book_directory? ? Softcover::Book.new(origin: source) : false
  end
end
dependency_filename(label) click to toggle source

Returns the filename of a dependency given a label.

# File lib/softcover/utils.rb, line 253
def dependency_filename(label)
  case label
  when :latex
    get_filename(:xelatex)
  when :ghostscript
    get_filename(:gs)
  when :calibre
    get_filename(:'ebook-convert')
  when :epubcheck
    # Finds EpubCheck anywhere on the path.
    version_4 = path('epubcheck-4.2.2/epubcheck.jar')
    first_path(version_4) || get_filename(:'epubcheck') || ""
  when :inkscape
    default = '/Applications/Inkscape.app/Contents/MacOS/inkscape'
    filename_or_default(:inkscape, default)
  when :phantomjs
    phantomjs = get_filename(label)
    # Test for version 2, which is now necessary.
    version = `#{phantomjs} -v`.scan(/^(\d)\./).flatten.first.to_i rescue nil
    if version == 2
      phantomjs
    else
      ""
    end
  when :python3
    python = get_filename(:python3)
    `#{python} --version`.match(/Python 3\.*/) ? python : ""
  else
    get_filename(label)
  end
end
digest(string) click to toggle source

Returns a digest of the string.

# File lib/softcover/utils.rb, line 173
def digest(string)
  Digest::SHA1.hexdigest(string)
end
executable(filename) click to toggle source

Returns the executable if it exists, raising an error otherwise.

# File lib/softcover/utils.rb, line 178
def executable(filename)
  filename.tap do |f|
    unless File.exist?(f)
      $stderr.puts "Document not built due to missing dependency"
      $stderr.puts "Run `softcover check` to check dependencies"
      exit 1
    end
  end
end
execute(command) click to toggle source

Execute a command. The issue here is that `exec` is awful in tests, since it exits the process. This command arranges to use `system` in tests instead.

# File lib/softcover/utils.rb, line 216
def execute(command)
  Softcover.test? ? system(command) : exec(command)
end
filename_or_default(name, default) click to toggle source

Returns the filename if it exists on the path and a default otherwise.

# File lib/softcover/utils.rb, line 290
def filename_or_default(name, default)
  (f = get_filename(name)).empty? ? default : f
end
first_path(file) click to toggle source

Returns first location on the path for a given file.

# File lib/softcover/utils.rb, line 246
def first_path(file)
  possible_paths = ENV['PATH'].split(File::PATH_SEPARATOR).
                                     collect { |x| File.join(x, file) }
  possible_paths.find { |f| File.file?(f) }
end
get_filename(name) click to toggle source
# File lib/softcover/utils.rb, line 285
def get_filename(name)
  `which #{name}`.chomp
end
html_extension() click to toggle source
# File lib/softcover/utils.rb, line 44
def html_extension
  'html'
end
in_book_directory?() click to toggle source
# File lib/softcover/utils.rb, line 25
def in_book_directory?
  Softcover::BookManifest::find_book_root!

  files = Dir['**/*']

  Softcover::FORMATS.each do |format|
    unless files.any?{ |file| File.extname(file) == ".#{format}" }
      puts "No #{format} found, skipping."
    end
  end

  return Softcover::BookManifest::valid_directory?
end
language_labels() click to toggle source

Returns the language labels from the config file.

# File lib/softcover/utils.rb, line 295
def language_labels
  YAML.load_file(File.join(Softcover::Directories::CONFIG, 'lang.yml'))
end
linux?() click to toggle source

Returns true if platform is Linux.

# File lib/softcover/utils.rb, line 234
def linux?
  RUBY_PLATFORM.match(/linux/)
end
logged_in?() click to toggle source
# File lib/softcover/utils.rb, line 39
def logged_in?
  require 'softcover/config'
  Softcover::Config['api_key'].present?
end
master_content(manifest) click to toggle source

Returns the content for the master LaTeX file.

# File lib/softcover/utils.rb, line 98
def master_content(manifest)
  front_or_mainmatter = /(.*):\s*$/
  source_file = /(.*)(?:\.md|\.tex)\s*$/

  tex_file = [master_latex_header(manifest)]
  book_file_lines(manifest).each do |line|
    if line.match(source_file)
      tex_file << "\\include{#{manifest.polytex_dir}/#{$1}}"
    elsif line.match(front_or_mainmatter)  # frontmatter or mainmatter
      tex_file << "\\#{$1}"
    elsif line.strip == 'cover'
      tex_file << '\\includepdf{images/cover.pdf}'
    else # raw command, like 'maketitle' or 'tableofcontents'
      tex_file << "\\#{line.strip}"
    end
  end
  tex_file << '\end{document}'
  tex_file.join("\n") + "\n"
end
master_filename(manifest) click to toggle source

Returns the name of the master LaTeX file.

# File lib/softcover/utils.rb, line 77
def master_filename(manifest)
  "#{manifest.filename}.tex"
end
master_latex_header(manifest) click to toggle source
# File lib/softcover/utils.rb, line 118
  def master_latex_header(manifest)
    preamble = File.read(path('config/preamble.tex'))
    subtitle = manifest.subtitle.nil? ? "" : "\\subtitle{#{manifest.subtitle}}"
    <<-EOS
#{preamble}
\\usepackage{#{Softcover::Directories::STYLES}/softcover}
\\VerbatimFootnotes % Allows verbatim text in footnotes
\\title{#{manifest.title}}
#{subtitle}
\\author{#{manifest.author}}
\\date{#{manifest.date}}

\\begin{document}
    EOS
  end
mkdir(dir) click to toggle source
# File lib/softcover/utils.rb, line 188
def mkdir(dir)
  Dir.mkdir(dir) unless File.directory?(dir)
end
non_comment_lines(lines) click to toggle source

Returns only non-comment lines.

# File lib/softcover/utils.rb, line 87
def non_comment_lines(lines)
  comment = /^\s*#.*$/
  lines.reject { |line| line.match(comment) }
end
os_x?() click to toggle source

Returns true if platform is OS X.

# File lib/softcover/utils.rb, line 229
def os_x?
  RUBY_PLATFORM.match(/darwin/)
end
path(path_string='') click to toggle source

Returns the system-independent file path. It's nicer to write `path('foo/bar/baz')` than `File.join('foo', 'bar', 'baz')`.

# File lib/softcover/utils.rb, line 209
def path(path_string='')
  File.join(*path_string.split('/'))
end
polytexnic_html(text) click to toggle source

Run text through the Polytexnic pipeline to make an HTML snippet.

# File lib/softcover/utils.rb, line 333
def polytexnic_html(text)
  Nokogiri::HTML(Polytexnic::Pipeline.new(text).to_html).at_css('p')
                                                       .inner_html.strip
end
raw_lines(manifest) click to toggle source

Returns all the lines in Book.txt.

# File lib/softcover/utils.rb, line 93
def raw_lines(manifest)
  File.readlines(manifest.book_file)
end
reset_current_book!() click to toggle source
# File lib/softcover/utils.rb, line 21
def reset_current_book!
  @@current_book = nil
end
rm(file) click to toggle source

Removes a file (or list of files).

# File lib/softcover/utils.rb, line 193
def rm(file)
  if file.is_a?(Array)
    file.each { |f| rm(f) }
  else
    FileUtils.rm(file) if File.exist?(file)
  end
end
rm_r(directory) click to toggle source

Removes a directory recursively.

# File lib/softcover/utils.rb, line 202
def rm_r(directory)
  FileUtils.rm_r(directory) if File.directory?(directory)
end
silence() { || ... } click to toggle source
# File lib/softcover/utils.rb, line 220
def silence
  return yield if ENV['silence'] == 'false'

  silence_stream(STDOUT) do
    yield
  end
end
silence_stream(stream) { || ... } click to toggle source

Silences a stream. This is taken directly from Rails Active Support `silence_stream`. The `silence_stream` method is deprecated because it's not thread-safe, but we don't care about that and the deprecation warnings are annoying.

# File lib/softcover/utils.rb, line 322
def silence_stream(stream)
  old_stream = stream.dup
  stream.reopen(RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? 'NUL:' : '/dev/null')
  stream.sync = true
  yield
ensure
  stream.reopen(old_stream)
  old_stream.close
end
source() click to toggle source

Returns the source type (PolyTeX or Markdown) of the current book.

# File lib/softcover/utils.rb, line 12
def source
  Dir.glob(path('chapters/*.md')).empty? ? :polytex : :markdown
end
template_dir(options) click to toggle source

Returns the directory of the document template.

# File lib/softcover/utils.rb, line 308
def template_dir(options)
  doc = options[:article] ? 'article' : 'book'
  File.expand_path File.join(File.dirname(__FILE__), "#{doc}_template")
end
tmpify(manifest, filename) click to toggle source

Returns the tmp version of a filename. E.g., tmpify('foo.tex') => 'foo.tmp.tex'

# File lib/softcover/utils.rb, line 136
def tmpify(manifest, filename)
  tmp = Softcover::Directories::TMP
  mkdir tmp
  sep = File::SEPARATOR
  filename.sub(manifest.polytex_dir + sep, tmp + sep).
           sub('.tex', '.tmp.tex')
end
unpublish_slug() click to toggle source

Returns the slug to be unpublished.

# File lib/softcover/utils.rb, line 17
def unpublish_slug
  Softcover::BookManifest.new(origin: source).slug
end
write_master_latex_file(manifest) click to toggle source

Writes the master LaTeX file <name>.tex to use chapters from Book.txt. We skip this step if Book.txt doesn't exist, as that means the user is writing raw LaTeX.

# File lib/softcover/utils.rb, line 70
def write_master_latex_file(manifest)
  if File.exist?(manifest.book_file)
    File.write(master_filename(manifest), master_content(manifest))
  end
end
write_pygments_file(format, path) click to toggle source

Writes a Pygments style file. We support both :html (outputting CSS) and :latex (outputting a LaTeX style file).

# File lib/softcover/utils.rb, line 147
def write_pygments_file(format, path)
  require 'pygments'
  extension = case format
              when :html
                'css'
              when :latex
                'sty'
              end
  # Here we burrow into the private 'Pygments#mentos' method.
  # Pygments exposes a 'css' method to return the CSS,
  # but we want to be able to output a LaTeX style file as well.
  # The inclusion of the ':css' symbol is necessary but doesn't actually
  # result in CSS being output unless the format is 'html'.
  pygments = Pygments::Popen.new.send(:mentos, :css, [format.to_s, ''])
  add_highlight_class!(pygments) if format == :html
  File.open(File.join(path, "pygments.#{extension}"), 'w') do |f|
    f.write(pygments)
  end
end