class ReVIEW::TOCPrinter

Attributes

calc_char_width[RW]

Public Class Methods

execute(*args) click to toggle source
# File lib/review/tocprinter.rb, line 54
def self.execute(*args)
  new.execute(*args)
end
new() click to toggle source
# File lib/review/tocprinter.rb, line 58
def initialize
  @logger = ReVIEW.logger
  @yamlfile = 'config.yml'
  @upper = 4
  @indent = true
  @buildonly = nil
  @detail = nil
  @calc_char_width = nil
end

Public Instance Methods

build_chap(chap) click to toggle source
# File lib/review/tocprinter.rb, line 259
def build_chap(chap)
  compiler = ReVIEW::Compiler.new(ReVIEW::PLAINTEXTTocBuilder.new)
  begin
    compiler.compile(@book.chapter(chap.name))
  rescue ReVIEW::ApplicationError => e
    @logger.error e.message
    ''
  end
end
build_result_array() click to toggle source
# File lib/review/tocprinter.rb, line 98
def build_result_array
  result_array = []
  begin
    @book.parts.each do |part|
      if part.name.present? && (@buildonly.nil? || @buildonly.include?(part.name))
        result_array.push(Counter.new(part: 'start'))
        if part.file?
          content = build_chap(part)
          result_array.concat(parse_contents(part.name, @upper, content))
        else
          title = part.format_number + I18n.t('chapter_postfix') + part.title
          result_array.push(
            Counter.new(name: '', lines: 1, chars: title.size, list_lines: 0, text_lines: 1),
            Counter.new(level: 0, headline: title, lines: 1, chars: title.size, list_lines: 0, text_lines: 1)
          )
        end
      end

      part.chapters.each do |chap|
        if @buildonly.nil? || @buildonly.include?(chap.name)
          content = build_chap(chap)
          result_array.concat(parse_contents(chap.name, @upper, content))
        end
      end
      if part.name.present? && (@buildonly.nil? || @buildonly.include?(part.name))
        result_array.push(Counter.new(part: 'end'))
      end
    end
  rescue ReVIEW::FileNotFound, ReVIEW::CompileError => e
    @logger.error e
    exit 1
  end

  result_array
end
calc_line_wrapping(line, mode:) click to toggle source
# File lib/review/tocprinter.rb, line 229
def calc_line_wrapping(line, mode:)
  return 1 if line.size == 0

  case mode
  when :list
    ((calc_linesize(line) - 1) / @book.page_metric.list.n_columns) + 1
  else # mode == :text
    ((calc_linesize(line) - 1) / @book.page_metric.text.n_columns) + 1
  end
end
calc_linesize(line) click to toggle source
# File lib/review/tocprinter.rb, line 166
def calc_linesize(line)
  return line.size unless @calc_char_width

  line.each_char.inject(0) do |result, char|
    # XXX: should include A also?
    if %i[Na H N].include?(Unicode::Eaw.property(char))
      result + 0.5 # halfwidth
    else
      result + 1
    end
  end
end
calc_pages(result) click to toggle source
# File lib/review/tocprinter.rb, line 161
def calc_pages(result)
  (result.list_lines.to_f / @book.page_metric.list.n_lines) +
    (result.text_lines.to_f / @book.page_metric.text.n_lines)
end
calc_total_count(name, headline_array) click to toggle source
# File lib/review/tocprinter.rb, line 240
def calc_total_count(name, headline_array)
  total = Counter.new(name: name,
                      lines: 0,
                      chars: 0,
                      list_lines: 0,
                      text_lines: 0)

  headline_array.each do |h|
    next unless h.lines

    total.lines += h.lines
    total.chars += h.chars
    total.list_lines += h.list_lines
    total.text_lines += h.text_lines
  end

  total
end
execute(*args) click to toggle source
# File lib/review/tocprinter.rb, line 70
def execute(*args)
  parse_options(args)
  begin
    @config = ReVIEW::Configure.create(yamlfile: @yamlfile)
    @book = ReVIEW::Book::Base.new('.', config: @config)
    unless File.readable?(@yamlfile)
      raise ReVIEW::FileNotFound, "No such fiile or can't open #{@yamlfile}."
    end
  rescue ReVIEW::ConfigError, ReVIEW::FileNotFound, ReVIEW::CompileError, ReVIEW::ApplicationError => e
    @logger.error e.message
    exit 1
  end

  I18n.setup(@config['language'])

  if @detail
    begin
      require 'unicode/eaw'
      @calc_char_width = true
    rescue LoadError
      @logger.warn('not found unicode/eaw library. page volume may be unreliable.')
      @calc_char_width = nil
    end
  end

  print_result(build_result_array)
end
parse_contents(name, upper, content) click to toggle source
# File lib/review/tocprinter.rb, line 179
def parse_contents(name, upper, content)
  headline_array = []
  counter = Counter.new(lines: 0, chars: 0, list_lines: 0, text_lines: 0)
  listmode = nil

  content.each_line(chomp: true) do |l|
    if l.start_with?("\x01STARTLIST\x01")
      listmode = true
      next
    elsif l.start_with?("\x01ENDLIST\x01")
      listmode = nil
      next
    elsif l =~ /\A\x01H(\d)\x01/
      # headline
      level = $1.to_i
      l = $'
      if level <= upper
        if counter.chars > 0
          headline_array.push(counter)
        end
        headline = l
        counter = Counter.new(
          level: level,
          headline: headline,
          lines: 1,
          chars: headline.size,
          list_lines: 0,
          text_lines: 1
        )
        next
      end
    end

    counter.lines += 1
    counter.chars += l.size

    if listmode
      # code list: calculate line wrapping
      counter.list_lines += calc_line_wrapping(l, mode: :list)
    else
      # normal paragraph: calculate line wrapping
      counter.text_lines += calc_line_wrapping(l, mode: :text)
    end
  end
  headline_array.push(counter)

  total = calc_total_count(name, headline_array)
  headline_array.unshift(total)
end
parse_options(args) click to toggle source
# File lib/review/tocprinter.rb, line 269
def parse_options(args)
  opts = OptionParser.new
  opts.version = ReVIEW::VERSION
  opts.on('--yaml=YAML', 'Read configurations from YAML file.') { |yaml| @yamlfile = yaml }
  opts.on('-y', '--only file1,file2,...', 'list only specified files.') do |v|
    @buildonly = v.split(/\s*,\s*/).map { |m| m.strip.sub(/\.re\Z/, '') }
  end
  opts.on('-l', '--level N', 'list upto N level (default=4)') do |n|
    @upper = n.to_i
  end
  opts.on('-d', '--detail', 'show characters and lines of each section.') do
    @detail = true
  end
  opts.on('--noindent', "don't indent headlines.") do
    @indent = nil
  end
  opts.on('--help', 'print this message and quit.') do
    puts opts.help
    exit 0
  end
  begin
    opts.parse!(args)
  rescue OptionParser::ParseError => e
    @logger.error e.message
    $stderr.puts opts.help
    exit 1
  end
end
print_result(result_array) click to toggle source