Almirah 0.1.6 → 0.1.8

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