Almirah 0.1.1 → 0.1.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4194e03230075235a57516fed73b44215dde4a7cb42474b641bdbd7ce8a6ad55
4
- data.tar.gz: f1a4f05ca5b4cf643cd179019c67cb08ea69c8876a235dfa368e99ec782ab21f
3
+ metadata.gz: d7a10581e498b38097f10868900c903c9e3bad04bfb3e1d63170bada3222c65b
4
+ data.tar.gz: 70ac0c4e2893e69ae0aa6c146c4c7a1da2b4ddd7ae0249604bc0b9afcb4980dd
5
5
  SHA512:
6
- metadata.gz: 56dc9e44de93dccbaf9424d6b654c00e08591b9cdcd62b5061d3356441b68f3c5b6a61778cc9d78bcf277fceb8c25d1b6f9bf34ca6f1a0a0f0284ce361d346a2
7
- data.tar.gz: 59790d27191f78845e8b7ca8e19f0c26858234dbb419f248de5034a1aac3451ed9afbcc26905fa062c2efc13b0613f3a60e2b9e57b590c3f6cd01ff55df83809
6
+ metadata.gz: 9d2f2cfe15dd20b56c31cab7748304007497cbb4a03928df501b2628a261861003a8a0d576ff084ebd54128b03a5c521e6e1da94e8125f93e1233bee94a06ddc
7
+ data.tar.gz: ff4cbc8d03219cb9792a854dfabbe0b968a097b73e57fca89f0a027bcca11916c646dbca4e64539ea3ac3f6a0b6213d18b71e4e9e323e57a05d83240289bf057
@@ -8,11 +8,14 @@ require_relative "doc_items/doc_item"
8
8
  require_relative "doc_items/heading"
9
9
  require_relative "doc_items/paragraph"
10
10
  require_relative "doc_items/blockquote"
11
+ require_relative "doc_items/code_block"
12
+ require_relative "doc_items/todo_block"
11
13
  require_relative "doc_items/controlled_paragraph"
12
14
  require_relative "doc_items/markdown_table"
13
15
  require_relative "doc_items/controlled_table"
14
16
  require_relative "doc_items/image"
15
17
  require_relative "doc_items/markdown_list"
18
+ require_relative "doc_items/doc_footer"
16
19
 
17
20
  class DocFabric
18
21
 
@@ -38,6 +41,7 @@ class DocFabric
38
41
 
39
42
  tempMdTable = nil
40
43
  tempMdList = nil
44
+ tempCodeBlock = nil
41
45
 
42
46
  file = File.open( doc.path )
43
47
  file_lines = file.readlines
@@ -58,25 +62,32 @@ class DocFabric
58
62
 
59
63
  level = res[1].length
60
64
  value = res[2]
65
+
66
+ if level == 1 && doc.title == ""
67
+ doc.title = value
68
+ Heading.reset_global_section_number()
69
+ end
70
+
61
71
  item = Heading.new(value, level)
62
72
  item.parent_doc = doc
63
73
  doc.items.append(item)
64
74
  doc.headings.append(item)
65
-
66
- if level == 1 && doc.title == ""
67
- doc.title = value
68
- end
75
+
69
76
  elsif res = /^\%\s(.*)/.match(s) # Pandoc Document Title
70
77
 
71
78
  title = res[1]
79
+
80
+ if doc.title == ""
81
+ doc.title = title
82
+ Heading.reset_global_section_number()
83
+ end
84
+
72
85
  item = Heading.new(title, 1)
73
86
  item.parent_doc = doc
74
87
  doc.items.append(item)
75
88
  doc.headings.append(item)
76
89
 
77
- if doc.title == ""
78
- doc.title = title
79
- end
90
+ Heading.reset_global_section_number() # Pandoc Document Title is not a section, so it shall not be taken into account in numbering
80
91
 
81
92
  elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
82
93
 
@@ -91,35 +102,70 @@ class DocFabric
91
102
 
92
103
  id = res[1]
93
104
  text = res[2]
105
+ up_links = nil
106
+
107
+ #check if it contains the uplink (one or many)
108
+ #TODO: check this regular expression
109
+ first_pos = text.length # for trailing commas
110
+ tmp = text.scan( /(>\[(?>[^\[\]]|\g<0>)*\])/ ) # >[SRS-001], >[SYS-002]
111
+ if tmp.length >0
112
+ up_links = Array.new
113
+ tmp.each do |ul|
114
+ up_links.append(ul[0])
115
+ # try to find the real end of text
116
+ pos = text.index(ul[0])
117
+ if pos < first_pos
118
+ first_pos = pos
119
+ end
120
+ # remove uplink from text
121
+ text = text.split(ul[0]).join("")
122
+ end
123
+ # remove trailing commas and spaces
124
+ if text.length > first_pos
125
+ first_pos -= 1
126
+ text = text[0..first_pos].strip
127
+ end
128
+ end
94
129
 
95
- #check if it contains the uplink
96
- if tmp = /(.*)\s+>\[(\S*)\]$/.match(text) # >[SRS-001]
130
+ # since we already know id and text
131
+ item = ControlledParagraph.new( text, id )
97
132
 
98
- text = tmp[1]
99
- up_link = tmp[2]
100
-
101
- if tmp = /^([a-zA-Z]+)[-]\d+/.match(up_link) # SRS
102
- doc.up_link_doc_id[ tmp[1].downcase.to_s ] = tmp[1].downcase # multiple documents could be up-linked
133
+ if up_links
134
+ doc.items_with_uplinks_number += 1 #for statistics
135
+ up_links.each do |ul|
136
+ if tmp = />\[(\S*)\]$/.match(ul) # >[SRS-001]
137
+ up_link_id = tmp[1]
138
+
139
+ unless item.up_link_ids
140
+ item.up_link_ids = Array.new
141
+ end
142
+
143
+ item.up_link_ids.append(up_link_id)
144
+
145
+ if tmp = /^([a-zA-Z]+)[-]\d+/.match(up_link_id) # SRS
146
+ doc.up_link_doc_id[ tmp[1].downcase.to_s ] = tmp[1].downcase # multiple documents could be up-linked
147
+ end
148
+ end
103
149
  end
104
150
  end
105
151
 
106
- item = ControlledParagraph.new( text, id )
152
+
107
153
  item.parent_doc = doc
108
154
  item.parent_heading = doc.headings[-1]
109
- if up_link
110
- item.up_link = up_link
111
- doc.items_with_uplinks_number += 1 #for statistics
112
- end
113
155
 
114
156
  doc.items.append(item)
115
- doc.dictionary[ id.to_s ] = item #for fast search
157
+ #for statistics
158
+ if doc.dictionary.has_key?( id.to_s )
159
+ doc.duplicated_ids_number += 1
160
+ doc.duplicates_list.append(item)
161
+ else
162
+ doc.dictionary[ id.to_s ] = item #for fast search
163
+ end
116
164
  doc.controlled_items.append(item) #for fast search
117
165
 
118
166
  #for statistics
119
167
  n = /\d+/.match(id)[0].to_i
120
- if n == doc.last_used_id_number
121
- doc.duplicated_ids_number += 1
122
- elsif n > doc.last_used_id_number
168
+ if n > doc.last_used_id_number
123
169
  doc.last_used_id = id
124
170
  doc.last_used_id_number = n
125
171
  end
@@ -143,7 +189,7 @@ class DocFabric
143
189
 
144
190
  doc.items.append(item)
145
191
 
146
- elsif res = /^(\*\s?)(.*)/.match(s) #check if unordered list start
192
+ elsif res = /^(\*\s+)(.*)/.match(s) #check if unordered list start
147
193
 
148
194
  if tempMdTable
149
195
  doc.items.append tempMdTable
@@ -230,6 +276,50 @@ class DocFabric
230
276
  item.parent_doc = doc
231
277
  doc.items.append(item)
232
278
 
279
+ elsif res = /^```(\w*)/.match(s) #check if code block
280
+
281
+ if tempMdTable
282
+ doc.items.append tempMdTable
283
+ tempMdTable = nil
284
+ end
285
+ if tempMdList
286
+ doc.items.append tempMdList
287
+ tempMdList = nil
288
+ end
289
+
290
+ suggested_format = ""
291
+ if res.length == 2
292
+ suggested_format = res[1]
293
+ end
294
+
295
+ if tempCodeBlock
296
+ # close already opened block
297
+ doc.items.append(tempCodeBlock)
298
+ tempCodeBlock = nil
299
+ else
300
+ #start code block
301
+ tempCodeBlock = CodeBlock.new(suggested_format)
302
+ tempCodeBlock.parent_doc = doc
303
+ end
304
+
305
+ elsif res = /^TODO\:(.*)/.match(s) #check if TODO block
306
+
307
+ if tempMdTable
308
+ doc.items.append tempMdTable
309
+ tempMdTable = nil
310
+ end
311
+ if tempMdList
312
+ doc.items.append tempMdList
313
+ tempMdList = nil
314
+ end
315
+
316
+ text = "**TODO**: " + res[1]
317
+
318
+ item = TodoBlock.new(text)
319
+ item.parent_doc = doc
320
+ doc.items.append(item)
321
+ doc.todo_blocks.append(item)
322
+
233
323
  else # Reqular Paragraph
234
324
  if tempMdTable
235
325
  doc.items.append tempMdTable
@@ -244,10 +334,13 @@ class DocFabric
244
334
  tempMdList = nil
245
335
  end
246
336
  end
247
-
248
- item = Paragraph.new(s)
249
- item.parent_doc = doc
250
- doc.items.append(item)
337
+ if tempCodeBlock
338
+ tempCodeBlock.code_lines.append(s)
339
+ else
340
+ item = Paragraph.new(s)
341
+ item.parent_doc = doc
342
+ doc.items.append(item)
343
+ end
251
344
  end
252
345
  else
253
346
  if tempMdList # lists are separated by emty line from each other
@@ -265,5 +358,13 @@ class DocFabric
265
358
  doc.items.append tempMdList
266
359
  tempMdList = nil
267
360
  end
361
+ if tempCodeBlock
362
+ doc.items.append tempCodeBlock
363
+ tempCodeBlock = nil
364
+ end
365
+ # Add footer to close opened tables if any
366
+ item = DocFooter.new
367
+ item.parent_doc = doc
368
+ doc.items.append(item)
268
369
  end
269
370
  end
@@ -0,0 +1,27 @@
1
+ require_relative "doc_item"
2
+
3
+ class CodeBlock < DocItem
4
+
5
+ attr_accessor :suggested_format
6
+ attr_accessor :code_lines
7
+
8
+ def initialize(suggested_format)
9
+ @suggested_format = suggested_format
10
+ @code_lines = Array.new
11
+ end
12
+
13
+ def to_html
14
+ s = ''
15
+
16
+ if @@htmlTableRenderInProgress
17
+ s += "</table>\n"
18
+ @@htmlTableRenderInProgress = false
19
+ end
20
+ s += "<code>"
21
+ @code_lines.each do |l|
22
+ s += l + " </br>"
23
+ end
24
+ s += "</code>\n"
25
+ return s
26
+ end
27
+ end
@@ -3,14 +3,14 @@ require_relative "paragraph"
3
3
  class ControlledParagraph < Paragraph
4
4
 
5
5
  attr_accessor :id
6
- attr_accessor :up_link
6
+ attr_accessor :up_link_ids
7
7
  attr_accessor :down_links
8
8
  attr_accessor :coverage_links
9
9
 
10
10
  def initialize(text, id)
11
11
  @text = text.strip
12
12
  @id = id
13
- @up_link = nil
13
+ @up_link_ids = nil
14
14
  @down_links = nil
15
15
  @coverage_links = nil
16
16
  end
@@ -27,11 +27,27 @@ class ControlledParagraph < Paragraph
27
27
  s += "\t\t<td class=\"item_id\"> <a name=\"#{@id}\" id=\"#{@id}\" href=\"##{@id}\">#{@id}</a></td>\n"
28
28
  s += "\t\t<td class=\"item_text\">#{f_text}</td>\n"
29
29
 
30
- if @up_link
31
- if tmp = /^([a-zA-Z]+)[-]\d+/.match(@up_link)
32
- up_link_doc_name = tmp[1].downcase
30
+ if @up_link_ids
31
+ if @up_link_ids.length == 1
32
+ if tmp = /^([a-zA-Z]+)[-]\d+/.match(@up_link_ids[0])
33
+ up_link_doc_name = tmp[1].downcase
34
+ end
35
+ s += "\t\t<td class=\"item_id\"><a href=\"./../#{up_link_doc_name}/#{up_link_doc_name}.html##{@up_link_ids[0]}\" class=\"external\">#{@up_link_ids[0]}</a></td>\n"
36
+ else
37
+ s += "\t\t<td class=\"item_id\">"
38
+ s += "<div id=\"DL_#{@id}\" style=\"display: block;\">"
39
+ s += "<a href=\"#\" onclick=\"downlink_OnClick(this.parentElement); return false;\" class=\"external\">#{@up_link_ids.length}</a>"
40
+ s += "</div>"
41
+ s += "<div id=\"DLS_#{@id}\" style=\"display: none;\">"
42
+ @up_link_ids.each do |lnk|
43
+ if tmp = /^([a-zA-Z]+)[-]\d+/.match(lnk)
44
+ up_link_doc_name = tmp[1].downcase
45
+ end
46
+ s += "\t\t\t<a href=\"./../#{up_link_doc_name}/#{up_link_doc_name}.html##{lnk}\" class=\"external\">#{lnk}</a>\n<br>"
47
+ end
48
+ s += "</div>"
49
+ s += "</td>\n"
33
50
  end
34
- s += "\t\t<td class=\"item_id\"><a href=\"./../#{up_link_doc_name}/#{up_link_doc_name}.html##{@up_link}\" class=\"external\">#{@up_link}</a></td>\n"
35
51
  else
36
52
  s += "\t\t<td class=\"item_id\"></td>\n"
37
53
  end
@@ -0,0 +1,17 @@
1
+ require_relative "doc_item"
2
+
3
+ class DocFooter < DocItem
4
+
5
+ def initialize
6
+ end
7
+
8
+ def to_html
9
+ s = ''
10
+ if @@htmlTableRenderInProgress
11
+ s += "</table>\n"
12
+ @@htmlTableRenderInProgress = false
13
+ end
14
+ return s
15
+ end
16
+
17
+ end
@@ -13,7 +13,7 @@ class Heading < Paragraph
13
13
  @level = level
14
14
  @anchor_id = getTextWithoutSpaces()
15
15
 
16
- if @@global_section_number = ""
16
+ if @@global_section_number == ""
17
17
  @@global_section_number = "1"
18
18
  for n in 1..(level-1) do
19
19
  @@global_section_number += ".1"
@@ -27,16 +27,21 @@ class Heading < Paragraph
27
27
  a[-1] = (a[-1].to_i() +1).to_s
28
28
  @@global_section_number = a.join(".")
29
29
 
30
- elsif previous_level < level
30
+ elsif level > previous_level
31
31
 
32
32
  a = @@global_section_number.split(".")
33
33
  a.push("1")
34
34
  @@global_section_number = a.join(".")
35
35
 
36
- else # previous_level > level
36
+ else # level < previous_level
37
37
 
38
38
  a = @@global_section_number.split(".")
39
- a.pop
39
+ delta = previous_level - level
40
+ a.pop(delta)
41
+ @@global_section_number = a.join(".")
42
+ # increment
43
+ a = @@global_section_number.split(".")
44
+ a[-1] = (a[-1].to_i() +1).to_s
40
45
  @@global_section_number = a.join(".")
41
46
  end
42
47
  end
@@ -59,4 +64,8 @@ class Heading < Paragraph
59
64
  s += "&para;</a></h#{headingLevel}>"
60
65
  return s
61
66
  end
67
+
68
+ def self.reset_global_section_number
69
+ @@global_section_number = ""
70
+ end
62
71
  end
@@ -21,7 +21,8 @@ class Image < DocItem
21
21
  @@htmlTableRenderInProgress = false
22
22
  end
23
23
 
24
- s += "<p style=\"margin-top: 15px;\"><img src=\"#{@path}\" alt=\"#{@text}\">"
24
+ s += "<p style=\"margin-top: 15px;\"><img src=\"#{@path}\" alt=\"#{@text}\" "
25
+ s += "href=\"javascript:void(0)\" onclick=\"image_OnClick(this)\">"
25
26
  return s
26
27
  end
27
28
  end
@@ -47,7 +47,9 @@ class MarkdownList < DocItem
47
47
 
48
48
  elsif pos < @@lists_stack[-1].indent_position
49
49
 
50
- @@lists_stack.pop
50
+ while pos < @@lists_stack[-1].indent_position
51
+ @@lists_stack.pop
52
+ end
51
53
  @@lists_stack[-1].rows.append(row)
52
54
 
53
55
  else
@@ -70,14 +72,27 @@ class MarkdownList < DocItem
70
72
  def calculate_text_position(s)
71
73
  s.downcase
72
74
  pos = 0
73
- space_detected = false
75
+ state = 'looking_for_list_item_marker'
74
76
  s.each_char do |c|
75
- if space_detected
76
- if c != ' ' && c != '\t' && c != '*' && c != '.' && !numeric?(c)
77
+ if state == 'looking_for_list_item_marker'
78
+ if c == '*'
79
+ state = 'looking_for_space'
80
+ elsif numeric?(c)
81
+ state = 'looking_for_dot'
82
+ end
83
+ elsif state == 'looking_for_dot'
84
+ if c == '.'
85
+ state = 'looking_for_space'
86
+ end
87
+ elsif state == 'looking_for_space'
88
+ if c == ' ' || c == '\t'
89
+ state = 'looking_for_non_space'
90
+ end
91
+ elsif state == 'looking_for_non_space'
92
+ if c != ' ' || c != '\t'
93
+ state = 'list_item_text_pos_found'
77
94
  break
78
95
  end
79
- elsif c == ' ' || c == '\t'
80
- space_detected = true
81
96
  end
82
97
  pos += 1
83
98
  end
@@ -155,7 +155,7 @@ class TextLine
155
155
  def link(link_text, link_url)
156
156
 
157
157
  # define default result first
158
- result = "<a href=\"#{link_url}\" class=\"external\">#{link_text}</a>"
158
+ result = "<a target=\"_blank\" rel=\"noopener\" href=\"#{link_url}\" class=\"external\">#{link_text}</a>"
159
159
 
160
160
  lazy_doc_id, anchor = nil, nil
161
161
 
@@ -0,0 +1,22 @@
1
+ require_relative "doc_item"
2
+
3
+ class TodoBlock < DocItem
4
+
5
+ attr_accessor :text
6
+
7
+ def initialize(text)
8
+ @text = text
9
+ end
10
+
11
+ def to_html
12
+ s = ''
13
+ f_text = format_string(@text)
14
+ if @@htmlTableRenderInProgress
15
+ s += "</table>\n"
16
+ @@htmlTableRenderInProgress = false
17
+ end
18
+
19
+ s += "<div class=\"todoblock\"><p>#{f_text}</div>\n"
20
+ return s
21
+ end
22
+ end
@@ -34,6 +34,8 @@ class Index < BaseDocument
34
34
  s += "\t\t<th>Items<br>w/ Downlinks</th>\n"
35
35
  s += "\t\t<th>Covered<br>by Tests</th>\n"
36
36
  s += "\t\t<th>Duplicated<br>ids</th>\n"
37
+ s += "\t\t<th>Wrong<br>links</th>\n"
38
+ s += "\t\t<th>TODOs</th>\n"
37
39
  s += "\t\t<th>Last Used<br>id</th>\n"
38
40
  s += "</thead>\n"
39
41
  html_rows.append s
@@ -47,7 +49,43 @@ class Index < BaseDocument
47
49
  s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.items_with_uplinks_number.to_s}</td>\n"
48
50
  s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.items_with_downlinks_number.to_s}</td>\n"
49
51
  s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.items_with_coverage_number.to_s}</td>\n"
50
- s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.duplicated_ids_number.to_s}</td>\n"
52
+
53
+ if doc.duplicated_ids_number >0
54
+ s += "\t\t<td class=\"item_id\" style='width: 7%; background-color: #fcc;'>"
55
+ s += "<div id=\"DL_#{doc.id}\" style=\"display: block;\">"
56
+ s += "<a href=\"#\" onclick=\"downlink_OnClick(this.parentElement); return false;\" class=\"external\">#{doc.duplicated_ids_number.to_s}</a>"
57
+ s += "</div>"
58
+ s += "<div id=\"DLS_#{doc.id}\" style=\"display: none;\">"
59
+ doc.duplicates_list.each do |lnk|
60
+ s += "\t\t\t<a href=\"./specifications/#{doc.id}/#{doc.id}.html##{lnk.id}\" class=\"external\">#{lnk.id}</a>\n<br>"
61
+ end
62
+ s += "</div>"
63
+ s += "</td>\n"
64
+ else
65
+ s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.duplicated_ids_number.to_s}</td>\n"
66
+ end
67
+
68
+ if doc.wrong_links_hash.length >0
69
+ s += "\t\t<td class=\"item_id\" style='width: 7%; background-color: #fcc;'>"
70
+ s += "<div id=\"DL_#{doc.id}wl\" style=\"display: block;\">"
71
+ s += "<a href=\"#\" onclick=\"downlink_OnClick(this.parentElement); return false;\" class=\"external\">#{doc.wrong_links_hash.length.to_s}</a>"
72
+ s += "</div>"
73
+ s += "<div id=\"DLS_#{doc.id}wl\" style=\"display: none;\">"
74
+ doc.wrong_links_hash.each do |wrong_lnk, item|
75
+ s += "\t\t\t<a href=\"./specifications/#{doc.id}/#{doc.id}.html##{item.id}\" class=\"external\">#{wrong_lnk}</a>\n<br>"
76
+ end
77
+ s += "</div>"
78
+ s += "</td>\n"
79
+ else
80
+ s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.wrong_links_hash.length.to_s}</td>\n"
81
+ end
82
+
83
+ if doc.todo_blocks.length >0
84
+ color = "background-color: #fcc;"
85
+ else
86
+ color = ""
87
+ end
88
+ s += "\t\t<td class=\"item_id\" style='width: 7%; #{color}'>#{doc.todo_blocks.length.to_s}</td>\n"
51
89
  s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.last_used_id.to_s}</td>\n"
52
90
  s += "</tr>\n"
53
91
  html_rows.append s
@@ -5,11 +5,14 @@ class Specification < BaseDocument
5
5
  attr_accessor :up_link_doc_id
6
6
  attr_accessor :dictionary
7
7
  attr_accessor :controlled_items
8
+ attr_accessor :todo_blocks
9
+ attr_accessor :wrong_links_hash
8
10
 
9
11
  attr_accessor :items_with_uplinks_number
10
12
  attr_accessor :items_with_downlinks_number
11
13
  attr_accessor :items_with_coverage_number
12
14
  attr_accessor :duplicated_ids_number
15
+ attr_accessor :duplicates_list
13
16
  attr_accessor :last_used_id
14
17
  attr_accessor :last_used_id_number
15
18
 
@@ -21,6 +24,9 @@ class Specification < BaseDocument
21
24
  @headings = Array.new
22
25
  @controlled_items = Array.new
23
26
  @dictionary = Hash.new
27
+ @duplicates_list = Array.new
28
+ @todo_blocks = Array.new
29
+ @wrong_links_hash = Hash.new
24
30
 
25
31
  @items_with_uplinks_number = 0
26
32
  @items_with_downlinks_number = 0
@@ -35,6 +35,7 @@ class Project
35
35
  parse_all_protocols
36
36
  link_all_specifications
37
37
  link_all_protocols
38
+ check_wrong_specification_referenced
38
39
  create_index
39
40
  render_all_specifications(@specifications)
40
41
  render_all_specifications(@traceability_matrices)
@@ -49,6 +50,7 @@ class Project
49
50
  parse_test_run test_run
50
51
  link_all_specifications
51
52
  link_all_protocols
53
+ check_wrong_specification_referenced
52
54
  create_index
53
55
  render_all_specifications(@specifications)
54
56
  render_all_specifications(@traceability_matrices)
@@ -123,6 +125,37 @@ class Project
123
125
  end
124
126
  end
125
127
 
128
+ def check_wrong_specification_referenced
129
+
130
+ available_specification_ids = Hash.new
131
+
132
+ @specifications.each do |s|
133
+ available_specification_ids[ s.id.to_s.downcase ] = s
134
+ end
135
+
136
+ @specifications.each do |s|
137
+ s.up_link_doc_id.each do |key, value|
138
+ unless available_specification_ids.has_key?(key)
139
+ # now key points to the doc_id that does not exist
140
+ wrong_doc_id = key
141
+ # find the item that reference to it
142
+ s.controlled_items.each do |item|
143
+ unless item.up_link_ids.nil?
144
+ item.up_link_ids.each do |up_link_id|
145
+ if tmp = /^([a-zA-Z]+)[-]\d+/.match(up_link_id) # SRS
146
+ if tmp[1].downcase == wrong_doc_id
147
+ # we got it finally!
148
+ s.wrong_links_hash[ up_link_id.to_s ] = item
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+
126
159
  def link_two_specifications(doc_A, doc_B)
127
160
 
128
161
  if doc_B.up_link_doc_id.has_key?(doc_A.id.to_s)
@@ -137,15 +170,27 @@ class Project
137
170
  #puts "Link: #{doc_A.id} - #{doc_B.id}"
138
171
  bottom_document.controlled_items.each do |item|
139
172
 
140
- if top_document.dictionary.has_key?(item.up_link.to_s)
141
-
142
- topItem = top_document.dictionary[item.up_link.to_s]
143
-
144
- unless topItem.down_links
145
- topItem.down_links = Array.new
146
- top_document.items_with_downlinks_number += 1 # for statistics
173
+ if item.up_link_ids
174
+ item.up_link_ids.each do |up_lnk|
175
+
176
+ if top_document.dictionary.has_key?(up_lnk.to_s)
177
+
178
+ topItem = top_document.dictionary[up_lnk.to_s]
179
+
180
+ unless topItem.down_links
181
+ topItem.down_links = Array.new
182
+ top_document.items_with_downlinks_number += 1 # for statistics
183
+ end
184
+ topItem.down_links.append(item)
185
+ else
186
+ # check if there is a non existing link with the right doc_id
187
+ if tmp = /^([a-zA-Z]+)[-]\d+/.match(up_lnk) # SRS
188
+ if tmp[1].downcase == top_document.id.downcase
189
+ bottom_document.wrong_links_hash[ up_lnk ] = item
190
+ end
191
+ end
192
+ end
147
193
  end
148
- topItem.down_links.append(item)
149
194
  end
150
195
  end
151
196
  # create treceability document
@@ -2,6 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
+ <title>{{DOCUMENT_TITLE}}</title>
5
6
  <!-- CSS -->
6
7
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
7
8
  <style>
@@ -144,6 +145,34 @@
144
145
  margin-top: 4px;
145
146
  margin-bottom: 4px;
146
147
  }
148
+ code {
149
+ display: block;
150
+ background:#ffffee;
151
+ border-left: 3px double #bbb;
152
+ font-family: Consolas, Menlo, "Liberation Mono", Courier, monospace;
153
+ padding: 4px 1em 4px 4px;
154
+ margin-top: 4px;
155
+ margin-bottom: 4px;
156
+ }
157
+ div.todoblock {
158
+ display: block;
159
+ background:#fcc;
160
+ border-left: 3px double #bbb;
161
+ font-style: italic;
162
+ padding: 4px 1em 4px 4px;
163
+ margin-top: 4px;
164
+ margin-bottom: 4px;
165
+ }
166
+ img:hover{
167
+ transition: 0.3s;
168
+ }
169
+ img{
170
+ opacity: 0.9;
171
+ cursor: pointer;
172
+ }
173
+ #modal_image_id{
174
+ cursor: default;
175
+ }
147
176
  #nav_pane{
148
177
  flex-shrink: 0;
149
178
  padding: 16px 8px 2px 8px;
@@ -164,6 +193,7 @@
164
193
  overflow: hidden;
165
194
  position: fixed;
166
195
  width: 100%;
196
+ z-index: 1;
167
197
  }
168
198
  #top_nav a {
169
199
  float: left;
@@ -191,7 +221,67 @@
191
221
  background-color: #169;
192
222
  color: white;
193
223
  }
194
-
224
+ .modal {
225
+ display: none; /* Hidden by default */
226
+ position: fixed; /* Stay in place */
227
+ z-index: 1; /* Sit on top */
228
+ padding-top: 100px; /* Location of the box */
229
+ left: 0;
230
+ top: 0;
231
+ width: 100%; /* Full width */
232
+ height: 100%; /* Full height */
233
+ overflow: auto; /* Enable scroll if needed */
234
+ background-color: rgb(0,0,0); /* Fallback color */
235
+ background-color: rgba(0,0,0,0.9); /* Black w/ opacity */
236
+ }
237
+ .modal_image {
238
+ margin: auto;
239
+ display: block;
240
+ width: 97%;
241
+ /*max-width: 700px;*/
242
+ }
243
+ #modal_image_caption {
244
+ margin: auto;
245
+ display: block;
246
+ width: 80%;
247
+ max-width: 700px;
248
+ text-align: center;
249
+ color: #ccc;
250
+ padding: 10px 0;
251
+ height: 150px;
252
+ }
253
+ .modal_image, #modal_image_caption {
254
+ animation-name: zoom;
255
+ animation-duration: 0.6s;
256
+ }
257
+ @keyframes zoom {
258
+ from {transform: scale(0.1)}
259
+ to {transform: scale(1)}
260
+ }
261
+ .modal_close_btn {
262
+ position: absolute;
263
+ top: 15px;
264
+ right: 35px;
265
+ color: #f1f1f1;
266
+ font-size: 30px;
267
+ font-weight: bold;
268
+ transition: 0.3s;
269
+ }
270
+ .modal_close_btn:hover,
271
+ .modal_close_btn:focus {
272
+ color: #bbb;
273
+ text-decoration: none;
274
+ cursor: pointer;
275
+ }
276
+ #footer {
277
+ clear: both;
278
+ border-top: 1px solid #bbb;
279
+ font-size: 0.9em;
280
+ color: #aaa;
281
+ padding: 5px;
282
+ text-align:center;
283
+ background:#fff;
284
+ }
195
285
  </style>
196
286
  <script>
197
287
  function openNav() {
@@ -221,11 +311,36 @@ function downlink_OnClick(clicked){
221
311
  required_id = "DLS_" + id_parts[1];
222
312
  document.getElementById(required_id).style.display = 'block';
223
313
  }
314
+
315
+ function navigate_to_home(){
316
+ if (document.title != "Document Index")
317
+ {
318
+ window.location.href = "./../../index.html";
319
+ }
320
+ }
321
+
322
+ // Modal window for image zoom
323
+ function image_OnClick(clicked){
324
+
325
+ var modal = document.getElementById('image_modal_div');
326
+ var modalImg = document.getElementById("modal_image_id");
327
+ var captionText = document.getElementById("modal_image_caption");
328
+
329
+ modal.style.display = "block";
330
+ modalImg.src = clicked.src;
331
+ captionText.innerHTML = clicked.alt;
332
+ }
333
+
334
+ function modal_close_OnClick(clicked){
335
+ var modal = document.getElementById('image_modal_div');
336
+ modal.style.display = "none";
337
+ }
338
+
224
339
  </script>
225
340
  </head>
226
341
  <body>
227
342
  <div id="top_nav">
228
- <a href="./../../index.html"><span><i class="fa fa-home" aria-hidden="true"></i></span>&nbsp;Home</a>
343
+ <a href="javascript:void(0)" onclick="navigate_to_home()"><span><i class="fa fa-home" aria-hidden="true"></i></span>&nbsp;Home</a>
229
344
  <!--a href="javascript:void(0)"> About</a-->
230
345
  <a class="split">{{DOCUMENT_TITLE}}</a>
231
346
  </div>
@@ -235,7 +350,16 @@ function downlink_OnClick(clicked){
235
350
  </div>
236
351
  <div id="content" href="javascript:void(0)" onclick="closeNav()">
237
352
  {{CONTENT}}
238
- </div>
353
+ </div><!-- content -->
354
+ </div><!-- main -->
355
+ <div id="footer">
356
+ Powered by <a target="_blank" rel="noopener" href="https://www.almirah.site/">Almirah Framework</a>
357
+ </div><!-- footer -->
358
+ <!-- The modal window for image zoom -->
359
+ <div id="image_modal_div" class="modal">
360
+ <span class="modal_close_btn" href="javascript:void(0)" onclick="modal_close_OnClick(this)">&times;</span>
361
+ <img class="modal_image" id="modal_image_id">
362
+ <div id="modal_image_caption"></div>
239
363
  </div>
240
364
  </body>
241
365
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Almirah
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleksandr Ivanov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-13 00:00:00.000000000 Z
11
+ date: 2024-04-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: The software part of the Almirah framework
14
14
  email: oleksandr.ivanov.development@gmail.com
@@ -21,9 +21,11 @@ files:
21
21
  - lib/almirah.rb
22
22
  - lib/almirah/doc_fabric.rb
23
23
  - lib/almirah/doc_items/blockquote.rb
24
+ - lib/almirah/doc_items/code_block.rb
24
25
  - lib/almirah/doc_items/controlled_paragraph.rb
25
26
  - lib/almirah/doc_items/controlled_table.rb
26
27
  - lib/almirah/doc_items/controlled_table_row.rb
28
+ - lib/almirah/doc_items/doc_footer.rb
27
29
  - lib/almirah/doc_items/doc_item.rb
28
30
  - lib/almirah/doc_items/heading.rb
29
31
  - lib/almirah/doc_items/image.rb
@@ -31,6 +33,7 @@ files:
31
33
  - lib/almirah/doc_items/markdown_table.rb
32
34
  - lib/almirah/doc_items/paragraph.rb
33
35
  - lib/almirah/doc_items/text_line.rb
36
+ - lib/almirah/doc_items/todo_block.rb
34
37
  - lib/almirah/doc_types/base_document.rb
35
38
  - lib/almirah/doc_types/coverage.rb
36
39
  - lib/almirah/doc_types/index.rb
@@ -59,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
59
62
  - !ruby/object:Gem::Version
60
63
  version: '0'
61
64
  requirements: []
62
- rubygems_version: 3.5.6
65
+ rubygems_version: 3.5.9
63
66
  signing_key:
64
67
  specification_version: 4
65
68
  summary: Almirah