If you’re using Markdown, and just looking for a standard Table of Contents, the RedCarpet Markdown renderer has that built in.
Add gem 'redcarpet' to your Gemfile and run bundle install.
Inside your config.rb:
set :markdown_engine, :redcarpet
set :markdown, with_toc_data: true
helpers do
  def table_of_contents(resource)
    content = File.read(resource.source_file)
    toc_renderer = Redcarpet::Render::HTML_TOC.new
    markdown = Redcarpet::Markdown.new(toc_renderer, nesting_level: 2) # nesting_level is optional
    markdown.render(content)
  end
end
Inside your layout.erb, you can place the Table of Contents anywhere:
<%= table_of_contents(current_page) %>
This will work well-enough if you’re using plain Markdown.
If you’re not using Markdown, or want to roll your own solution, there’s essentially two approaches:
- Top-down: render the page and parse the result to extract the headings.
 
- Bottom-up: customise the renderer to handle your extensions.
 
I would recommend a bottom-up approach, but I’ll cover the top-down first.
A top-down approach is fairly straightforward, but slow and perhaps more tightly coupled with your page. You can do this by rendering the resource’s markup and parsing the result with a library like Nokogiri.
Add gem 'nokogiri' to your Gemfile and run bundle install.
Inside your config.rb:
require 'nokogiri'
helpers do
  def body_for(resource)
    resource.render(layout: nil)
  end
  def doc_for(resource)
    html = body_for(resource)
    Nokogiri::HTML::DocumentFragment.parse(html)
  end
  def toc_link(heading)
    content_tag(:a, heading.text, href: "#" + heading[:id])
  end
  def toc_item(heading)
    content_tag(:li, toc_link(heading))
  end
  def heading_nodes(resource)
    doc_for(resource).css('h2')
  end
  def table_of_contents(resource)
    list = heading_nodes(resource).map do |heading|
      toc_item(heading)
    end.join
    
    content_tag(:ul, list)
  end
end
This will work, assuming your page’s rendered HTML has headings with ids (if you’re using Markdown, it’s often an option with the renderer – see RedCarpet’s with_toc_data option above):
<h2 id="a-heading">A heading</h2>
<h2 id="b-heading">B heading</h2>
As above, you could then put the following in your layout.erb (calling this in your page would cause an infinite rendering loop):
<%= table_of_contents(current_page) %>
This will work in a pinch, but if you need more fine-grained control you might find it better to extend the renderer directly. RedCarpet, for instance, supports extending Markdown in a number of ways.
Hope that helps!