Almirah 0.2.5 → 0.2.6

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/bin/almirah +4 -4
  3. data/lib/almirah/doc_fabric.rb +65 -65
  4. data/lib/almirah/doc_items/blockquote.rb +21 -21
  5. data/lib/almirah/doc_items/code_block.rb +26 -26
  6. data/lib/almirah/doc_items/controlled_paragraph.rb +112 -112
  7. data/lib/almirah/doc_items/controlled_table.rb +224 -224
  8. data/lib/almirah/doc_items/controlled_table_row.rb +22 -22
  9. data/lib/almirah/doc_items/doc_footer.rb +16 -16
  10. data/lib/almirah/doc_items/doc_item.rb +22 -22
  11. data/lib/almirah/doc_items/frontmatter.rb +9 -9
  12. data/lib/almirah/doc_items/heading.rb +93 -93
  13. data/lib/almirah/doc_items/image.rb +27 -27
  14. data/lib/almirah/doc_items/markdown_list.rb +156 -156
  15. data/lib/almirah/doc_items/markdown_table.rb +61 -61
  16. data/lib/almirah/doc_items/paragraph.rb +25 -25
  17. data/lib/almirah/doc_items/text_line.rb +296 -296
  18. data/lib/almirah/doc_items/todo_block.rb +21 -21
  19. data/lib/almirah/doc_parser.rb +378 -378
  20. data/lib/almirah/doc_types/base_document.rb +64 -64
  21. data/lib/almirah/doc_types/coverage.rb +95 -80
  22. data/lib/almirah/doc_types/index.rb +173 -173
  23. data/lib/almirah/doc_types/persistent_document.rb +17 -17
  24. data/lib/almirah/doc_types/protocol.rb +24 -24
  25. data/lib/almirah/doc_types/specification.rb +67 -67
  26. data/lib/almirah/doc_types/traceability.rb +142 -142
  27. data/lib/almirah/dom/doc_section.rb +25 -25
  28. data/lib/almirah/dom/document.rb +78 -78
  29. data/lib/almirah/navigation_pane.rb +16 -16
  30. data/lib/almirah/project.rb +287 -287
  31. data/lib/almirah/project_configuration.rb +41 -41
  32. data/lib/almirah/project_template.rb +298 -298
  33. data/lib/almirah/project_utility.rb +52 -0
  34. data/lib/almirah/search/specifications_db.rb +79 -79
  35. data/lib/almirah/templates/css/main.css +300 -300
  36. data/lib/almirah/templates/css/search.css +40 -40
  37. data/lib/almirah/templates/page.html +42 -42
  38. data/lib/almirah/templates/scripts/main.js +111 -111
  39. data/lib/almirah/templates/scripts/orama_search.js +138 -138
  40. data/lib/almirah.rb +93 -58
  41. metadata +4 -3
@@ -1,378 +1,378 @@
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
- require_relative 'doc_items/frontmatter'
15
-
16
- class DocParser # rubocop:disable Metrics/ClassLength,Style/Documentation
17
- def self.try_to_extract_frontmatter(doc, text_lines) # rubocop:disable Metrics/MethodLength
18
- lines_to_remove = 0
19
- frontmatter_lines = ''
20
- if /^(-{3,})/.match(text_lines[0])
21
- frontmatter_started = false
22
- text_lines.each do |s|
23
- lines_to_remove += 1
24
- if /^(-{3,})/.match(s)
25
- if frontmatter_started
26
- doc.frontmatter = Frontmatter.new(frontmatter_lines)
27
- frontmatter_started = false
28
- break
29
- else
30
- frontmatter_started = true
31
- end
32
- elsif frontmatter_started
33
- frontmatter_lines += s
34
- end
35
- end
36
- end
37
- text_lines.shift(lines_to_remove)
38
- text_lines
39
- end
40
-
41
- def self.parse(doc, text_lines)
42
- temp_md_table = nil
43
- temp_md_list = nil
44
- temp_code_block = nil
45
- # restart section numbering for each new document
46
- Heading.reset_global_section_number
47
- # try to get frontmatter first
48
- text_lines = try_to_extract_frontmatter(doc, text_lines)
49
- # There is no document without heading
50
- title = "#{doc.id}.md"
51
- item = Heading.new(doc, title, 0)
52
- doc.items.append(item)
53
- doc.headings.append(item)
54
- doc.title = title
55
- # replace dummy title with extracted from frontmatter
56
- if doc.frontmatter && (doc.frontmatter.parameters.key? 'title')
57
- doc.title = doc.frontmatter.parameters['title']
58
- doc.headings[0].text = doc.frontmatter.parameters['title']
59
- end
60
- # main loop
61
- text_lines.each do |s|
62
- if s.lstrip != ''
63
- if res = /^(\#{1,})\s(.*)/.match(s) # Heading
64
-
65
- temp_md_table = process_temp_table(doc, temp_md_table)
66
- if temp_md_list
67
- doc.items.append temp_md_list
68
- temp_md_list = nil
69
- end
70
-
71
- level = res[1].length
72
- value = res[2]
73
-
74
- item = Heading.new(doc, value, level)
75
- doc.items.append(item)
76
- doc.headings.append(item)
77
-
78
- elsif res = /^%\s(.*)/.match(s) # Pandoc Document Title
79
-
80
- title = res[1]
81
-
82
- # Rewrite
83
- doc.title = title
84
- doc.headings[0].text = title
85
-
86
- elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
87
-
88
- temp_md_table = process_temp_table(doc, temp_md_table)
89
- if temp_md_list
90
- doc.items.append temp_md_list
91
- temp_md_list = nil
92
- end
93
-
94
- id = res[1].upcase
95
- text = res[2]
96
- up_links = nil
97
-
98
- # check if it contains the uplink (one or many)
99
- # TODO: check this regular expression
100
- first_pos = text.length # for trailing commas
101
- tmp = text.scan(/(>\[(?>[^\[\]]|\g<0>)*\])/) # >[SRS-001], >[SYS-002]
102
- if tmp.length > 0
103
- up_links = []
104
- tmp.each do |ul|
105
- lnk = ul[0]
106
- # do not add links for the self document
107
- doc_id = /([a-zA-Z]+)-\d+/.match(lnk) # SRS
108
- up_links << lnk.upcase if doc_id and (doc_id[1].downcase != doc.id.downcase)
109
- # try to find the real end of text
110
- pos = text.index(lnk)
111
- first_pos = pos if pos < first_pos
112
- # remove uplink from text
113
- text = text.split(lnk, 1).join('')
114
- end
115
- # remove trailing commas and spaces
116
- if text.length > first_pos
117
- first_pos -= 1
118
- text = text[0..first_pos].strip
119
- end
120
- end
121
-
122
- # since we already know id and text
123
- item = ControlledParagraph.new(doc, text, id)
124
-
125
- if up_links
126
- up_links.uniq! # remove duplicates
127
- doc.items_with_uplinks_number += 1 # for statistics
128
- up_links.each do |ul|
129
- next unless tmp = />\[(\S*)\]$/.match(ul) # >[SRS-001]
130
-
131
- up_link_id = tmp[1]
132
-
133
- item.up_link_ids = [] unless item.up_link_ids
134
-
135
- item.up_link_ids.append(up_link_id)
136
-
137
- if tmp = /^([a-zA-Z]+)-\d+/.match(up_link_id) # SRS
138
- doc.up_link_docs[tmp[1].downcase.to_s] = tmp[1].downcase # multiple documents could be up-linked
139
- end
140
- end
141
- end
142
-
143
- doc.items.append(item)
144
- # for statistics
145
- if doc.dictionary.has_key?(id.to_s)
146
- doc.duplicated_ids_number += 1
147
- doc.duplicates_list.append(item)
148
- else
149
- doc.dictionary[id.to_s] = item # for fast search
150
- end
151
- doc.controlled_items.append(item) # for fast search
152
-
153
- # for statistics
154
- n = /\d+/.match(id)[0].to_i
155
- if n > doc.last_used_id_number
156
- doc.last_used_id = id
157
- doc.last_used_id_number = n
158
- end
159
-
160
- elsif res = /^!\[(.*)\]\((.*)\)/.match(s) # Image
161
-
162
- temp_md_table = process_temp_table(doc, temp_md_table)
163
- if temp_md_list
164
- doc.items.append temp_md_list
165
- temp_md_list = nil
166
- end
167
-
168
- img_text = res[1]
169
- img_path = res[2]
170
-
171
- item = Image.new(img_text, img_path)
172
- item.parent_doc = doc
173
- item.parent_heading = doc.headings[-1]
174
-
175
- doc.items.append(item)
176
-
177
- elsif res = /^(\*\s+)(.*)/.match(s) # check if unordered list start
178
-
179
- if doc.title == ''
180
- # dummy section if root is not a Document Title (level 0)
181
- title = "#{doc.id}.md"
182
- item = Heading.new(doc, title, 0)
183
- doc.items.append(item)
184
- doc.headings.append(item)
185
- doc.title = title
186
- end
187
-
188
- temp_md_table = process_temp_table(doc, temp_md_table)
189
-
190
- row = res[2]
191
-
192
- if temp_md_list
193
- temp_md_list.add_row(s)
194
- else
195
- item = MarkdownList.new(doc, false)
196
- item.add_row(s)
197
- temp_md_list = item
198
- end
199
-
200
- elsif res = /^\d[.]\s(.*)/.match(s) # check if ordered list start
201
-
202
- temp_md_table = process_temp_table(doc, temp_md_table)
203
-
204
- row = res[1]
205
-
206
- if temp_md_list
207
- temp_md_list.add_row(s)
208
- else
209
- item = MarkdownList.new(doc, true)
210
- item.add_row(s)
211
- temp_md_list = item
212
- end
213
-
214
- elsif s[0] == '|' # check if table
215
-
216
- if doc.title == ''
217
- # dummy section if root is not a Document Title (level 0)
218
- title = "#{doc.id}.md"
219
- item = Heading.new(doc, title, 0)
220
- doc.items.append(item)
221
- doc.headings.append(item)
222
- doc.title = title
223
- end
224
-
225
- if temp_md_list
226
- doc.items.append temp_md_list
227
- temp_md_list = nil
228
- end
229
-
230
- if res = /^[|](-{3,})[|]/.match(s) # check if it is a separator first
231
-
232
- if temp_md_table
233
- # separator is found after heading
234
- temp_md_table.is_separator_detected = true
235
- else
236
- # separator out of table scope consider it just as a regular paragraph
237
- item = Paragraph.new(doc, s)
238
- doc.items.append(item)
239
- end
240
-
241
- elsif res = /^[|](.*[|])/.match(s) # check if it looks as a table row
242
-
243
- row = res[1]
244
-
245
- if temp_md_table
246
- if temp_md_table.is_separator_detected # if there is a separator
247
- # check if parent doc is a Protocol
248
- if doc.instance_of? Protocol
249
- # check if it is a controlled table
250
- tmp = /(.*)\s+>\[(\S*)\]/.match(row)
251
- if tmp && (temp_md_table.instance_of? MarkdownTable)
252
- # this is not a regular Markdown table
253
- # so the table type shall be changed and this row shall be passed one more time
254
- temp_md_table = ControlledTable.new(doc, temp_md_table)
255
- end
256
- end
257
- temp_md_table.add_row(row)
258
- else
259
- # replece table heading with regular paragraph
260
- item = Paragraph.new(doc, temp_md_table.heading_row)
261
- doc.items.append(item)
262
- # and current row
263
- item = Paragraph.new(doc, s)
264
- doc.items.append(item)
265
- temp_md_table = nil
266
- end
267
- else
268
- # start table from heading
269
- temp_md_table = MarkdownTable.new(doc, s)
270
- end
271
- end
272
-
273
- elsif res = /^>(.*)/.match(s) # check if blockquote
274
-
275
- temp_md_table = process_temp_table(doc, temp_md_table)
276
-
277
- if temp_md_list
278
- doc.items.append temp_md_list
279
- temp_md_list = nil
280
- end
281
-
282
- item = Blockquote.new(res[1])
283
- item.parent_doc = doc
284
- item.parent_heading = doc.headings[-1]
285
- doc.items.append(item)
286
-
287
- elsif res = /^```(\w*)/.match(s) # check if code block
288
-
289
- temp_md_table = process_temp_table(doc, temp_md_table)
290
- if temp_md_list
291
- doc.items.append temp_md_list
292
- temp_md_list = nil
293
- end
294
-
295
- suggested_format = ''
296
- suggested_format = res[1] if res.length == 2
297
-
298
- if temp_code_block
299
- # close already opened block
300
- doc.items.append(temp_code_block)
301
- temp_code_block = nil
302
- else
303
- # start code block
304
- temp_code_block = CodeBlock.new(suggested_format)
305
- temp_code_block.parent_doc = doc
306
- temp_code_block.parent_heading = doc.headings[-1]
307
- end
308
-
309
- elsif res = /^TODO:(.*)/.match(s) # check if TODO block
310
-
311
- temp_md_table = process_temp_table(doc, temp_md_table)
312
- if temp_md_list
313
- doc.items.append temp_md_list
314
- temp_md_list = nil
315
- end
316
-
317
- text = '**TODO**: ' + res[1]
318
-
319
- item = TodoBlock.new(text)
320
- item.parent_doc = doc
321
- item.parent_heading = doc.headings[-1]
322
- doc.items.append(item)
323
- doc.todo_blocks.append(item)
324
-
325
- else # Reqular Paragraph
326
-
327
- temp_md_table = process_temp_table(doc, temp_md_table)
328
- if temp_md_list
329
- if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
330
- temp_md_list.add_row(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(doc, s)
341
- doc.items.append(item)
342
- end
343
- end
344
- elsif temp_md_list
345
- doc.items.append temp_md_list
346
- temp_md_list = nil # lists are separated by emty line from each other
347
- end
348
- end
349
- # Finalize non-closed elements
350
- temp_md_table = process_temp_table(doc, temp_md_table)
351
- if temp_md_list
352
- doc.items.append temp_md_list
353
- temp_md_list = nil
354
- end
355
- if temp_code_block
356
- doc.items.append temp_code_block
357
- temp_code_block = nil
358
- end
359
- # Add footer to close opened tables if any
360
- item = DocFooter.new
361
- item.parent_doc = doc
362
- doc.items.append(item)
363
- end
364
-
365
- def self.process_temp_table(doc, temp_md_table)
366
- if temp_md_table
367
- if temp_md_table.is_separator_detected
368
- doc.items.append temp_md_table
369
- else # no separator
370
- # replece table heading with regular paragraph
371
- item = Paragraph.new(doc, temp_md_table.heading_row)
372
- doc.items.append(item)
373
- end
374
- temp_md_table = nil
375
- end
376
- temp_md_table
377
- end
378
- end
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
+ require_relative 'doc_items/frontmatter'
15
+
16
+ class DocParser # rubocop:disable Metrics/ClassLength,Style/Documentation
17
+ def self.try_to_extract_frontmatter(doc, text_lines) # rubocop:disable Metrics/MethodLength
18
+ lines_to_remove = 0
19
+ frontmatter_lines = ''
20
+ if /^(-{3,})/.match(text_lines[0])
21
+ frontmatter_started = false
22
+ text_lines.each do |s|
23
+ lines_to_remove += 1
24
+ if /^(-{3,})/.match(s)
25
+ if frontmatter_started
26
+ doc.frontmatter = Frontmatter.new(frontmatter_lines)
27
+ frontmatter_started = false
28
+ break
29
+ else
30
+ frontmatter_started = true
31
+ end
32
+ elsif frontmatter_started
33
+ frontmatter_lines += s
34
+ end
35
+ end
36
+ end
37
+ text_lines.shift(lines_to_remove)
38
+ text_lines
39
+ end
40
+
41
+ def self.parse(doc, text_lines)
42
+ temp_md_table = nil
43
+ temp_md_list = nil
44
+ temp_code_block = nil
45
+ # restart section numbering for each new document
46
+ Heading.reset_global_section_number
47
+ # try to get frontmatter first
48
+ text_lines = try_to_extract_frontmatter(doc, text_lines)
49
+ # There is no document without heading
50
+ title = "#{doc.id}.md"
51
+ item = Heading.new(doc, title, 0)
52
+ doc.items.append(item)
53
+ doc.headings.append(item)
54
+ doc.title = title
55
+ # replace dummy title with extracted from frontmatter
56
+ if doc.frontmatter && (doc.frontmatter.parameters.key? 'title')
57
+ doc.title = doc.frontmatter.parameters['title']
58
+ doc.headings[0].text = doc.frontmatter.parameters['title']
59
+ end
60
+ # main loop
61
+ text_lines.each do |s|
62
+ if s.lstrip != ''
63
+ if res = /^(\#{1,})\s(.*)/.match(s) # Heading
64
+
65
+ temp_md_table = process_temp_table(doc, temp_md_table)
66
+ if temp_md_list
67
+ doc.items.append temp_md_list
68
+ temp_md_list = nil
69
+ end
70
+
71
+ level = res[1].length
72
+ value = res[2]
73
+
74
+ item = Heading.new(doc, value, level)
75
+ doc.items.append(item)
76
+ doc.headings.append(item)
77
+
78
+ elsif res = /^%\s(.*)/.match(s) # Pandoc Document Title
79
+
80
+ title = res[1]
81
+
82
+ # Rewrite
83
+ doc.title = title
84
+ doc.headings[0].text = title
85
+
86
+ elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
87
+
88
+ temp_md_table = process_temp_table(doc, temp_md_table)
89
+ if temp_md_list
90
+ doc.items.append temp_md_list
91
+ temp_md_list = nil
92
+ end
93
+
94
+ id = res[1].upcase
95
+ text = res[2]
96
+ up_links = nil
97
+
98
+ # check if it contains the uplink (one or many)
99
+ # TODO: check this regular expression
100
+ first_pos = text.length # for trailing commas
101
+ tmp = text.scan(/(>\[(?>[^\[\]]|\g<0>)*\])/) # >[SRS-001], >[SYS-002]
102
+ if tmp.length > 0
103
+ up_links = []
104
+ tmp.each do |ul|
105
+ lnk = ul[0]
106
+ # do not add links for the self document
107
+ doc_id = /([a-zA-Z]+)-\d+/.match(lnk) # SRS
108
+ up_links << lnk.upcase if doc_id and (doc_id[1].downcase != doc.id.downcase)
109
+ # try to find the real end of text
110
+ pos = text.index(lnk)
111
+ first_pos = pos if pos < first_pos
112
+ # remove uplink from text
113
+ text = text.split(lnk, 1).join('')
114
+ end
115
+ # remove trailing commas and spaces
116
+ if text.length > first_pos
117
+ first_pos -= 1
118
+ text = text[0..first_pos].strip
119
+ end
120
+ end
121
+
122
+ # since we already know id and text
123
+ item = ControlledParagraph.new(doc, text, id)
124
+
125
+ if up_links
126
+ up_links.uniq! # remove duplicates
127
+ doc.items_with_uplinks_number += 1 # for statistics
128
+ up_links.each do |ul|
129
+ next unless tmp = />\[(\S*)\]$/.match(ul) # >[SRS-001]
130
+
131
+ up_link_id = tmp[1]
132
+
133
+ item.up_link_ids = [] unless item.up_link_ids
134
+
135
+ item.up_link_ids.append(up_link_id)
136
+
137
+ if tmp = /^([a-zA-Z]+)-\d+/.match(up_link_id) # SRS
138
+ doc.up_link_docs[tmp[1].downcase.to_s] = tmp[1].downcase # multiple documents could be up-linked
139
+ end
140
+ end
141
+ end
142
+
143
+ doc.items.append(item)
144
+ # for statistics
145
+ if doc.dictionary.has_key?(id.to_s)
146
+ doc.duplicated_ids_number += 1
147
+ doc.duplicates_list.append(item)
148
+ else
149
+ doc.dictionary[id.to_s] = item # for fast search
150
+ end
151
+ doc.controlled_items.append(item) # for fast search
152
+
153
+ # for statistics
154
+ n = /\d+/.match(id)[0].to_i
155
+ if n > doc.last_used_id_number
156
+ doc.last_used_id = id
157
+ doc.last_used_id_number = n
158
+ end
159
+
160
+ elsif res = /^!\[(.*)\]\((.*)\)/.match(s) # Image
161
+
162
+ temp_md_table = process_temp_table(doc, temp_md_table)
163
+ if temp_md_list
164
+ doc.items.append temp_md_list
165
+ temp_md_list = nil
166
+ end
167
+
168
+ img_text = res[1]
169
+ img_path = res[2]
170
+
171
+ item = Image.new(img_text, img_path)
172
+ item.parent_doc = doc
173
+ item.parent_heading = doc.headings[-1]
174
+
175
+ doc.items.append(item)
176
+
177
+ elsif res = /^(\*\s+)(.*)/.match(s) # check if unordered list start
178
+
179
+ if doc.title == ''
180
+ # dummy section if root is not a Document Title (level 0)
181
+ title = "#{doc.id}.md"
182
+ item = Heading.new(doc, title, 0)
183
+ doc.items.append(item)
184
+ doc.headings.append(item)
185
+ doc.title = title
186
+ end
187
+
188
+ temp_md_table = process_temp_table(doc, temp_md_table)
189
+
190
+ row = res[2]
191
+
192
+ if temp_md_list
193
+ temp_md_list.add_row(s)
194
+ else
195
+ item = MarkdownList.new(doc, false)
196
+ item.add_row(s)
197
+ temp_md_list = item
198
+ end
199
+
200
+ elsif res = /^\d[.]\s(.*)/.match(s) # check if ordered list start
201
+
202
+ temp_md_table = process_temp_table(doc, temp_md_table)
203
+
204
+ row = res[1]
205
+
206
+ if temp_md_list
207
+ temp_md_list.add_row(s)
208
+ else
209
+ item = MarkdownList.new(doc, true)
210
+ item.add_row(s)
211
+ temp_md_list = item
212
+ end
213
+
214
+ elsif s[0] == '|' # check if table
215
+
216
+ if doc.title == ''
217
+ # dummy section if root is not a Document Title (level 0)
218
+ title = "#{doc.id}.md"
219
+ item = Heading.new(doc, title, 0)
220
+ doc.items.append(item)
221
+ doc.headings.append(item)
222
+ doc.title = title
223
+ end
224
+
225
+ if temp_md_list
226
+ doc.items.append temp_md_list
227
+ temp_md_list = nil
228
+ end
229
+
230
+ if res = /^[|](-{3,})[|]/.match(s) # check if it is a separator first
231
+
232
+ if temp_md_table
233
+ # separator is found after heading
234
+ temp_md_table.is_separator_detected = true
235
+ else
236
+ # separator out of table scope consider it just as a regular paragraph
237
+ item = Paragraph.new(doc, s)
238
+ doc.items.append(item)
239
+ end
240
+
241
+ elsif res = /^[|](.*[|])/.match(s) # check if it looks as a table row
242
+
243
+ row = res[1]
244
+
245
+ if temp_md_table
246
+ if temp_md_table.is_separator_detected # if there is a separator
247
+ # check if parent doc is a Protocol
248
+ if doc.instance_of? Protocol
249
+ # check if it is a controlled table
250
+ tmp = /(.*)\s+>\[(\S*)\]/.match(row)
251
+ if tmp && (temp_md_table.instance_of? MarkdownTable)
252
+ # this is not a regular Markdown table
253
+ # so the table type shall be changed and this row shall be passed one more time
254
+ temp_md_table = ControlledTable.new(doc, temp_md_table)
255
+ end
256
+ end
257
+ temp_md_table.add_row(row)
258
+ else
259
+ # replece table heading with regular paragraph
260
+ item = Paragraph.new(doc, temp_md_table.heading_row)
261
+ doc.items.append(item)
262
+ # and current row
263
+ item = Paragraph.new(doc, s)
264
+ doc.items.append(item)
265
+ temp_md_table = nil
266
+ end
267
+ else
268
+ # start table from heading
269
+ temp_md_table = MarkdownTable.new(doc, s)
270
+ end
271
+ end
272
+
273
+ elsif res = /^>(.*)/.match(s) # check if blockquote
274
+
275
+ temp_md_table = process_temp_table(doc, temp_md_table)
276
+
277
+ if temp_md_list
278
+ doc.items.append temp_md_list
279
+ temp_md_list = nil
280
+ end
281
+
282
+ item = Blockquote.new(res[1])
283
+ item.parent_doc = doc
284
+ item.parent_heading = doc.headings[-1]
285
+ doc.items.append(item)
286
+
287
+ elsif res = /^```(\w*)/.match(s) # check if code block
288
+
289
+ temp_md_table = process_temp_table(doc, temp_md_table)
290
+ if temp_md_list
291
+ doc.items.append temp_md_list
292
+ temp_md_list = nil
293
+ end
294
+
295
+ suggested_format = ''
296
+ suggested_format = res[1] if res.length == 2
297
+
298
+ if temp_code_block
299
+ # close already opened block
300
+ doc.items.append(temp_code_block)
301
+ temp_code_block = nil
302
+ else
303
+ # start code block
304
+ temp_code_block = CodeBlock.new(suggested_format)
305
+ temp_code_block.parent_doc = doc
306
+ temp_code_block.parent_heading = doc.headings[-1]
307
+ end
308
+
309
+ elsif res = /^TODO:(.*)/.match(s) # check if TODO block
310
+
311
+ temp_md_table = process_temp_table(doc, temp_md_table)
312
+ if temp_md_list
313
+ doc.items.append temp_md_list
314
+ temp_md_list = nil
315
+ end
316
+
317
+ text = '**TODO**: ' + res[1]
318
+
319
+ item = TodoBlock.new(text)
320
+ item.parent_doc = doc
321
+ item.parent_heading = doc.headings[-1]
322
+ doc.items.append(item)
323
+ doc.todo_blocks.append(item)
324
+
325
+ else # Reqular Paragraph
326
+
327
+ temp_md_table = process_temp_table(doc, temp_md_table)
328
+ if temp_md_list
329
+ if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
330
+ temp_md_list.add_row(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(doc, s)
341
+ doc.items.append(item)
342
+ end
343
+ end
344
+ elsif temp_md_list
345
+ doc.items.append temp_md_list
346
+ temp_md_list = nil # lists are separated by emty line from each other
347
+ end
348
+ end
349
+ # Finalize non-closed elements
350
+ temp_md_table = process_temp_table(doc, temp_md_table)
351
+ if temp_md_list
352
+ doc.items.append temp_md_list
353
+ temp_md_list = nil
354
+ end
355
+ if temp_code_block
356
+ doc.items.append temp_code_block
357
+ temp_code_block = nil
358
+ end
359
+ # Add footer to close opened tables if any
360
+ item = DocFooter.new
361
+ item.parent_doc = doc
362
+ doc.items.append(item)
363
+ end
364
+
365
+ def self.process_temp_table(doc, temp_md_table)
366
+ if temp_md_table
367
+ if temp_md_table.is_separator_detected
368
+ doc.items.append temp_md_table
369
+ else # no separator
370
+ # replece table heading with regular paragraph
371
+ item = Paragraph.new(doc, temp_md_table.heading_row)
372
+ doc.items.append(item)
373
+ end
374
+ temp_md_table = nil
375
+ end
376
+ temp_md_table
377
+ end
378
+ end