Almirah 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,20 +1,22 @@
1
- require_relative "text_line"
1
+ # frozen_string_literal: true
2
2
 
3
- class DocItem < TextLine
4
- attr_accessor :parent_doc
5
- attr_accessor :parent_heading
6
-
7
- @parent_doc = nil
8
- @parent_heading = nil
9
-
10
- @@html_table_render_in_progress = false
11
-
12
- def get_url
13
- ''
14
- end
15
- end
3
+ require_relative 'text_line'
16
4
 
5
+ class DocItem < TextLine # rubocop:disable Style/Documentation
6
+ attr_accessor :parent_doc, :parent_heading
17
7
 
8
+ @parent_doc = nil
9
+ @parent_heading = nil
18
10
 
11
+ @@html_table_render_in_progress = false # rubocop:disable Style/ClassVars
19
12
 
13
+ def initialize(doc)
14
+ super()
15
+ @parent_doc = doc
16
+ @parent_heading = doc.headings[-1]
17
+ end
20
18
 
19
+ def get_url
20
+ ''
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ require 'yaml'
2
+
3
+ class Frontmatter
4
+ attr_accessor :parameters
5
+
6
+ def initialize(yaml_text_line)
7
+ @parameters = YAML.safe_load(yaml_text_line)
8
+ end
9
+ end
@@ -8,9 +8,7 @@ class MarkdownList < DocItem
8
8
  @@lists_stack = []
9
9
 
10
10
  def initialize(doc, is_ordered)
11
- super()
12
- @parent_doc = doc
13
- @parent_heading = doc.headings[-1]
11
+ super(doc)
14
12
 
15
13
  @rows = []
16
14
  @is_ordered = is_ordered
@@ -21,7 +19,7 @@ class MarkdownList < DocItem
21
19
  @@lists_stack.push(self)
22
20
  end
23
21
 
24
- def addRow(raw_text)
22
+ def add_row(raw_text)
25
23
  pos = calculate_text_position(raw_text)
26
24
  row = raw_text[pos..-1]
27
25
 
@@ -44,7 +42,7 @@ class MarkdownList < DocItem
44
42
  prev_lists_stack_item.rows[-1] = nested_list
45
43
  end
46
44
 
47
- nested_list.addRow(raw_text)
45
+ nested_list.add_row(raw_text)
48
46
 
49
47
  elsif pos < @@lists_stack[-1].indent_position
50
48
 
@@ -6,9 +6,7 @@ class MarkdownTable < DocItem
6
6
  attr_accessor :column_names, :rows, :heading_row, :is_separator_detected
7
7
 
8
8
  def initialize(doc, heading_row)
9
- super()
10
- @parent_doc = doc
11
- @parent_heading = doc.headings[-1]
9
+ super(doc)
12
10
  @heading_row = heading_row
13
11
 
14
12
  res = /^[|](.*[|])/.match(heading_row)
@@ -21,7 +19,7 @@ class MarkdownTable < DocItem
21
19
  @is_separator_detected = false
22
20
  end
23
21
 
24
- def addRow(row)
22
+ def add_row(row)
25
23
  columns = row.split('|')
26
24
  @rows.append(columns.map!(&:strip))
27
25
  true
@@ -1,27 +1,25 @@
1
- require_relative "doc_item"
1
+ require_relative 'doc_item'
2
2
 
3
3
  class Paragraph < DocItem
4
+ attr_accessor :text
4
5
 
5
- attr_accessor :text
6
+ def initialize(doc, text)
7
+ super(doc)
8
+ @text = text.strip
9
+ end
6
10
 
7
- def initialize(doc, text)
8
- @parent_doc = doc
9
- @parent_heading = doc.headings[-1]
10
- @text = text
11
- end
11
+ def getTextWithoutSpaces
12
+ @text.split.join('-').downcase
13
+ end
12
14
 
13
- def getTextWithoutSpaces
14
- return @text.split.join('-').downcase
15
+ def to_html
16
+ s = ''
17
+ if @@html_table_render_in_progress
18
+ s += '</table>'
19
+ @@html_table_render_in_progress = false
15
20
  end
16
21
 
17
- def to_html
18
- s = ''
19
- if @@html_table_render_in_progress
20
- s += "</table>"
21
- @@html_table_render_in_progress = false
22
- end
23
-
24
- s += "<p>" + format_string(@text)
25
- return s
26
- end
27
- end
22
+ s += "<p>#{format_string(@text)}"
23
+ s
24
+ end
25
+ end
@@ -11,15 +11,53 @@ require_relative 'doc_items/controlled_table'
11
11
  require_relative 'doc_items/image'
12
12
  require_relative 'doc_items/markdown_list'
13
13
  require_relative 'doc_items/doc_footer'
14
+ require_relative 'doc_items/frontmatter'
15
+
16
+ class DocParser # rubocop:disable Metrics/ClassLength,Style/Documentation
17
+ def self.try_to_extract_frontmatter(doc, text_lines) # rubocop:disable Metrics/MethodLength
18
+ lines_to_remove = 0
19
+ frontmatter_lines = ''
20
+ if /^(-{3,})/.match(text_lines[0])
21
+ frontmatter_started = false
22
+ text_lines.each do |s|
23
+ lines_to_remove += 1
24
+ if /^(-{3,})/.match(s)
25
+ if frontmatter_started
26
+ doc.frontmatter = Frontmatter.new(frontmatter_lines)
27
+ frontmatter_started = false
28
+ break
29
+ else
30
+ frontmatter_started = true
31
+ end
32
+ elsif frontmatter_started
33
+ frontmatter_lines += s
34
+ end
35
+ end
36
+ end
37
+ text_lines.shift(lines_to_remove)
38
+ text_lines
39
+ end
14
40
 
15
- class DocParser
16
41
  def self.parse(doc, text_lines)
17
42
  temp_md_table = nil
18
43
  temp_md_list = nil
19
44
  temp_code_block = nil
20
45
  # restart section numbering for each new document
21
46
  Heading.reset_global_section_number
22
-
47
+ # try to get frontmatter first
48
+ text_lines = try_to_extract_frontmatter(doc, text_lines)
49
+ # There is no document without heading
50
+ title = "#{doc.id}.md"
51
+ item = Heading.new(doc, title, 0)
52
+ doc.items.append(item)
53
+ doc.headings.append(item)
54
+ doc.title = title
55
+ # replace dummy title with extracted from frontmatter
56
+ if doc.frontmatter && (doc.frontmatter.parameters.key? 'title')
57
+ doc.title = doc.frontmatter.parameters['title']
58
+ doc.headings[0].text = doc.frontmatter.parameters['title']
59
+ end
60
+ # main loop
23
61
  text_lines.each do |s|
24
62
  if s.lstrip != ''
25
63
  if res = /^(\#{1,})\s(.*)/.match(s) # Heading
@@ -33,10 +71,6 @@ class DocParser
33
71
  level = res[1].length
34
72
  value = res[2]
35
73
 
36
- if level == 1 && doc.title == ''
37
- doc.title = value
38
- end
39
-
40
74
  item = Heading.new(doc, value, level)
41
75
  doc.items.append(item)
42
76
  doc.headings.append(item)
@@ -45,13 +79,9 @@ class DocParser
45
79
 
46
80
  title = res[1]
47
81
 
48
- if doc.title == ''
49
- doc.title = title
50
- end
51
-
52
- item = Heading.new(doc, title, 0)
53
- doc.items.append(item)
54
- doc.headings.append(item)
82
+ # Rewrite
83
+ doc.title = title
84
+ doc.headings[0].text = title
55
85
 
56
86
  elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
57
87
 
@@ -72,12 +102,10 @@ class DocParser
72
102
  if tmp.length > 0
73
103
  up_links = []
74
104
  tmp.each do |ul|
75
- lnk = ul[0]
105
+ lnk = ul[0]
76
106
  # do not add links for the self document
77
107
  doc_id = /([a-zA-Z]+)-\d+/.match(lnk) # SRS
78
- if (doc_id) and (doc_id[1].downcase != doc.id.downcase)
79
- up_links << lnk.upcase
80
- end
108
+ up_links << lnk.upcase if doc_id and (doc_id[1].downcase != doc.id.downcase)
81
109
  # try to find the real end of text
82
110
  pos = text.index(lnk)
83
111
  first_pos = pos if pos < first_pos
@@ -95,7 +123,7 @@ class DocParser
95
123
  item = ControlledParagraph.new(doc, text, id)
96
124
 
97
125
  if up_links
98
- up_links.uniq! #remove duplicates
126
+ up_links.uniq! # remove duplicates
99
127
  doc.items_with_uplinks_number += 1 # for statistics
100
128
  up_links.each do |ul|
101
129
  next unless tmp = />\[(\S*)\]$/.match(ul) # >[SRS-001]
@@ -146,36 +174,54 @@ class DocParser
146
174
 
147
175
  doc.items.append(item)
148
176
 
149
- elsif res = /^(\*\s+)(.*)/.match(s) # check if unordered list start
177
+ elsif res = /^(\*\s+)(.*)/.match(s) # check if unordered list start
178
+
179
+ if doc.title == ''
180
+ # dummy section if root is not a Document Title (level 0)
181
+ title = "#{doc.id}.md"
182
+ item = Heading.new(doc, title, 0)
183
+ doc.items.append(item)
184
+ doc.headings.append(item)
185
+ doc.title = title
186
+ end
150
187
 
151
188
  temp_md_table = process_temp_table(doc, temp_md_table)
152
189
 
153
190
  row = res[2]
154
191
 
155
192
  if temp_md_list
156
- temp_md_list.addRow(s)
193
+ temp_md_list.add_row(s)
157
194
  else
158
195
  item = MarkdownList.new(doc, false)
159
- item.addRow(s)
196
+ item.add_row(s)
160
197
  temp_md_list = item
161
198
  end
162
199
 
163
- elsif res = /^\d[.]\s(.*)/.match(s) # check if ordered list start
200
+ elsif res = /^\d[.]\s(.*)/.match(s) # check if ordered list start
164
201
 
165
202
  temp_md_table = process_temp_table(doc, temp_md_table)
166
203
 
167
204
  row = res[1]
168
205
 
169
206
  if temp_md_list
170
- temp_md_list.addRow(s)
207
+ temp_md_list.add_row(s)
171
208
  else
172
209
  item = MarkdownList.new(doc, true)
173
- item.addRow(s)
210
+ item.add_row(s)
174
211
  temp_md_list = item
175
212
  end
176
213
 
177
214
  elsif s[0] == '|' # check if table
178
215
 
216
+ if doc.title == ''
217
+ # dummy section if root is not a Document Title (level 0)
218
+ title = "#{doc.id}.md"
219
+ item = Heading.new(doc, title, 0)
220
+ doc.items.append(item)
221
+ doc.headings.append(item)
222
+ doc.title = title
223
+ end
224
+
179
225
  if temp_md_list
180
226
  doc.items.append temp_md_list
181
227
  temp_md_list = nil
@@ -184,8 +230,8 @@ class DocParser
184
230
  if res = /^[|](-{3,})[|]/.match(s) # check if it is a separator first
185
231
 
186
232
  if temp_md_table
187
- # separator is found after heading
188
- temp_md_table.is_separator_detected = true
233
+ # separator is found after heading
234
+ temp_md_table.is_separator_detected = true
189
235
  else
190
236
  # separator out of table scope consider it just as a regular paragraph
191
237
  item = Paragraph.new(doc, s)
@@ -208,7 +254,7 @@ class DocParser
208
254
  temp_md_table = ControlledTable.new(doc, temp_md_table)
209
255
  end
210
256
  end
211
- temp_md_table.addRow(row)
257
+ temp_md_table.add_row(row)
212
258
  else
213
259
  # replece table heading with regular paragraph
214
260
  item = Paragraph.new(doc, temp_md_table.heading_row)
@@ -257,6 +303,7 @@ class DocParser
257
303
  # start code block
258
304
  temp_code_block = CodeBlock.new(suggested_format)
259
305
  temp_code_block.parent_doc = doc
306
+ temp_code_block.parent_heading = doc.headings[-1]
260
307
  end
261
308
 
262
309
  elsif res = /^TODO:(.*)/.match(s) # check if TODO block
@@ -276,10 +323,11 @@ class DocParser
276
323
  doc.todo_blocks.append(item)
277
324
 
278
325
  else # Reqular Paragraph
326
+
279
327
  temp_md_table = process_temp_table(doc, temp_md_table)
280
328
  if temp_md_list
281
329
  if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
282
- temp_md_list.addRow(s)
330
+ temp_md_list.add_row(s)
283
331
  next
284
332
  else
285
333
  doc.items.append temp_md_list
@@ -314,7 +362,7 @@ class DocParser
314
362
  doc.items.append(item)
315
363
  end
316
364
 
317
- def self.process_temp_table(doc, temp_md_table) # rubocop:disable Metrics/MethodLength
365
+ def self.process_temp_table(doc, temp_md_table)
318
366
  if temp_md_table
319
367
  if temp_md_table.is_separator_detected
320
368
  doc.items.append temp_md_table
@@ -1,69 +1,64 @@
1
+ # frozen_string_literal: true
1
2
 
2
- class BaseDocument
3
+ class BaseDocument # rubocop:disable Style/Documentation
4
+ attr_accessor :title, :id, :dom, :headings
3
5
 
4
- attr_accessor :title
5
- attr_accessor :id
6
- attr_accessor :dom
6
+ def initialize
7
+ @items = []
8
+ @headings = []
9
+ @title = ''
10
+ @id = ''
11
+ @dom = nil
12
+ end
7
13
 
8
- def initialize()
9
- @items = Array.new
10
- @headings = Array.new
11
- @title = ""
12
- @id = ""
13
- @dom = nil
14
- end
15
-
16
- def save_html_to_file html_rows, nav_pane, output_file_path
17
-
18
- gem_root = File.expand_path './../../..', File.dirname(__FILE__)
19
- template_file = gem_root + "/lib/almirah/templates/page.html"
14
+ def save_html_to_file(html_rows, nav_pane, output_file_path) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
15
+ gem_root = File.expand_path './../../..', File.dirname(__FILE__)
16
+ template_file = "#{gem_root}/lib/almirah/templates/page.html"
20
17
 
21
- file = File.open( template_file )
22
- file_data = file.readlines
23
- file.close
18
+ file = File.open(template_file)
19
+ file_data = file.readlines
20
+ file.close
24
21
 
25
- if @id == 'index'
26
- output_file_path += "#{@id}.html"
27
- else
28
- output_file_path += "#{@id}/#{@id}.html"
22
+ output_file_path += if @id == 'index'
23
+ "#{@id}.html"
24
+ else
25
+ "#{@id}/#{@id}.html"
26
+ end
27
+ file = File.open(output_file_path, 'w')
28
+ file_data.each do |s| # rubocop:disable Metrics/BlockLength
29
+ if s.include?('{{CONTENT}}')
30
+ html_rows.each do |r|
31
+ file.puts r
29
32
  end
30
- file = File.open( output_file_path, "w" )
31
- file_data.each do |s|
32
- if s.include?('{{CONTENT}}')
33
- html_rows.each do |r|
34
- file.puts r
35
- end
36
- elsif s.include?('{{NAV_PANE}}')
37
- if nav_pane
38
- file.puts nav_pane.to_html
39
- end
40
- elsif s.include?('{{DOCUMENT_TITLE}}')
41
- file.puts s.gsub! '{{DOCUMENT_TITLE}}', @title
42
- elsif s.include?('{{STYLES_AND_SCRIPTS}}')
43
- if @id == 'index'
44
- file.puts '<script type="module" src="./scripts/orama_search.js"></script>'
45
- file.puts '<link rel="stylesheet" href="./css/search.css">'
46
- file.puts '<link rel="stylesheet" href="./css/main.css">'
47
- file.puts '<script src="./scripts/main.js"></script>'
48
- elsif self.instance_of? Specification
49
- file.puts '<link rel="stylesheet" href="../../css/main.css">'
50
- file.puts '<script src="../../scripts/main.js"></script>'
51
- elsif self.instance_of? Traceability
52
- file.puts '<link rel="stylesheet" href="../../css/main.css">'
53
- file.puts '<script src="../../scripts/main.js"></script>'
54
- elsif self.instance_of? Coverage
55
- file.puts '<link rel="stylesheet" href="../../css/main.css">'
56
- file.puts '<script src="../../scripts/main.js"></script>'
57
- elsif self.instance_of? Protocol
58
- file.puts '<link rel="stylesheet" href="../../../css/main.css">'
59
- file.puts '<script src="../../../scripts/main.js"></script>'
60
- end
61
- elsif s.include?('{{GEM_VERSION}}')
62
- file.puts "(" + Gem.loaded_specs['Almirah'].version.version + ")"
63
- else
64
- file.puts s
65
- end
33
+ elsif s.include?('{{NAV_PANE}}')
34
+ file.puts nav_pane.to_html if nav_pane
35
+ elsif s.include?('{{DOCUMENT_TITLE}}')
36
+ file.puts s.gsub! '{{DOCUMENT_TITLE}}', @title
37
+ elsif s.include?('{{STYLES_AND_SCRIPTS}}')
38
+ if @id == 'index'
39
+ file.puts '<script type="module" src="./scripts/orama_search.js"></script>'
40
+ file.puts '<link rel="stylesheet" href="./css/search.css">'
41
+ file.puts '<link rel="stylesheet" href="./css/main.css">'
42
+ file.puts '<script src="./scripts/main.js"></script>'
43
+ elsif instance_of? Specification
44
+ file.puts '<link rel="stylesheet" href="../../css/main.css">'
45
+ file.puts '<script src="../../scripts/main.js"></script>'
46
+ elsif instance_of? Traceability
47
+ file.puts '<link rel="stylesheet" href="../../css/main.css">'
48
+ file.puts '<script src="../../scripts/main.js"></script>'
49
+ elsif instance_of? Coverage
50
+ file.puts '<link rel="stylesheet" href="../../css/main.css">'
51
+ file.puts '<script src="../../scripts/main.js"></script>'
52
+ elsif instance_of? Protocol
53
+ file.puts '<link rel="stylesheet" href="../../../css/main.css">'
54
+ file.puts '<script src="../../../scripts/main.js"></script>'
66
55
  end
67
- file.close
56
+ elsif s.include?('{{GEM_VERSION}}')
57
+ file.puts "(#{Gem.loaded_specs['Almirah'].version.version})"
58
+ else
59
+ file.puts s
60
+ end
68
61
  end
69
- end
62
+ file.close
63
+ end
64
+ end
@@ -1,78 +1,80 @@
1
- require_relative "base_document"
1
+ require_relative 'base_document'
2
2
 
3
3
  class Coverage < BaseDocument
4
+ attr_accessor :top_doc, :bottom_doc, :covered_items, :passed_steps_number, :failed_steps_number
4
5
 
5
- attr_accessor :top_doc
6
- attr_accessor :bottom_doc
6
+ def initialize(top_doc)
7
+ super()
8
+ @top_doc = top_doc
9
+ @bottom_doc = nil
7
10
 
8
- def initialize(top_doc)
9
- super()
10
- @top_doc = top_doc
11
- @bottom_doc = bottom_doc
11
+ @id = top_doc.id + '-' + 'tests'
12
+ @title = 'Coverage Matrix: ' + @id
13
+ @covered_items = {}
14
+ @passed_steps_number = 0
15
+ @failed_steps_number = 0
16
+ end
12
17
 
13
- @id = top_doc.id + "-" + "tests"
14
- @title = "Coverage Matrix: " + @id
15
- end
16
-
17
- def to_console
18
- puts "\e[35m" + "Traceability: " + @id + "\e[0m"
19
- end
18
+ def to_console
19
+ puts "\e[35m" + 'Traceability: ' + @id + "\e[0m"
20
+ end
20
21
 
21
- def to_html(nav_pane, output_file_path)
22
+ def to_html(nav_pane, output_file_path)
23
+ html_rows = []
22
24
 
23
- html_rows = Array.new
25
+ html_rows.append('')
26
+ s = "<h1>#{@title}</h1>\n"
27
+ s += "<table class=\"controlled\">\n"
28
+ s += "\t<thead> <th>#</th> <th style='font-weight: bold;'>#{@top_doc.title}</th> <th>#</th> <th style='font-weight: bold;'>Test CaseId.StepId</th> </thead>\n"
29
+ html_rows.append s
24
30
 
25
- html_rows.append('')
26
- s = "<h1>#{@title}</h1>\n"
27
- s += "<table class=\"controlled\">\n"
28
- s += "\t<thead> <th>#</th> <th style='font-weight: bold;'>#{@top_doc.title}</th> <th>#</th> <th style='font-weight: bold;'>Test CaseId.StepId</th> </thead>\n"
29
- html_rows.append s
31
+ sorted_items = @top_doc.controlled_items.sort_by { |w| w.id }
30
32
 
31
- sorted_items = @top_doc.controlled_items.sort_by { |w| w.id }
33
+ sorted_items.each do |top_item|
34
+ row = render_table_row top_item
35
+ html_rows.append row
36
+ end
37
+ html_rows.append "</table>\n"
32
38
 
33
- sorted_items.each do |top_item|
34
- row = render_table_row top_item
35
- html_rows.append row
36
- end
37
- html_rows.append "</table>\n"
39
+ save_html_to_file(html_rows, nav_pane, output_file_path)
40
+ end
38
41
 
39
- self.save_html_to_file(html_rows, nav_pane, output_file_path)
40
-
41
- end
42
+ def render_table_row(top_item)
43
+ s = ''
44
+ if top_item.coverage_links
45
+ id_color = if top_item.coverage_links.length > 1
46
+ '' # "style='background-color: #fff8c5;'" # disabled for now
47
+ else
48
+ ''
49
+ end
50
+ top_item.coverage_links.each do |bottom_item|
51
+ s += "\t<tr>\n"
52
+ s += "\t\t<td class=\"item_id\" #{id_color}><a href=\"./../#{top_item.parent_doc.id}/#{top_item.parent_doc.id}.html##{top_item.id}\" class=\"external\">#{top_item.id}</a></td>\n"
53
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_item.text}</td>\n"
42
54
 
43
- def render_table_row(top_item)
44
- s = ""
45
- if top_item.coverage_links
46
- if top_item.coverage_links.length > 1
47
- id_color = "" # "style='background-color: #fff8c5;'" # disabled for now
48
- else
49
- id_color = ""
50
- end
51
- top_item.coverage_links.each do |bottom_item|
52
- s += "\t<tr>\n"
53
- s += "\t\t<td class=\"item_id\" #{id_color}><a href=\"./../#{top_item.parent_doc.id}/#{top_item.parent_doc.id}.html##{top_item.id}\" class=\"external\">#{top_item.id}</a></td>\n"
54
- s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_item.text}</td>\n"
55
-
56
- if bottom_item.columns[-2].text.downcase == "pass"
57
- test_step_color = "style='background-color: #cfc;'"
58
- elsif bottom_item.columns[-2].text.downcase == "fail"
59
- test_step_color = "style='background-color: #fcc;'"
60
- else
61
- test_step_color = ""
62
- end
55
+ test_step_color = if bottom_item.columns[-2].text.downcase == 'pass'
56
+ @passed_steps_number += 1
57
+ "style='background-color: #cfc;'"
58
+ elsif bottom_item.columns[-2].text.downcase == 'fail'
59
+ @failed_steps_number += 1
60
+ "style='background-color: #fcc;'"
61
+ else
62
+ ''
63
+ end
63
64
 
64
- s += "\t\t<td class=\"item_id\" #{test_step_color}><a href=\"./../../tests/protocols/#{bottom_item.parent_doc.id}/#{bottom_item.parent_doc.id}.html##{bottom_item.id}\" class=\"external\">#{bottom_item.id}</a></td>\n"
65
- s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{bottom_item.columns[1].text}</td>\n"
66
- s += "\t</tr>\n"
67
- end
68
- else
69
- s += "\t<tr>\n"
70
- s += "\t\t<td class=\"item_id\"><a href=\"./../#{top_item.parent_doc.id}/#{top_item.parent_doc.id}.html##{top_item.id}\" class=\"external\">#{top_item.id}</a></td>\n"
71
- s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_item.text}</td>\n"
72
- s += "\t\t<td class=\"item_id\"></td>\n"
73
- s += "\t\t<td class=\"item_text\" style='width: 42%;'></td>\n"
74
- s += "\t</tr>\n"
75
- end
76
- return s
65
+ s += "\t\t<td class=\"item_id\" #{test_step_color}><a href=\"./../../tests/protocols/#{bottom_item.parent_doc.id}/#{bottom_item.parent_doc.id}.html##{bottom_item.id}\" class=\"external\">#{bottom_item.id}</a></td>\n"
66
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{bottom_item.columns[1].text}</td>\n"
67
+ s += "\t</tr>\n"
68
+ @covered_items[top_item.id.to_s.downcase] = top_item
69
+ end
70
+ else
71
+ s += "\t<tr>\n"
72
+ s += "\t\t<td class=\"item_id\"><a href=\"./../#{top_item.parent_doc.id}/#{top_item.parent_doc.id}.html##{top_item.id}\" class=\"external\">#{top_item.id}</a></td>\n"
73
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_item.text}</td>\n"
74
+ s += "\t\t<td class=\"item_id\"></td>\n"
75
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'></td>\n"
76
+ s += "\t</tr>\n"
77
77
  end
78
+ s
79
+ end
78
80
  end