Class: Ligarb::Chapter

Inherits:
Object
  • Object
show all
Defined in:
lib/ligarb/chapter.rb

Defined Under Namespace

Classes: CiteEntry, CrossReferenceError, Heading, IndexEntry

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, base_dir, slug_prefix: nil) ⇒ Chapter

Returns a new instance of Chapter.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/ligarb/chapter.rb', line 17

def initialize(path, base_dir, slug_prefix: nil)
  @path     = path
  @base_dir = base_dir
  @source   = File.read(path)
  @number   = nil
  @appendix_letter = nil
  @part_title = false
  @cover = false

  @relative_path = nil
  base_slug = File.basename(path, ".md").gsub(/[^a-zA-Z0-9_-]/, "-")
  @slug = slug_prefix ? "#{slug_prefix}#{base_slug}" : base_slug
  parse!
end

Instance Attribute Details

#appendix_letterObject

Returns the value of attribute appendix_letter.



10
11
12
# File 'lib/ligarb/chapter.rb', line 10

def appendix_letter
  @appendix_letter
end

#cite_entriesObject (readonly)

Returns the value of attribute cite_entries.



10
11
12
# File 'lib/ligarb/chapter.rb', line 10

def cite_entries
  @cite_entries
end

#coverObject

Returns the value of attribute cover.



11
12
13
# File 'lib/ligarb/chapter.rb', line 11

def cover
  @cover
end

#headingsObject (readonly)

Returns the value of attribute headings.



10
11
12
# File 'lib/ligarb/chapter.rb', line 10

def headings
  @headings
end

#htmlObject (readonly)

Returns the value of attribute html.



10
11
12
# File 'lib/ligarb/chapter.rb', line 10

def html
  @html
end

#index_entriesObject (readonly)

Returns the value of attribute index_entries.



10
11
12
# File 'lib/ligarb/chapter.rb', line 10

def index_entries
  @index_entries
end

#numberObject

Returns the value of attribute number.



10
11
12
# File 'lib/ligarb/chapter.rb', line 10

def number
  @number
end

#part_titleObject

Returns the value of attribute part_title.



11
12
13
# File 'lib/ligarb/chapter.rb', line 11

def part_title
  @part_title
end

#relative_pathObject

Returns the value of attribute relative_path.



11
12
13
# File 'lib/ligarb/chapter.rb', line 11

def relative_path
  @relative_path
end

#slugObject (readonly)

Returns the value of attribute slug.



10
11
12
# File 'lib/ligarb/chapter.rb', line 10

def slug
  @slug
end

#titleObject (readonly)

Returns the value of attribute title.



10
11
12
# File 'lib/ligarb/chapter.rb', line 10

def title
  @title
end

Class Method Details

.generate_id(text) ⇒ Object



50
51
52
53
54
55
# File 'lib/ligarb/chapter.rb', line 50

def self.generate_id(text)
  text.downcase
      .gsub(/[^\p{L}\p{N}\s_-]/u, "")
      .strip
      .gsub(/\s+/, "-")
end

Instance Method Details

#cover?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/ligarb/chapter.rb', line 46

def cover?
  @cover
end

#display_titleObject



90
91
92
93
94
95
96
97
98
# File 'lib/ligarb/chapter.rb', line 90

def display_title
  if @appendix_letter
    "#{@appendix_letter}. #{@title}"
  elsif @number
    "#{@number}. #{@title}"
  else
    @title
  end
end

#part_title?Boolean

Returns:

  • (Boolean)


42
43
44
# File 'lib/ligarb/chapter.rb', line 42

def part_title?
  @part_title
end

#resolve_cross_references!(chapter_map) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/ligarb/chapter.rb', line 57

def resolve_cross_references!(chapter_map)
  source_dir = File.dirname(@path)

  @html = @html.gsub(%r{<a\s+href="((?!https?://)[^"]+\.md)(?:#([^"]*))?">(.*?)</a>}m) do
    href_path = $1
    fragment = $2
    link_text = $3

    target_path = File.expand_path(href_path, source_dir)
    entry = chapter_map[target_path]
    unless entry
      line_no = @source.each_line.with_index(1) { |line, i| break i if line.include?(href_path) }
      loc = line_no ? "#{@path}:#{line_no}" : File.basename(@path)
      raise CrossReferenceError, "cross-reference target not found: #{href_path} (from #{loc})\n  link text: #{link_text.empty? ? "(auto)" : link_text}\n  resolved to: #{target_path}"
    end

    if fragment && !fragment.empty?
      normalized = self.class.generate_id(fragment)
      heading = entry[:headings][normalized]
      unless heading
        raise CrossReferenceError, "cross-reference heading not found: #{href_path}##{fragment} (from #{File.basename(@path)})"
      end
      anchor = "#{entry[:slug]}--#{heading.id}"
      text = link_text.empty? ? heading.display_text : link_text
    else
      anchor = entry[:slug]
      text = link_text.empty? ? entry[:chapter].display_title : link_text
    end

    %(<a href="##{anchor}">#{text}</a>)
  end
end