Class: TermIndex

Inherits:
Object
  • Object
show all
Defined in:
lib/asciidoctor/autoterm/converter.rb

Instance Method Summary collapse

Instance Method Details

#collect_terms(terminology) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/asciidoctor/autoterm/converter.rb', line 109

def collect_terms(terminology)
  terms_by_full_name_with_abbr_and_definition = {}
  terminology_present = !terminology.empty?

  @index.categories.each do |category|
    category.terms.each do |term_obj|
      term_name = term_obj.name

      # AsciiDoc's ((Full Term (Abbr))) indexterm syntax matches the FIRST ))
      # encountered, so nested parens like (Abbr) lose their closing ).
      # The regex matches (Abbr with or without a closing ) to handle both.
      if term_name =~ /(.*?)\s+\(([^)]+)\)?$/
        full_name = $1.strip
        abbr = $2.strip
      else
        full_name = term_name
        abbr = nil
      end

      definition_entry = terminology[full_name]
      definition = definition_entry ? definition_entry[:definition] : nil

      if abbr.nil? && (!terminology_present || definition.nil_or_empty?)
        next
      end

      terms_by_full_name_with_abbr_and_definition[full_name] = {
        abbr: abbr,
        definition: definition
      }
    end
  end

  terms_by_full_name_with_abbr_and_definition
end

#convert_index_section(node) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/asciidoctor/autoterm/converter.rb', line 7

def convert_index_section(node)
  if node.attributes['type'] == 'terminology'
    use_custom_definitions = node.document.attr('terminology-use-definitions', 'false').to_s.downcase != 'false'
    terminology = use_custom_definitions ? parse_terminology_from_ast(node.document) : {}
    terms_by_full_name_with_abbr_and_definition = collect_terms(terminology)

    convert_terminology_entries(terms_by_full_name_with_abbr_and_definition) unless terms_by_full_name_with_abbr_and_definition.empty?
    nil
  else
    super
  end
end

#convert_terminology_entries(terms_by_full_name_with_abbr_and_definition) ⇒ Object



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
70
71
72
73
74
75
76
77
# File 'lib/asciidoctor/autoterm/converter.rb', line 20

def convert_terminology_entries(terms_by_full_name_with_abbr_and_definition)
  sorted_terms = terms_by_full_name_with_abbr_and_definition.sort_by do |full_term, details|
    abbr = details[:abbr]
    (abbr.nil_or_empty? ? full_term : abbr).downcase
  end

  grouped_terms = sorted_terms.group_by { |full_term, _details| full_term[0].upcase }
  sorted_letters = grouped_terms.keys.sort

  line_metrics = calc_line_metrics @base_line_height
  space_needed_for_letter = @theme.description_list_term_spacing + (2 * (height_of_typeset_text 'A'))

  sorted_letters.each do |letter|
    bounds.move_past_bottom if space_needed_for_letter > cursor

    ink_prose letter,
      align: :left,
      inline_format: false,
      margin_bottom: @theme.description_list_term_spacing,
      style: :bold

    grouped_terms[letter].each do |full_term, details|
      abbreviation = details[:abbr]
      definition = details[:definition]

      if abbreviation
        term_text = abbreviation
        desc_text = full_term
        desc_text += "#{definition}" unless definition.nil_or_empty?
      else
        term_text = full_term
        desc_text = definition || ''
      end

      entry_height = height_of_typeset_text term_text
      bounds.move_past_bottom if entry_height > cursor

      term_width = bounds.width * 0.15
      start_cursor = cursor

      float do
        indent 0 do
          typeset_formatted_text [{ text: term_text, color: @font_color }], line_metrics, align: :left
        end
      end

      indent term_width do
        typeset_formatted_text [{ text: desc_text, color: @font_color }], line_metrics, align: :left
      end

      move_down 4.24
    end

    @theme.prose_margin_bottom > cursor ? bounds.move_past_bottom : (move_down @theme.prose_margin_bottom)
  end

  start_new_page unless at_page_top?
end

#parse_terminology_from_ast(document) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/asciidoctor/autoterm/converter.rb', line 79

def parse_terminology_from_ast(document)
  terminology = {}

  terminology_tables = document.find_by do |block|
    block.context == :table && block.has_role?('terminology')
  end

  if terminology_tables.any?
    first_table = terminology_tables.first
    if first_table.rows && first_table.rows.body
      first_table.rows.body.each do |row|
        full_term = row[0].text.strip
        definition = row[2].text.strip

        if full_term && definition
          terminology[full_term] = { definition: definition }
        else
          log :warn, %(Skipping invalid row with missing data: #{row.inspect})
        end
      end
    else
      log :warn, %(No rows found in the table with .terminology role.)
    end
  else
    log :info, %(No tables with .terminology role found in the document.)
  end

  terminology
end