Almirah 0.1.9 → 0.2.1
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 +3 -327
- data/lib/almirah/doc_items/controlled_paragraph.rb +3 -1
- data/lib/almirah/doc_items/controlled_table.rb +1 -1
- data/lib/almirah/doc_items/doc_item.rb +4 -0
- data/lib/almirah/doc_items/heading.rb +18 -2
- data/lib/almirah/doc_items/markdown_list.rb +5 -2
- data/lib/almirah/doc_parser.rb +334 -0
- data/lib/almirah/doc_types/base_document.rb +22 -6
- data/lib/almirah/doc_types/coverage.rb +1 -5
- data/lib/almirah/doc_types/index.rb +1 -3
- data/lib/almirah/doc_types/persistent_document.rb +20 -0
- data/lib/almirah/doc_types/protocol.rb +3 -15
- data/lib/almirah/doc_types/specification.rb +3 -11
- data/lib/almirah/doc_types/traceability.rb +1 -4
- data/lib/almirah/dom/document.rb +1 -1
- data/lib/almirah/project.rb +58 -47
- data/lib/almirah/project_configuration.rb +42 -0
- data/lib/almirah/search/specifications_db.rb +66 -0
- data/lib/almirah/templates/css/main.css +298 -0
- data/lib/almirah/templates/css/search.css +40 -0
- data/lib/almirah/templates/page.html +7 -357
- data/lib/almirah/templates/scripts/main.js +61 -0
- data/lib/almirah/templates/scripts/orama_search.js +136 -0
- data/lib/almirah.rb +3 -1
- metadata +10 -2
@@ -0,0 +1,334 @@
|
|
1
|
+
require_relative 'doc_items/text_line'
|
2
|
+
require_relative 'doc_items/doc_item'
|
3
|
+
require_relative 'doc_items/heading'
|
4
|
+
require_relative 'doc_items/paragraph'
|
5
|
+
require_relative 'doc_items/blockquote'
|
6
|
+
require_relative 'doc_items/code_block'
|
7
|
+
require_relative 'doc_items/todo_block'
|
8
|
+
require_relative 'doc_items/controlled_paragraph'
|
9
|
+
require_relative 'doc_items/markdown_table'
|
10
|
+
require_relative 'doc_items/controlled_table'
|
11
|
+
require_relative 'doc_items/image'
|
12
|
+
require_relative 'doc_items/markdown_list'
|
13
|
+
require_relative 'doc_items/doc_footer'
|
14
|
+
|
15
|
+
class DocParser
|
16
|
+
def self.parse(doc, text_lines)
|
17
|
+
temp_md_table = nil
|
18
|
+
temp_md_list = nil
|
19
|
+
temp_code_block = nil
|
20
|
+
# restart section numbering for each new document
|
21
|
+
Heading.reset_global_section_number
|
22
|
+
|
23
|
+
text_lines.each do |s|
|
24
|
+
if s.lstrip != ''
|
25
|
+
if res = /^(\#{1,})\s(.*)/.match(s) # Heading
|
26
|
+
|
27
|
+
if temp_md_table
|
28
|
+
doc.items.append temp_md_table
|
29
|
+
temp_md_table = nil
|
30
|
+
end
|
31
|
+
if temp_md_list
|
32
|
+
doc.items.append temp_md_list
|
33
|
+
temp_md_list = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
level = res[1].length
|
37
|
+
value = res[2]
|
38
|
+
|
39
|
+
if level == 1 && doc.title == ''
|
40
|
+
doc.title = value
|
41
|
+
end
|
42
|
+
|
43
|
+
item = Heading.new(doc, value, level)
|
44
|
+
doc.items.append(item)
|
45
|
+
doc.headings.append(item)
|
46
|
+
|
47
|
+
elsif res = /^%\s(.*)/.match(s) # Pandoc Document Title
|
48
|
+
|
49
|
+
title = res[1]
|
50
|
+
|
51
|
+
if doc.title == ''
|
52
|
+
doc.title = title
|
53
|
+
end
|
54
|
+
|
55
|
+
item = Heading.new(doc, title, 0)
|
56
|
+
doc.items.append(item)
|
57
|
+
doc.headings.append(item)
|
58
|
+
|
59
|
+
elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
|
60
|
+
|
61
|
+
if temp_md_table
|
62
|
+
doc.items.append temp_md_table
|
63
|
+
temp_md_table = nil
|
64
|
+
end
|
65
|
+
if temp_md_list
|
66
|
+
doc.items.append temp_md_list
|
67
|
+
temp_md_list = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
id = res[1].upcase
|
71
|
+
text = res[2]
|
72
|
+
up_links = nil
|
73
|
+
|
74
|
+
# check if it contains the uplink (one or many)
|
75
|
+
# TODO: check this regular expression
|
76
|
+
first_pos = text.length # for trailing commas
|
77
|
+
tmp = text.scan(/(>\[(?>[^\[\]]|\g<0>)*\])/) # >[SRS-001], >[SYS-002]
|
78
|
+
if tmp.length > 0
|
79
|
+
up_links = []
|
80
|
+
tmp.each do |ul|
|
81
|
+
lnk = ul[0]
|
82
|
+
# do not add links for the self document
|
83
|
+
doc_id = /([a-zA-Z]+)-\d+/.match(lnk) # SRS
|
84
|
+
if (doc_id) and (doc_id[1].downcase != doc.id.downcase)
|
85
|
+
up_links << lnk.upcase
|
86
|
+
end
|
87
|
+
# try to find the real end of text
|
88
|
+
pos = text.index(lnk)
|
89
|
+
first_pos = pos if pos < first_pos
|
90
|
+
# remove uplink from text
|
91
|
+
text = text.split(lnk, 1).join('')
|
92
|
+
end
|
93
|
+
# remove trailing commas and spaces
|
94
|
+
if text.length > first_pos
|
95
|
+
first_pos -= 1
|
96
|
+
text = text[0..first_pos].strip
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# since we already know id and text
|
101
|
+
item = ControlledParagraph.new(doc, text, id)
|
102
|
+
|
103
|
+
if up_links
|
104
|
+
up_links.uniq! #remove duplicates
|
105
|
+
doc.items_with_uplinks_number += 1 # for statistics
|
106
|
+
up_links.each do |ul|
|
107
|
+
next unless tmp = />\[(\S*)\]$/.match(ul) # >[SRS-001]
|
108
|
+
|
109
|
+
up_link_id = tmp[1]
|
110
|
+
|
111
|
+
item.up_link_ids = [] unless item.up_link_ids
|
112
|
+
|
113
|
+
item.up_link_ids.append(up_link_id)
|
114
|
+
|
115
|
+
if tmp = /^([a-zA-Z]+)-\d+/.match(up_link_id) # SRS
|
116
|
+
doc.up_link_docs[tmp[1].downcase.to_s] = tmp[1].downcase # multiple documents could be up-linked
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
doc.items.append(item)
|
122
|
+
# for statistics
|
123
|
+
if doc.dictionary.has_key?(id.to_s)
|
124
|
+
doc.duplicated_ids_number += 1
|
125
|
+
doc.duplicates_list.append(item)
|
126
|
+
else
|
127
|
+
doc.dictionary[id.to_s] = item # for fast search
|
128
|
+
end
|
129
|
+
doc.controlled_items.append(item) # for fast search
|
130
|
+
|
131
|
+
# for statistics
|
132
|
+
n = /\d+/.match(id)[0].to_i
|
133
|
+
if n > doc.last_used_id_number
|
134
|
+
doc.last_used_id = id
|
135
|
+
doc.last_used_id_number = n
|
136
|
+
end
|
137
|
+
|
138
|
+
elsif res = /^!\[(.*)\]\((.*)\)/.match(s) # Image
|
139
|
+
|
140
|
+
if temp_md_table
|
141
|
+
doc.items.append temp_md_table
|
142
|
+
temp_md_table = nil
|
143
|
+
end
|
144
|
+
if temp_md_list
|
145
|
+
doc.items.append temp_md_list
|
146
|
+
temp_md_list = nil
|
147
|
+
end
|
148
|
+
|
149
|
+
img_text = res[1]
|
150
|
+
img_path = res[2]
|
151
|
+
|
152
|
+
item = Image.new(img_text, img_path)
|
153
|
+
item.parent_doc = doc
|
154
|
+
item.parent_heading = doc.headings[-1]
|
155
|
+
|
156
|
+
doc.items.append(item)
|
157
|
+
|
158
|
+
elsif res = /^(\*\s+)(.*)/.match(s) # check if unordered list start
|
159
|
+
|
160
|
+
if temp_md_table
|
161
|
+
doc.items.append temp_md_table
|
162
|
+
temp_md_table = nil
|
163
|
+
end
|
164
|
+
|
165
|
+
row = res[2]
|
166
|
+
|
167
|
+
if temp_md_list
|
168
|
+
temp_md_list.addRow(s)
|
169
|
+
else
|
170
|
+
item = MarkdownList.new(doc, false)
|
171
|
+
item.addRow(s)
|
172
|
+
temp_md_list = item
|
173
|
+
end
|
174
|
+
|
175
|
+
elsif res = /^\d[.]\s(.*)/.match(s) # check if ordered list start
|
176
|
+
|
177
|
+
if temp_md_table
|
178
|
+
doc.items.append temp_md_table
|
179
|
+
temp_md_table = nil
|
180
|
+
end
|
181
|
+
|
182
|
+
row = res[1]
|
183
|
+
|
184
|
+
if temp_md_list
|
185
|
+
temp_md_list.addRow(s)
|
186
|
+
else
|
187
|
+
item = MarkdownList.new(doc, true)
|
188
|
+
item.addRow(s)
|
189
|
+
temp_md_list = item
|
190
|
+
end
|
191
|
+
|
192
|
+
elsif s[0] == '|' # check if table
|
193
|
+
|
194
|
+
if temp_md_list
|
195
|
+
doc.items.append temp_md_list
|
196
|
+
temp_md_list = nil
|
197
|
+
end
|
198
|
+
|
199
|
+
if res = /^[|](-{3,})[|]/.match(s) # check if it is a separator first
|
200
|
+
|
201
|
+
if temp_md_table
|
202
|
+
# separator is found after heading - just skip it
|
203
|
+
else
|
204
|
+
# separator out of table scope consider it just as a regular paragraph
|
205
|
+
item = Paragraph.new(s)
|
206
|
+
item.parent_doc = doc
|
207
|
+
item.parent_heading = doc.headings[-1]
|
208
|
+
doc.items.append(item)
|
209
|
+
end
|
210
|
+
|
211
|
+
elsif res = /^[|](.*[|])/.match(s) # check if it looks as a table
|
212
|
+
|
213
|
+
row = res[1]
|
214
|
+
|
215
|
+
if temp_md_table
|
216
|
+
# check if it is a controlled table
|
217
|
+
unless temp_md_table.addRow(row)
|
218
|
+
temp_md_table = ControlledTable.new(temp_md_table, doc)
|
219
|
+
temp_md_table.parent_doc = doc
|
220
|
+
temp_md_table.addRow(row)
|
221
|
+
end
|
222
|
+
else
|
223
|
+
# start table from heading
|
224
|
+
temp_md_table = MarkdownTable.new(row)
|
225
|
+
temp_md_table.parent_doc = doc
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
elsif res = /^>(.*)/.match(s) # check if blockquote
|
230
|
+
|
231
|
+
if temp_md_table
|
232
|
+
doc.items.append temp_md_table
|
233
|
+
temp_md_table = nil
|
234
|
+
end
|
235
|
+
if temp_md_list
|
236
|
+
doc.items.append temp_md_list
|
237
|
+
temp_md_list = nil
|
238
|
+
end
|
239
|
+
|
240
|
+
item = Blockquote.new(res[1])
|
241
|
+
item.parent_doc = doc
|
242
|
+
item.parent_heading = doc.headings[-1]
|
243
|
+
doc.items.append(item)
|
244
|
+
|
245
|
+
elsif res = /^```(\w*)/.match(s) # check if code block
|
246
|
+
|
247
|
+
if temp_md_table
|
248
|
+
doc.items.append temp_md_table
|
249
|
+
temp_md_table = nil
|
250
|
+
end
|
251
|
+
if temp_md_list
|
252
|
+
doc.items.append temp_md_list
|
253
|
+
temp_md_list = nil
|
254
|
+
end
|
255
|
+
|
256
|
+
suggested_format = ''
|
257
|
+
suggested_format = res[1] if res.length == 2
|
258
|
+
|
259
|
+
if temp_code_block
|
260
|
+
# close already opened block
|
261
|
+
doc.items.append(temp_code_block)
|
262
|
+
temp_code_block = nil
|
263
|
+
else
|
264
|
+
# start code block
|
265
|
+
temp_code_block = CodeBlock.new(suggested_format)
|
266
|
+
temp_code_block.parent_doc = doc
|
267
|
+
end
|
268
|
+
|
269
|
+
elsif res = /^TODO:(.*)/.match(s) # check if TODO block
|
270
|
+
|
271
|
+
if temp_md_table
|
272
|
+
doc.items.append temp_md_table
|
273
|
+
temp_md_table = nil
|
274
|
+
end
|
275
|
+
if temp_md_list
|
276
|
+
doc.items.append temp_md_list
|
277
|
+
temp_md_list = nil
|
278
|
+
end
|
279
|
+
|
280
|
+
text = '**TODO**: ' + res[1]
|
281
|
+
|
282
|
+
item = TodoBlock.new(text)
|
283
|
+
item.parent_doc = doc
|
284
|
+
item.parent_heading = doc.headings[-1]
|
285
|
+
doc.items.append(item)
|
286
|
+
doc.todo_blocks.append(item)
|
287
|
+
|
288
|
+
else # Reqular Paragraph
|
289
|
+
if temp_md_table
|
290
|
+
doc.items.append temp_md_table
|
291
|
+
temp_md_table = nil
|
292
|
+
end
|
293
|
+
if temp_md_list
|
294
|
+
if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
|
295
|
+
temp_md_list.addRow(s)
|
296
|
+
next
|
297
|
+
else
|
298
|
+
doc.items.append temp_md_list
|
299
|
+
temp_md_list = nil
|
300
|
+
end
|
301
|
+
end
|
302
|
+
if temp_code_block
|
303
|
+
temp_code_block.code_lines.append(s)
|
304
|
+
else
|
305
|
+
item = Paragraph.new(s)
|
306
|
+
item.parent_doc = doc
|
307
|
+
item.parent_heading = doc.headings[-1]
|
308
|
+
doc.items.append(item)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
elsif temp_md_list
|
312
|
+
doc.items.append temp_md_list
|
313
|
+
temp_md_list = nil # lists are separated by emty line from each other
|
314
|
+
end
|
315
|
+
end
|
316
|
+
# Finalize non-closed elements
|
317
|
+
if temp_md_table
|
318
|
+
doc.items.append temp_md_table
|
319
|
+
temp_md_table = nil
|
320
|
+
end
|
321
|
+
if temp_md_list
|
322
|
+
doc.items.append temp_md_list
|
323
|
+
temp_md_list = nil
|
324
|
+
end
|
325
|
+
if temp_code_block
|
326
|
+
doc.items.append temp_code_block
|
327
|
+
temp_code_block = nil
|
328
|
+
end
|
329
|
+
# Add footer to close opened tables if any
|
330
|
+
item = DocFooter.new
|
331
|
+
item.parent_doc = doc
|
332
|
+
doc.items.append(item)
|
333
|
+
end
|
334
|
+
end
|
@@ -1,16 +1,11 @@
|
|
1
1
|
|
2
2
|
class BaseDocument
|
3
3
|
|
4
|
-
attr_accessor :path
|
5
|
-
attr_accessor :items
|
6
|
-
attr_accessor :headings
|
7
4
|
attr_accessor :title
|
8
5
|
attr_accessor :id
|
9
6
|
attr_accessor :dom
|
10
7
|
|
11
|
-
def initialize(
|
12
|
-
|
13
|
-
@path = fele_path
|
8
|
+
def initialize()
|
14
9
|
@items = Array.new
|
15
10
|
@headings = Array.new
|
16
11
|
@title = ""
|
@@ -44,6 +39,27 @@ class BaseDocument
|
|
44
39
|
end
|
45
40
|
elsif s.include?('{{DOCUMENT_TITLE}}')
|
46
41
|
file.puts s.gsub! '{{DOCUMENT_TITLE}}', @title
|
42
|
+
elsif s.include?('{{STYLES_AND_SCRIPTS}}')
|
43
|
+
if @id == 'index'
|
44
|
+
file.puts '<script type="module" src="./scripts/orama_search.js"></script>'
|
45
|
+
file.puts '<link rel="stylesheet" href="./css/search.css">'
|
46
|
+
file.puts '<link rel="stylesheet" href="./css/main.css">'
|
47
|
+
file.puts '<script src="./scripts/main.js"></script>'
|
48
|
+
elsif self.instance_of? Specification
|
49
|
+
file.puts '<link rel="stylesheet" href="../../css/main.css">'
|
50
|
+
file.puts '<script src="../../scripts/main.js"></script>'
|
51
|
+
elsif self.instance_of? Traceability
|
52
|
+
file.puts '<link rel="stylesheet" href="../../css/main.css">'
|
53
|
+
file.puts '<script src="../../scripts/main.js"></script>'
|
54
|
+
elsif self.instance_of? Coverage
|
55
|
+
file.puts '<link rel="stylesheet" href="../../css/main.css">'
|
56
|
+
file.puts '<script src="../../scripts/main.js"></script>'
|
57
|
+
elsif self.instance_of? Protocol
|
58
|
+
file.puts '<link rel="stylesheet" href="../../../css/main.css">'
|
59
|
+
file.puts '<script src="../../../scripts/main.js"></script>'
|
60
|
+
end
|
61
|
+
elsif s.include?('{{GEM_VERSION}}')
|
62
|
+
file.puts "(" + Gem.loaded_specs['Almirah'].version.version + ")"
|
47
63
|
else
|
48
64
|
file.puts s
|
49
65
|
end
|
@@ -4,16 +4,12 @@ class Coverage < BaseDocument
|
|
4
4
|
|
5
5
|
attr_accessor :top_doc
|
6
6
|
attr_accessor :bottom_doc
|
7
|
-
attr_accessor :items
|
8
7
|
|
9
8
|
def initialize(top_doc)
|
10
|
-
|
9
|
+
super()
|
11
10
|
@top_doc = top_doc
|
12
11
|
@bottom_doc = bottom_doc
|
13
12
|
|
14
|
-
@items = Array.new
|
15
|
-
@headings = Array.new
|
16
|
-
|
17
13
|
@id = top_doc.id + "-" + "tests"
|
18
14
|
@title = "Coverage Matrix: " + @id
|
19
15
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative "base_document"
|
2
|
+
|
3
|
+
class PersistentDocument < BaseDocument
|
4
|
+
|
5
|
+
attr_accessor :path
|
6
|
+
attr_accessor :items
|
7
|
+
attr_accessor :controlled_items
|
8
|
+
attr_accessor :headings
|
9
|
+
attr_accessor :up_link_docs
|
10
|
+
|
11
|
+
def initialize(fele_path)
|
12
|
+
super()
|
13
|
+
@path = fele_path
|
14
|
+
@items = []
|
15
|
+
@controlled_items = []
|
16
|
+
@headings = []
|
17
|
+
@up_link_docs = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -1,22 +1,10 @@
|
|
1
|
-
require_relative "
|
1
|
+
require_relative "persistent_document"
|
2
2
|
|
3
|
-
class Protocol <
|
4
|
-
|
5
|
-
attr_accessor :up_link_doc_id
|
6
|
-
#attr_accessor :dictionary
|
7
|
-
attr_accessor :controlled_items
|
3
|
+
class Protocol < PersistentDocument
|
8
4
|
|
9
5
|
def initialize(fele_path)
|
10
|
-
|
11
|
-
@path = fele_path
|
12
|
-
@title = ""
|
13
|
-
@items = Array.new
|
14
|
-
@headings = Array.new
|
15
|
-
@controlled_items = Array.new
|
16
|
-
#@dictionary = Hash.new
|
17
|
-
|
6
|
+
super
|
18
7
|
@id = File.basename(fele_path, File.extname(fele_path)).downcase
|
19
|
-
@up_link_doc_id = Hash.new
|
20
8
|
end
|
21
9
|
|
22
10
|
def to_html(nav_pane, output_file_path)
|
@@ -1,10 +1,8 @@
|
|
1
|
-
require_relative "
|
1
|
+
require_relative "persistent_document"
|
2
2
|
|
3
|
-
class Specification <
|
3
|
+
class Specification < PersistentDocument
|
4
4
|
|
5
|
-
attr_accessor :up_link_doc_id
|
6
5
|
attr_accessor :dictionary
|
7
|
-
attr_accessor :controlled_items
|
8
6
|
attr_accessor :todo_blocks
|
9
7
|
attr_accessor :wrong_links_hash
|
10
8
|
|
@@ -18,12 +16,7 @@ class Specification < BaseDocument
|
|
18
16
|
attr_accessor :color
|
19
17
|
|
20
18
|
def initialize(fele_path)
|
21
|
-
|
22
|
-
@path = fele_path
|
23
|
-
@title = ""
|
24
|
-
@items = Array.new
|
25
|
-
@headings = Array.new
|
26
|
-
@controlled_items = Array.new
|
19
|
+
super
|
27
20
|
@dictionary = Hash.new
|
28
21
|
@duplicates_list = Array.new
|
29
22
|
@todo_blocks = Array.new
|
@@ -39,7 +32,6 @@ class Specification < BaseDocument
|
|
39
32
|
@color = 'bbb'
|
40
33
|
|
41
34
|
@id = File.basename(fele_path, File.extname(fele_path)).downcase
|
42
|
-
@up_link_doc_id = Hash.new
|
43
35
|
end
|
44
36
|
|
45
37
|
def to_console
|
@@ -9,15 +9,12 @@ class Traceability < BaseDocument
|
|
9
9
|
attr_accessor :traced_items
|
10
10
|
|
11
11
|
def initialize(top_doc, bottom_doc, is_agregated)
|
12
|
-
|
12
|
+
super()
|
13
13
|
@top_doc = top_doc
|
14
14
|
@bottom_doc = bottom_doc
|
15
15
|
@is_agregated = is_agregated
|
16
16
|
@traced_items = {}
|
17
17
|
|
18
|
-
@items = Array.new
|
19
|
-
@headings = Array.new
|
20
|
-
|
21
18
|
if @is_agregated
|
22
19
|
@id = top_doc.id + "-all"
|
23
20
|
else
|
data/lib/almirah/dom/document.rb
CHANGED
@@ -49,7 +49,7 @@ class Document
|
|
49
49
|
|
50
50
|
def section_tree_to_html
|
51
51
|
s = ''
|
52
|
-
s += "<a href=\"\#" + @root_section.heading.anchor_id.to_s + "\">" + @root_section.heading.
|
52
|
+
s += "<a href=\"\#" + @root_section.heading.anchor_id.to_s + "\">" + @root_section.heading.get_section_info + "</a>\n"
|
53
53
|
if @root_section.sections.length >0
|
54
54
|
s += "\t<ul class=\"fa-ul\" style=\"margin-top: 2px;\">\n"
|
55
55
|
@root_section.sections.each do |sub_section|
|