class TOCBot

To follow

Constants

VERSION

Public Class Methods

new(options = {}) click to toggle source
# File lib/TOCBot.rb, line 9
def initialize(options = {})
    @separator = '<!--TOCBot-->'
    @level = 1
    @depth = 5

    @separator = options[:separator] unless options[:separator].nil?
    @level = options[:level].to_i unless options[:level].nil?
    @depth = options[:depth].to_i unless options[:depth].nil?
end

Public Instance Methods

load_file(filename) click to toggle source
# File lib/TOCBot.rb, line 19
def load_file(filename)
    lines = []

    begin
        lines = File.readlines(filename).each(&:chomp!)
    rescue SystemCallError
        raise StandardError.new("Failed to open file #{filename} for reading")
    end
    return lines
end
process_file(filename) click to toggle source
# File lib/TOCBot.rb, line 112
def process_file(filename)
    spinners = TTY::Spinner::Multi.new("[:spinner] TOCBot is generating your Table of Contents (TOC) (Start Level: #{@level}, Depth: #{@depth})")

    sp1 = spinners.register '[:spinner] Loading File'
    sp2 = spinners.register '[:spinner] Processing File'
    sp3 = spinners.register '[:spinner] Writing File'

    sp1.auto_spin
    sp2.auto_spin
    sp3.auto_spin

    lines = load_file(filename)
    sp1.success

    processed, toc = process_lines(lines)
    sp2.success

    write_file(filename, processed, toc)
    sp3.success
end
process_lines(lines) click to toggle source
# File lib/TOCBot.rb, line 52
def process_lines(lines)
    processed = []
    toc = []

    skip_code_block = false
    strip_existing_toc = false
    lines.each do |line|
        line = line.strip

        #
        # Identify code blocks and ignore the contents
        #
        skip_code_block = !skip_code_block if line.start_with?('```')

        if skip_code_block
            processed << line
            next
        end

        #
        # Identify open/closing <!--TOC--> tags
        #
        strip_existing_toc = !strip_existing_toc if line == @separator

        #
        # Skip over effectively removing the existing TOC
        #
        next if strip_existing_toc && line.downcase != @separator.downcase

        #
        # Strip out relative links
        #
        next if line.start_with?('<a name="')

        if line.scan(/^\#{1,}.*/m).size.positive?

            m = line.match(/^(\#{1,})(.*)/)
            hashes = m[1].length
            text = m[2].strip

            if hashes >= @level
                hashes = hashes - @level + 1

                if hashes <= @depth
                    link = text.gsub(/ /, '-').downcase

                    toc << '     ' * (hashes - 1) + "* [#{text}](##{link})"
                    processed << "<a name=\"#{link}\"></a>"
                end
            end
        end

        #
        # Add the line to array - but also process it to see if it needs to go into the TOC
        #
        processed << line
    end
    return processed, toc
end
write_file(filename, processed, toc_list, permissions = 0o0644) click to toggle source
# File lib/TOCBot.rb, line 30
def write_file(filename, processed, toc_list, permissions = 0o0644)
    toc_done = false

    begin
        File.open(filename, 'w') do |f|
            processed.each do |line|
                f.puts line

                next unless line == @separator && !toc_done

                toc_list.each do |toc|
                    f.puts toc
                end
                toc_done = true
            end
            f.chmod(permissions)
        end
    rescue SystemCallError
        raise StandardError.new("Failed to open file #{filename} for writing")
    end
end