aboutsummaryrefslogtreecommitdiffstats
path: root/guides/rails_guides/indexer.rb
blob: 576ec85b278643ca87b24c509f0e6079bfd36953 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# frozen_string_literal: true

require "active_support/core_ext/object/blank"
require "active_support/core_ext/string/inflections"

module RailsGuides
  class Indexer
    attr_reader :body, :result, :warnings, :level_hash

    def initialize(body, warnings)
      @body     = body
      @result   = @body.dup
      @warnings = warnings
    end

    def index
      @level_hash = process(body)
    end

    private
      def process(string, current_level = 3, counters = [1])
        s = StringScanner.new(string)

        level_hash = {}

        while !s.eos?
          re = %r{^h(\d)(?:\((#.*?)\))?\s*\.\s*(.*)$}
          s.match?(re)
          if matched = s.matched
            matched =~ re
            level, idx, title = $1.to_i, $2, $3.strip

            if level < current_level
              # This is needed. Go figure.
              return level_hash
            elsif level == current_level
              index = counters.join(".")
              idx ||= "#" + title_to_idx(title)

              raise "Parsing Fail" unless @result.sub!(matched, "h#{level}(#{idx}). #{index} #{title}")

              key = {
                title: title,
                id: idx
              }
              # Recurse
              counters << 1
              level_hash[key] = process(s.post_match, current_level + 1, counters)
              counters.pop

              # Increment the current level
              last = counters.pop
              counters << last + 1
            end
          end
          s.getch
        end
        level_hash
      end

      def title_to_idx(title)
        idx = title.strip.parameterize.sub(/^\d+/, "")
        if warnings && idx.blank?
          puts "BLANK ID: please put an explicit ID for section #{title}, as in h5(#my-id)"
        end
        idx
      end
  end
end