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 +4 -4
- data/lib/almirah/doc_fabric.rb +129 -28
- data/lib/almirah/doc_items/code_block.rb +27 -0
- data/lib/almirah/doc_items/controlled_paragraph.rb +22 -6
- data/lib/almirah/doc_items/doc_footer.rb +17 -0
- data/lib/almirah/doc_items/heading.rb +13 -4
- data/lib/almirah/doc_items/image.rb +2 -1
- data/lib/almirah/doc_items/markdown_list.rb +21 -6
- data/lib/almirah/doc_items/text_line.rb +1 -1
- data/lib/almirah/doc_items/todo_block.rb +22 -0
- data/lib/almirah/doc_types/index.rb +39 -1
- data/lib/almirah/doc_types/specification.rb +6 -0
- data/lib/almirah/project.rb +53 -8
- data/lib/almirah/templates/page.html +127 -3
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7a10581e498b38097f10868900c903c9e3bad04bfb3e1d63170bada3222c65b
|
4
|
+
data.tar.gz: 70ac0c4e2893e69ae0aa6c146c4c7a1da2b4ddd7ae0249604bc0b9afcb4980dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d2f2cfe15dd20b56c31cab7748304007497cbb4a03928df501b2628a261861003a8a0d576ff084ebd54128b03a5c521e6e1da94e8125f93e1233bee94a06ddc
|
7
|
+
data.tar.gz: ff4cbc8d03219cb9792a854dfabbe0b968a097b73e57fca89f0a027bcca11916c646dbca4e64539ea3ac3f6a0b6213d18b71e4e9e323e57a05d83240289bf057
|
data/lib/almirah/doc_fabric.rb
CHANGED
@@ -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
|
-
|
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
|
-
#
|
96
|
-
|
130
|
+
# since we already know id and text
|
131
|
+
item = ControlledParagraph.new( text, id )
|
97
132
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
249
|
-
|
250
|
-
|
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 :
|
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
|
-
@
|
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 @
|
31
|
-
if
|
32
|
-
|
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
|
@@ -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
|
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 #
|
36
|
+
else # level < previous_level
|
37
37
|
|
38
38
|
a = @@global_section_number.split(".")
|
39
|
-
|
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 += "¶</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.
|
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
|
-
|
75
|
+
state = 'looking_for_list_item_marker'
|
74
76
|
s.each_char do |c|
|
75
|
-
if
|
76
|
-
if 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
|
-
|
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
|
data/lib/almirah/project.rb
CHANGED
@@ -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
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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="
|
343
|
+
<a href="javascript:void(0)" onclick="navigate_to_home()"><span><i class="fa fa-home" aria-hidden="true"></i></span> 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)">×</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.
|
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-
|
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.
|
65
|
+
rubygems_version: 3.5.9
|
63
66
|
signing_key:
|
64
67
|
specification_version: 4
|
65
68
|
summary: Almirah
|