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