| The End | Top | Appendices and Ephemera | 
This just in
I’m using this setup for a book I’m trying to write about software development (surprise!). I’m having to change some things in the setup and script, and as I notice important ones, I’ll add a note here in the “This just in” section.
In the book, I’m using two levels of outline (so far), so I have some Markdown headers with just one pound sign, and some with two. And I wanted the table of contents to reflect that, using an outline structure that looks like this:
The indented bits are done, in Markdown, by putting four spaces for each level, before the asterisk that means list item. My table of contents maker wasn’t that clever, so I added some logic to strip pound signs differently, save the leading ones, and convert them to spaces at the last minute. I also needed to change the way the top of page / bottom of page links were parsed.
The resulting code is here:
#!/usr/bin/ruby
#!/Users/ron/.rvm/rubies/ruby-2.3.0/bin/ruby
require 'tempfile'
require 'fileutils'
SPLIT_MARKER = "----\n\n"
TOC_MARKER = "<!--TOC-->\n"
SCRIPT_FILE = "/Users/ron/Dropbox/bin/splitter"
TAB = '    '
Titles = {}
def add_toc(chunk)
  halves = chunk.split(TOC_MARKER)
  puts "halves length %d" % halves.length
  return chunk if halves.length != 2
  return halves[0] + table_of_contents + halves[1]
end
def make_file_name(filenumber)
  return "index.md" if filenumber == 0
  return sprintf("%02d.md", filenumber)
end
def make_link_line(filenumber, max_length)
  link = ""
  link += "[%s](%02d.html) | " % [trim_left(Titles[filenumber - 1]), filenumber - 1] unless filenumber == 0
  link += "[Top](index.html) | "
  link += "[%s](%02d.html)" % [trim_left(Titles[filenumber + 1]), filenumber + 1] unless filenumber >= max_length
  return link
end
def record_titles(chunks)
  filenumber = 0
  chunks.each do | chunk |
    title = chunk.split("\n")[0].strip # remove any spaces
    Titles[filenumber] = trim_right(title) # remove trailing stuff
    filenumber += 1
  end
end
def trim_full(string)
  trim_left(trim_right(string))
end
def trim_right(string)
  string.gsub(/ *#*$/, '')
end
def trim_left(string)
  string.gsub(/^#* */, '')
end
def table_of_contents
  toc = ""
  Titles.each_pair do | number, title |
    # looks like: ### title
    pounds, *rest = title.split(' ')
    the_title = rest.join(' ')
    tabs = pounds.gsub(/#/, '    ')
    tabs = tabs[4..-1] # remove one set
    toc += "%s* [%s](%s)\n" % [tabs, the_title, make_file_name(number)] 
  end
  return toc
end
def update_table_of_contents(chunks)
  toc_chunk = chunks.delete_at(0)
  updated_toc = add_toc(toc_chunk)
  chunks.insert(0, updated_toc)
end
def write_file(chunk, reference_chunk, filenumber, max_length)
  filename = make_file_name(filenumber)
  title = Titles[filenumber]
  puts filename + ": " + title
  tf = File.new(filename, "w")
  tf.puts make_link_line(filenumber, max_length)
  tf.puts
  tf.print chunk
  tf.puts
  tf.puts
  tf.puts make_link_line(filenumber, max_length)
  tf.puts
  tf.puts
  tf.print reference_chunk
  tf.puts
  tf.puts
  tf.close
end
def write_files(chunks, reference_chunk)
  filenumber = 0
  chunks.each do |chunk|
    write_file(chunk, reference_chunk, filenumber, chunks.length - 1) unless chunk.length < 1
    filenumber += 1
  end
end
ARGF.set_encoding(Encoding::UTF_8) 
input = ARGF.read
chunks = input.split(SPLIT_MARKER)
reference_chunk = chunks.delete_at(-1)
record_titles(chunks)
update_table_of_contents(chunks)
write_files(chunks, reference_chunk)
FileUtils.cp(SCRIPT_FILE, ".")
I expect that I may go to more than two levels, and I think the above code will handle that.
At present, the splitter only looks for table of contents headings right after a page separator. I can imagine that it might need to be changed to search for all headings in the whole document. We’ll see.
Stay tuned for any other important changes!
| The End | Top | Appendices and Ephemera |