Almirah 0.2.5 → 0.2.6

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