Almirah 0.1.1 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
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