Markdown TOC in Ruby
A complete script: parse headings and emit a nested contents list.
#!/usr/bin/env ruby
# Build a nested table of contents from markdown headings.
DOC = <<~MARKDOWN
# Getting started
## Install
## First run
# Concepts
## Tours and sets
### Stars
# FAQ
MARKDOWN
entries = DOC.lines.filter_map do |line|
next unless line =~ /\A(#+)\s+(.+)/
depth = Regexp.last_match(1).length
title = Regexp.last_match(2).strip
slug = title.downcase.gsub(/[^a-z0-9]+/, "-")
[depth, title, slug]
end
entries.each do |depth, title, slug|
puts "#{" " * (depth - 1)}- [#{title}](##{slug})"
end
puts "#{entries.length} headings"
How it works
filter_mapkeeps only lines the heading regexp matches.Regexp.last_matchpulls out the depth and the title.gsubslugifies titles; indentation comes from heading depth.
Keywords and builtins used here
doendnextputsunless
The run, in numbers
- Lines
- 26
- Characters to type
- 541
- Tokens
- 125
- Three-star pace
- 75 tpm
At the three-star pace of 75 tokens a minute, this run takes about 100 seconds.
Step 2 of 2 in Encore, step 29 of 29 in Language basics.