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 +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
|