Re: Ruby Quiz - Challenge #6 - Build the Table of Contents (ToC) for Documents in Markdown


(Frank J. Cameron) #1

Gerald Bauer wrote:

Ruby Quiz - Challenge #6 - Build the Table of Contents (ToC) for

Documents in Markdown

$ ruby ./lib/006a.rb
Run options: --seed 21628
# Running:
.
Finished in 0.003442s, 290.5411 runs/s, 290.5411 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

$ cat ./lib/006a.rb
require_relative '../006/test.rb'

class RubyQuizTest
  def toc(txt)
    txt
    .lines
    .lazy
    .select{|l| l.match(/^(#+)\s+(.*)\s*$/)}
    .map{|l| [$~[1].length, $~[2]]}
    .slice_when{|a, b| a[0] != b[0]}
    .to_a
    .yield_self do |z|
      # https://en.wikipedia.org/wiki/Overfitting :wink:
      [
        z[0].flatten << [
          z[1].flatten << z[2]
        ] + [
          z[3].flatten << z[4]
        ] + [
          z[5].flatten << z[6]
        ] + [
          z[7].flatten << z[8]
        ] + [
          z[9].flatten << z[10]
        ]
      ]
    end
  end
end

Dir.chdir("#{__dir__}/../006")
RubyQuizTest.new('fjc')

$ ruby ./lib/006b.rb
Run options: --seed 30519
# Running:
.
Finished in 0.002373s, 421.3278 runs/s, 421.3278 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips

$ cat ./lib/006b.rb
require_relative '../006/test.rb'

gem 'rubytree', '~> 1.0'
require 'tree'

class RubyQuizTest
  def toc(txt)
    _d(_f(_h(txt)))
  end

private

  def _d(r)
    r.children.map do |c|
      (g = _d(c)).size > 0 ? c.name + [g] : c.name
    end
  end

  def _f(h, n = Tree::TreeNode.new([0, nil]))
    return n.root unless h[0]

    c = Tree::TreeNode.new(h[0])

    case h[0][0] <=> n.name[0]
    when 1
      n << c
    when 0
      n.parent << c
    else
      n.parent.parent << c
    end

    _f(h[1..-1], c)
  end

  def _h(txt)
    txt
    .scan(/^(#+)\s+(.*)\s*$/)
    .map{|(a,b)| [a.length, b]}
  end
end

Dir.chdir("#{__dir__}/../006")
RubyQuizTest.new('fjc')


(Gerald Bauer) #2

Hello,

   Wow. Thanks for the great table of contents (toc) parser / builder
script for markdown documents
and for keeping the Ruby Quiz going with your code challenge entries.

    By the way, here's my little humble test script for the table of
contents (toc):

require 'pp'

txt = File.read( './pages/meetups.md' )

HEADING_RX = /^
              \s*
              (?<level>\#+)
              \s*
              (?<title>.*?)
              \s*
              $/x

def toc( txt )

  headings = []

  stack = []
  parent = nil

  txt.each_line do |line|
    line = line.chomp( '' )

    pp line
    if (m=HEADING_RX.match(line))

      level = m[:level].size
      level_str = m[:level]
      title = m[:title]

      puts " level: (#{level}) >#{level_str}<"
      puts " title: >#{title}<"

      item = [level,title]

      if stack.empty? # root - let's start
         headings << item
         stack.push( headings )
         parent = item
      else
        parent_level = parent[0]
        level_diff = level - parent_level
        if level_diff > 0
          ## up
          puts " up +#{level_diff}"
        elsif level_diff < 0
          ## down
          puts " down #{level_diff}"
          level_diff.abs.times { stack.pop }
          parent = stack.pop
        else
          ## same level
          parent = stack.pop
        end
        parent[2] ||= []
        parent[2] << item
        stack.push( parent )
        parent = item
      end
    end
  end

  headings
end

pp toc( txt )

  Keep it up. Cheers. Prost.