Almirah 0.1.6 → 0.1.8

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.
@@ -1,377 +1,370 @@
1
- #
2
- require_relative "doc_types/base_document"
3
- require_relative "doc_types/specification"
4
- require_relative "doc_types/protocol"
5
- #
6
- require_relative "doc_items/text_line"
7
- require_relative "doc_items/doc_item"
8
- require_relative "doc_items/heading"
9
- require_relative "doc_items/paragraph"
10
- require_relative "doc_items/blockquote"
11
- require_relative "doc_items/code_block"
12
- require_relative "doc_items/todo_block"
13
- require_relative "doc_items/controlled_paragraph"
14
- require_relative "doc_items/markdown_table"
15
- require_relative "doc_items/controlled_table"
16
- require_relative "doc_items/image"
17
- require_relative "doc_items/markdown_list"
18
- require_relative "doc_items/doc_footer"
19
-
20
- require_relative "dom/document"
1
+ require_relative 'doc_types/base_document'
2
+ require_relative 'doc_types/specification'
3
+ require_relative 'doc_types/protocol'
4
+ require_relative 'doc_items/text_line'
5
+ require_relative 'doc_items/doc_item'
6
+ require_relative 'doc_items/heading'
7
+ require_relative 'doc_items/paragraph'
8
+ require_relative 'doc_items/blockquote'
9
+ require_relative 'doc_items/code_block'
10
+ require_relative 'doc_items/todo_block'
11
+ require_relative 'doc_items/controlled_paragraph'
12
+ require_relative 'doc_items/markdown_table'
13
+ require_relative 'doc_items/controlled_table'
14
+ require_relative 'doc_items/image'
15
+ require_relative 'doc_items/markdown_list'
16
+ require_relative 'doc_items/doc_footer'
17
+
18
+ require_relative 'dom/document'
21
19
 
22
20
  class DocFabric
21
+ @@color_index = 0
22
+ @@spec_colors = %w[cff4d2 fbeee6 ffcad4 bce6ff e4dfd9 f9e07f cbe54e d3e7ee eab595 86e3c3
23
+ ffdca2 ffffff ffdd94 d0e6a5 ffb284 f3dbcf c9bbc8 c6c09c]
23
24
 
24
- def self.add_lazy_doc_id(path)
25
- if res = /(\w+)[.]md$/.match(path)
26
- TextLine.add_lazy_doc_id(res[1])
27
- end
25
+ def self.add_lazy_doc_id(path)
26
+ if res = /(\w+)[.]md$/.match(path)
27
+ TextLine.add_lazy_doc_id(res[1])
28
28
  end
29
+ end
30
+
31
+ def self.create_specification(path)
32
+ color = @@spec_colors[@@color_index]
33
+ @@color_index += 1
34
+ @@color_index = 0 if @@color_index >= @@spec_colors.length
35
+ doc = Specification.new path
36
+ DocFabric.parse_document doc
37
+ doc.color = color
38
+ doc
39
+ end
40
+
41
+ def self.create_protocol(path)
42
+ doc = Protocol.new path
43
+ DocFabric.parse_document doc
44
+ doc
45
+ end
46
+
47
+ def self.parse_document(doc)
48
+ temp_md_table = nil
49
+ temp_md_list = nil
50
+ temp_code_block = nil
51
+
52
+ file = File.open(doc.path)
53
+ file_lines = file.readlines
54
+ file.close
55
+
56
+ file_lines.each do |s|
57
+ if s.lstrip != ''
58
+ if res = /^(\#{1,})\s(.*)/.match(s) # Heading
59
+
60
+ if temp_md_table
61
+ doc.items.append temp_md_table
62
+ temp_md_table = nil
63
+ end
64
+ if temp_md_list
65
+ doc.items.append temp_md_list
66
+ temp_md_list = nil
67
+ end
68
+
69
+ level = res[1].length
70
+ value = res[2]
71
+
72
+ if level == 1 && doc.title == ''
73
+ doc.title = value
74
+ level = 0 # Doc Title is a Root
75
+ Heading.reset_global_section_number
76
+ end
77
+
78
+ item = Heading.new(value, level)
79
+ item.parent_doc = doc
80
+ doc.items.append(item)
81
+ doc.headings.append(item)
82
+
83
+ elsif res = /^%\s(.*)/.match(s) # Pandoc Document Title
84
+
85
+ title = res[1]
86
+
87
+ if doc.title == ''
88
+ doc.title = title
89
+ Heading.reset_global_section_number
90
+ end
91
+
92
+ item = Heading.new(title, 0)
93
+ item.parent_doc = doc
94
+ doc.items.append(item)
95
+ doc.headings.append(item)
96
+
97
+ Heading.reset_global_section_number # Pandoc Document Title is not a section, so it shall not be taken into account in numbering
98
+
99
+ elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
100
+
101
+ if temp_md_table
102
+ doc.items.append temp_md_table
103
+ temp_md_table = nil
104
+ end
105
+ if temp_md_list
106
+ doc.items.append temp_md_list
107
+ temp_md_list = nil
108
+ end
109
+
110
+ id = res[1]
111
+ text = res[2]
112
+ up_links = nil
113
+
114
+ # check if it contains the uplink (one or many)
115
+ # TODO: check this regular expression
116
+ first_pos = text.length # for trailing commas
117
+ tmp = text.scan(/(>\[(?>[^\[\]]|\g<0>)*\])/) # >[SRS-001], >[SYS-002]
118
+ if tmp.length > 0
119
+ up_links = []
120
+ tmp.each do |ul|
121
+ up_links.append(ul[0])
122
+ # try to find the real end of text
123
+ pos = text.index(ul[0])
124
+ first_pos = pos if pos < first_pos
125
+ # remove uplink from text
126
+ text = text.split(ul[0]).join('')
127
+ end
128
+ # remove trailing commas and spaces
129
+ if text.length > first_pos
130
+ first_pos -= 1
131
+ text = text[0..first_pos].strip
132
+ end
133
+ end
29
134
 
30
- def self.create_specification(path)
31
- doc = Specification.new path
32
- DocFabric.parse_document doc
33
- return doc
34
- end
135
+ # since we already know id and text
136
+ item = ControlledParagraph.new(text, id)
35
137
 
36
- def self.create_protocol(path)
37
- doc = Protocol.new path
38
- DocFabric.parse_document doc
39
- return doc
40
- end
138
+ if up_links
139
+ doc.items_with_uplinks_number += 1 # for statistics
140
+ up_links.each do |ul|
141
+ next unless tmp = />\[(\S*)\]$/.match(ul) # >[SRS-001]
142
+
143
+ up_link_id = tmp[1]
41
144
 
42
- def self.parse_document(doc)
43
-
44
- tempMdTable = nil
45
- tempMdList = nil
46
- tempCodeBlock = nil
47
-
48
- file = File.open( doc.path )
49
- file_lines = file.readlines
50
- file.close
51
-
52
- file_lines.each do |s|
53
- if s.lstrip != ""
54
- if res = /^([#]{1,})\s(.*)/.match(s) # Heading
55
-
56
- if tempMdTable
57
- doc.items.append tempMdTable
58
- tempMdTable = nil
59
- end
60
- if tempMdList
61
- doc.items.append tempMdList
62
- tempMdList = nil
63
- end
64
-
65
- level = res[1].length
66
- value = res[2]
67
-
68
- if level == 1 && doc.title == ""
69
- doc.title = value
70
- level = 0 # Doc Title is a Root
71
- Heading.reset_global_section_number()
72
- end
73
-
74
- item = Heading.new(value, level)
75
- item.parent_doc = doc
76
- doc.items.append(item)
77
- doc.headings.append(item)
78
-
79
- elsif res = /^\%\s(.*)/.match(s) # Pandoc Document Title
80
-
81
- title = res[1]
82
-
83
- if doc.title == ""
84
- doc.title = title
85
- Heading.reset_global_section_number()
86
- end
87
-
88
- item = Heading.new(title, 0)
89
- item.parent_doc = doc
90
- doc.items.append(item)
91
- doc.headings.append(item)
92
-
93
- Heading.reset_global_section_number() # Pandoc Document Title is not a section, so it shall not be taken into account in numbering
94
-
95
- elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
96
-
97
- if tempMdTable
98
- doc.items.append tempMdTable
99
- tempMdTable = nil
100
- end
101
- if tempMdList
102
- doc.items.append tempMdList
103
- tempMdList = nil
104
- end
105
-
106
- id = res[1]
107
- text = res[2]
108
- up_links = nil
109
-
110
- #check if it contains the uplink (one or many)
111
- #TODO: check this regular expression
112
- first_pos = text.length # for trailing commas
113
- tmp = text.scan( /(>\[(?>[^\[\]]|\g<0>)*\])/ ) # >[SRS-001], >[SYS-002]
114
- if tmp.length >0
115
- up_links = Array.new
116
- tmp.each do |ul|
117
- up_links.append(ul[0])
118
- # try to find the real end of text
119
- pos = text.index(ul[0])
120
- if pos < first_pos
121
- first_pos = pos
122
- end
123
- # remove uplink from text
124
- text = text.split(ul[0]).join("")
125
- end
126
- # remove trailing commas and spaces
127
- if text.length > first_pos
128
- first_pos -= 1
129
- text = text[0..first_pos].strip
130
- end
131
- end
132
-
133
- # since we already know id and text
134
- item = ControlledParagraph.new( text, id )
135
-
136
- if up_links
137
- doc.items_with_uplinks_number += 1 #for statistics
138
- up_links.each do |ul|
139
- if tmp = />\[(\S*)\]$/.match(ul) # >[SRS-001]
140
- up_link_id = tmp[1]
141
-
142
- unless item.up_link_ids
143
- item.up_link_ids = Array.new
144
- end
145
-
146
- item.up_link_ids.append(up_link_id)
147
-
148
- if tmp = /^([a-zA-Z]+)[-]\d+/.match(up_link_id) # SRS
149
- doc.up_link_doc_id[ tmp[1].downcase.to_s ] = tmp[1].downcase # multiple documents could be up-linked
150
- end
151
- end
152
- end
153
- end
154
-
155
-
156
- item.parent_doc = doc
157
- item.parent_heading = doc.headings[-1]
158
-
159
- doc.items.append(item)
160
- #for statistics
161
- if doc.dictionary.has_key?( id.to_s )
162
- doc.duplicated_ids_number += 1
163
- doc.duplicates_list.append(item)
164
- else
165
- doc.dictionary[ id.to_s ] = item #for fast search
166
- end
167
- doc.controlled_items.append(item) #for fast search
168
-
169
- #for statistics
170
- n = /\d+/.match(id)[0].to_i
171
- if n > doc.last_used_id_number
172
- doc.last_used_id = id
173
- doc.last_used_id_number = n
174
- end
175
-
176
- elsif res = /^[!]\[(.*)\]\((.*)\)/.match(s) # Image
177
-
178
- if tempMdTable
179
- doc.items.append tempMdTable
180
- tempMdTable = nil
181
- end
182
- if tempMdList
183
- doc.items.append tempMdList
184
- tempMdList = nil
185
- end
186
-
187
- img_text = res[1]
188
- img_path = res[2]
189
-
190
- item = Image.new( img_text, img_path )
191
- item.parent_doc = doc
192
-
193
- doc.items.append(item)
194
-
195
- elsif res = /^(\*\s+)(.*)/.match(s) #check if unordered list start
196
-
197
- if tempMdTable
198
- doc.items.append tempMdTable
199
- tempMdTable = nil
200
- end
201
-
202
- row = res[2]
203
-
204
- if tempMdList
205
- tempMdList.addRow(s)
206
- else
207
- item = MarkdownList.new(false)
208
- item.addRow(s)
209
- item.parent_doc = doc
210
- tempMdList = item
211
- end
212
-
213
- elsif res = /^\d[.]\s(.*)/.match(s) #check if ordered list start
214
-
215
- if tempMdTable
216
- doc.items.append tempMdTable
217
- tempMdTable = nil
218
- end
219
-
220
- row = res[1]
221
-
222
- if tempMdList
223
- tempMdList.addRow(s)
224
- else
225
- item = MarkdownList.new(true)
226
- item.addRow(s)
227
- item.parent_doc = doc
228
- tempMdList = item
229
- end
230
-
231
- elsif s[0] == '|' #check if table
232
-
233
- if tempMdList
234
- doc.items.append tempMdList
235
- tempMdList = nil
236
- end
237
-
238
- if res = /^[|](-{3,})[|]/.match(s) #check if it is a separator first
239
-
240
- if tempMdTable
241
- #separator is found after heading - just skip it
242
- else
243
- #separator out of table scope consider it just as a regular paragraph
244
- item = Paragraph.new(s)
245
- item.parent_doc = doc
246
- doc.items.append(item)
247
- end
248
-
249
- elsif res = /^[|](.*[|])/.match(s) #check if it looks as a table
250
-
251
- row = res[1]
252
-
253
- if tempMdTable
254
- # check if it is a controlled table
255
- unless tempMdTable.addRow(row)
256
- tempMdTable = ControlledTable.new(tempMdTable, doc)
257
- tempMdTable.parent_doc = doc
258
- tempMdTable.addRow(row)
259
- end
260
- else
261
- #start table from heading
262
- tempMdTable = MarkdownTable.new(row)
263
- tempMdTable.parent_doc = doc
264
- end
265
- end
266
-
267
- elsif res = /^[>](.*)/.match(s) #check if blockquote
268
-
269
- if tempMdTable
270
- doc.items.append tempMdTable
271
- tempMdTable = nil
272
- end
273
- if tempMdList
274
- doc.items.append tempMdList
275
- tempMdList = nil
276
- end
277
-
278
- item = Blockquote.new(res[1])
279
- item.parent_doc = doc
280
- doc.items.append(item)
281
-
282
- elsif res = /^```(\w*)/.match(s) #check if code block
283
-
284
- if tempMdTable
285
- doc.items.append tempMdTable
286
- tempMdTable = nil
287
- end
288
- if tempMdList
289
- doc.items.append tempMdList
290
- tempMdList = nil
291
- end
292
-
293
- suggested_format = ""
294
- if res.length == 2
295
- suggested_format = res[1]
296
- end
297
-
298
- if tempCodeBlock
299
- # close already opened block
300
- doc.items.append(tempCodeBlock)
301
- tempCodeBlock = nil
302
- else
303
- #start code block
304
- tempCodeBlock = CodeBlock.new(suggested_format)
305
- tempCodeBlock.parent_doc = doc
306
- end
307
-
308
- elsif res = /^TODO\:(.*)/.match(s) #check if TODO block
309
-
310
- if tempMdTable
311
- doc.items.append tempMdTable
312
- tempMdTable = nil
313
- end
314
- if tempMdList
315
- doc.items.append tempMdList
316
- tempMdList = nil
317
- end
318
-
319
- text = "**TODO**: " + res[1]
320
-
321
- item = TodoBlock.new(text)
322
- item.parent_doc = doc
323
- doc.items.append(item)
324
- doc.todo_blocks.append(item)
325
-
326
- else # Reqular Paragraph
327
- if tempMdTable
328
- doc.items.append tempMdTable
329
- tempMdTable = nil
330
- end
331
- if tempMdList
332
- if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
333
- tempMdList.addRow(s)
334
- next
335
- else
336
- doc.items.append tempMdList
337
- tempMdList = nil
338
- end
339
- end
340
- if tempCodeBlock
341
- tempCodeBlock.code_lines.append(s)
342
- else
343
- item = Paragraph.new(s)
344
- item.parent_doc = doc
345
- doc.items.append(item)
346
- end
347
- end
145
+ item.up_link_ids = [] unless item.up_link_ids
146
+
147
+ item.up_link_ids.append(up_link_id)
148
+
149
+ if tmp = /^([a-zA-Z]+)-\d+/.match(up_link_id) # SRS
150
+ doc.up_link_doc_id[tmp[1].downcase.to_s] = tmp[1].downcase # multiple documents could be up-linked
151
+ end
152
+ end
153
+ end
154
+
155
+ item.parent_doc = doc
156
+ item.parent_heading = doc.headings[-1]
157
+
158
+ doc.items.append(item)
159
+ # for statistics
160
+ if doc.dictionary.has_key?(id.to_s)
161
+ doc.duplicated_ids_number += 1
162
+ doc.duplicates_list.append(item)
163
+ else
164
+ doc.dictionary[id.to_s] = item # for fast search
165
+ end
166
+ doc.controlled_items.append(item) # for fast search
167
+
168
+ # for statistics
169
+ n = /\d+/.match(id)[0].to_i
170
+ if n > doc.last_used_id_number
171
+ doc.last_used_id = id
172
+ doc.last_used_id_number = n
173
+ end
174
+
175
+ elsif res = /^!\[(.*)\]\((.*)\)/.match(s) # Image
176
+
177
+ if temp_md_table
178
+ doc.items.append temp_md_table
179
+ temp_md_table = nil
180
+ end
181
+ if temp_md_list
182
+ doc.items.append temp_md_list
183
+ temp_md_list = nil
184
+ end
185
+
186
+ img_text = res[1]
187
+ img_path = res[2]
188
+
189
+ item = Image.new(img_text, img_path)
190
+ item.parent_doc = doc
191
+
192
+ doc.items.append(item)
193
+
194
+ elsif res = /^(\*\s+)(.*)/.match(s) # check if unordered list start
195
+
196
+ if temp_md_table
197
+ doc.items.append temp_md_table
198
+ temp_md_table = nil
199
+ end
200
+
201
+ row = res[2]
202
+
203
+ if temp_md_list
204
+ temp_md_list.addRow(s)
205
+ else
206
+ item = MarkdownList.new(false)
207
+ item.addRow(s)
208
+ item.parent_doc = doc
209
+ temp_md_list = item
210
+ end
211
+
212
+ elsif res = /^\d[.]\s(.*)/.match(s) # check if ordered list start
213
+
214
+ if temp_md_table
215
+ doc.items.append temp_md_table
216
+ temp_md_table = nil
217
+ end
218
+
219
+ row = res[1]
220
+
221
+ if temp_md_list
222
+ temp_md_list.addRow(s)
223
+ else
224
+ item = MarkdownList.new(true)
225
+ item.addRow(s)
226
+ item.parent_doc = doc
227
+ temp_md_list = item
228
+ end
229
+
230
+ elsif s[0] == '|' # check if table
231
+
232
+ if temp_md_list
233
+ doc.items.append temp_md_list
234
+ temp_md_list = nil
235
+ end
236
+
237
+ if res = /^[|](-{3,})[|]/.match(s) # check if it is a separator first
238
+
239
+ if temp_md_table
240
+ # separator is found after heading - just skip it
348
241
  else
349
- if tempMdList # lists are separated by emty line from each other
350
- doc.items.append tempMdList
351
- tempMdList = nil
352
- end
242
+ # separator out of table scope consider it just as a regular paragraph
243
+ item = Paragraph.new(s)
244
+ item.parent_doc = doc
245
+ doc.items.append(item)
353
246
  end
247
+
248
+ elsif res = /^[|](.*[|])/.match(s) # check if it looks as a table
249
+
250
+ row = res[1]
251
+
252
+ if temp_md_table
253
+ # check if it is a controlled table
254
+ unless temp_md_table.addRow(row)
255
+ temp_md_table = ControlledTable.new(temp_md_table, doc)
256
+ temp_md_table.parent_doc = doc
257
+ temp_md_table.addRow(row)
258
+ end
259
+ else
260
+ # start table from heading
261
+ temp_md_table = MarkdownTable.new(row)
262
+ temp_md_table.parent_doc = doc
263
+ end
264
+ end
265
+
266
+ elsif res = /^>(.*)/.match(s) # check if blockquote
267
+
268
+ if temp_md_table
269
+ doc.items.append temp_md_table
270
+ temp_md_table = nil
271
+ end
272
+ if temp_md_list
273
+ doc.items.append temp_md_list
274
+ temp_md_list = nil
275
+ end
276
+
277
+ item = Blockquote.new(res[1])
278
+ item.parent_doc = doc
279
+ doc.items.append(item)
280
+
281
+ elsif res = /^```(\w*)/.match(s) # check if code block
282
+
283
+ if temp_md_table
284
+ doc.items.append temp_md_table
285
+ temp_md_table = nil
286
+ end
287
+ if temp_md_list
288
+ doc.items.append temp_md_list
289
+ temp_md_list = nil
290
+ end
291
+
292
+ suggested_format = ''
293
+ suggested_format = res[1] if res.length == 2
294
+
295
+ if temp_code_block
296
+ # close already opened block
297
+ doc.items.append(temp_code_block)
298
+ temp_code_block = nil
299
+ else
300
+ # start code block
301
+ temp_code_block = CodeBlock.new(suggested_format)
302
+ temp_code_block.parent_doc = doc
303
+ end
304
+
305
+ elsif res = /^TODO:(.*)/.match(s) # check if TODO block
306
+
307
+ if temp_md_table
308
+ doc.items.append temp_md_table
309
+ temp_md_table = nil
310
+ end
311
+ if temp_md_list
312
+ doc.items.append temp_md_list
313
+ temp_md_list = 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
+
323
+ else # Reqular Paragraph
324
+ if temp_md_table
325
+ doc.items.append temp_md_table
326
+ temp_md_table = nil
327
+ end
328
+ if temp_md_list
329
+ if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
330
+ temp_md_list.addRow(s)
331
+ next
332
+ else
333
+ doc.items.append temp_md_list
334
+ temp_md_list = nil
335
+ end
336
+ end
337
+ if temp_code_block
338
+ temp_code_block.code_lines.append(s)
339
+ else
340
+ item = Paragraph.new(s)
341
+ item.parent_doc = doc
342
+ doc.items.append(item)
343
+ end
354
344
  end
355
- # Finalize non-closed elements
356
- if tempMdTable
357
- doc.items.append tempMdTable
358
- tempMdTable = nil
359
- end
360
- if tempMdList
361
- doc.items.append tempMdList
362
- tempMdList = nil
363
- end
364
- if tempCodeBlock
365
- doc.items.append tempCodeBlock
366
- tempCodeBlock = nil
367
- end
368
- # Add footer to close opened tables if any
369
- item = DocFooter.new
370
- item.parent_doc = doc
371
- doc.items.append(item)
372
- # Build dom
373
- if doc.is_a?(Specification)
374
- doc.dom = Document.new(doc.headings)
375
- end
345
+ elsif temp_md_list
346
+ doc.items.append temp_md_list
347
+ temp_md_list = nil # lists are separated by emty line from each other
348
+ end
349
+ end
350
+ # Finalize non-closed elements
351
+ if temp_md_table
352
+ doc.items.append temp_md_table
353
+ temp_md_table = nil
354
+ end
355
+ if temp_md_list
356
+ doc.items.append temp_md_list
357
+ temp_md_list = nil
358
+ end
359
+ if temp_code_block
360
+ doc.items.append temp_code_block
361
+ temp_code_block = nil
376
362
  end
377
- end
363
+ # Add footer to close opened tables if any
364
+ item = DocFooter.new
365
+ item.parent_doc = doc
366
+ doc.items.append(item)
367
+ # Build dom
368
+ doc.dom = Document.new(doc.headings) if doc.is_a?(Specification)
369
+ end
370
+ end