Almirah 0.0.8 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1841cdb6a5d88bcbe36d8ed926fd8f659e9a630d58763ead2b78e8b7f17281dd
4
- data.tar.gz: 13b91603331fe68ff13f4b1917806551f94f11d98084ce773a1e247abb4b1abb
3
+ metadata.gz: 4bc6867a502188fb11b4632e9ab695d6fda2af0d1bfef94d3976d069acfb409f
4
+ data.tar.gz: 7d993b275d67bf0fa9cc6f40bfb3c43c2d16f6bb8cab5b76135866b5d81b59b9
5
5
  SHA512:
6
- metadata.gz: ed609c1862a9f33b46c2379ae8f08904c30a00767939418e28600267ccc449aa88b7bcf96efc661c1c3d39d9a720a12491c01eed4c0c30034623f342a47d5d70
7
- data.tar.gz: e5c91e4efbd5d96d915ad2228b22982391ccc91eae8afc545dc8c1fd1a8f077a690d9da988e47794df470eda560e7f6a0a99ec7a173d33660c0cc532de1c5e97
6
+ metadata.gz: '087e3aa7b1792ef031d42945fa29d05e5d2231b3e6b83177bfd529e3e7de646a24ac091a0be6e175575c814f87154641aad2036aa9ea7bd8f9247e6e50bd5aca'
7
+ data.tar.gz: 223acb70d369cdb753635b67b424815cee057ce0309d379a9547ec7769aa9ec78385a178a4862b859444cdd0a187e37c9eaf9771860a2756f1dfea68439133d5
@@ -3,6 +3,7 @@ require_relative "doc_types/base_document"
3
3
  require_relative "doc_types/specification"
4
4
  require_relative "doc_types/protocol"
5
5
  #
6
+ require_relative "doc_items/text_line"
6
7
  require_relative "doc_items/doc_item"
7
8
  require_relative "doc_items/heading"
8
9
  require_relative "doc_items/paragraph"
@@ -15,6 +16,12 @@ require_relative "doc_items/markdown_list"
15
16
 
16
17
  class DocFabric
17
18
 
19
+ def self.add_lazy_doc_id(path)
20
+ if res = /(\w+)[.]md$/.match(path)
21
+ TextLine.add_lazy_doc_id(res[1])
22
+ end
23
+ end
24
+
18
25
  def self.create_specification(path)
19
26
  doc = Specification.new path
20
27
  DocFabric.parse_document doc
@@ -59,7 +66,18 @@ class DocFabric
59
66
  if level == 1 && doc.title == ""
60
67
  doc.title = value
61
68
  end
62
-
69
+ elsif res = /^\%\s(.*)/.match(s) # Pandoc Document Title
70
+
71
+ title = res[1]
72
+ item = Heading.new(title, 1)
73
+ item.parent_doc = doc
74
+ doc.items.append(item)
75
+ doc.headings.append(item)
76
+
77
+ if doc.title == ""
78
+ doc.title = title
79
+ end
80
+
63
81
  elsif res = /^\[(\S*)\]\s+(.*)/.match(s) # Controlled Paragraph
64
82
 
65
83
  if tempMdTable
@@ -81,7 +99,7 @@ class DocFabric
81
99
  up_link = tmp[2]
82
100
 
83
101
  if tmp = /^([a-zA-Z]+)[-]\d+/.match(up_link) # SRS
84
- doc.up_link_doc_id = tmp[1].downcase
102
+ doc.up_link_doc_id[ tmp[1].downcase.to_s ] = tmp[1].downcase # multiple documents could be up-linked
85
103
  end
86
104
  end
87
105
 
@@ -124,7 +142,7 @@ class DocFabric
124
142
 
125
143
  doc.items.append(item)
126
144
 
127
- elsif res = /^(\*\s?)+(.*)/.match(s) #check if bullet list
145
+ elsif res = /^(\*\s?)(.*)/.match(s) #check if unordered list start
128
146
 
129
147
  if tempMdTable
130
148
  doc.items.append tempMdTable
@@ -134,9 +152,28 @@ class DocFabric
134
152
  row = res[2]
135
153
 
136
154
  if tempMdList
137
- tempMdList.addRow(row)
155
+ tempMdList.addRow(s)
138
156
  else
139
- item = MarkdownList.new(row)
157
+ item = MarkdownList.new(false)
158
+ item.addRow(s)
159
+ item.parent_doc = doc
160
+ tempMdList = item
161
+ end
162
+
163
+ elsif res = /^\d[.]\s(.*)/.match(s) #check if ordered list start
164
+
165
+ if tempMdTable
166
+ doc.items.append tempMdTable
167
+ tempMdTable = nil
168
+ end
169
+
170
+ row = res[1]
171
+
172
+ if tempMdList
173
+ tempMdList.addRow(s)
174
+ else
175
+ item = MarkdownList.new(true)
176
+ item.addRow(s)
140
177
  item.parent_doc = doc
141
178
  tempMdList = item
142
179
  end
@@ -198,14 +235,24 @@ class DocFabric
198
235
  tempMdTable = nil
199
236
  end
200
237
  if tempMdList
201
- doc.items.append tempMdList
202
- tempMdList = nil
238
+ if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
239
+ tempMdList.addRow(s)
240
+ next
241
+ else
242
+ doc.items.append tempMdList
243
+ tempMdList = nil
244
+ end
203
245
  end
204
246
 
205
247
  item = Paragraph.new(s)
206
248
  item.parent_doc = doc
207
249
  doc.items.append(item)
208
250
  end
251
+ else
252
+ if tempMdList # lists are separated by emty line from each other
253
+ doc.items.append tempMdList
254
+ tempMdList = nil
255
+ end
209
256
  end
210
257
  end
211
258
  # Finalize non-closed elements
@@ -10,12 +10,13 @@ class Blockquote < DocItem
10
10
 
11
11
  def to_html
12
12
  s = ''
13
+ f_text = format_string(@text)
13
14
  if @@htmlTableRenderInProgress
14
15
  s += "</table>\n"
15
16
  @@htmlTableRenderInProgress = false
16
17
  end
17
18
 
18
- s += "<div class=\"blockquote\"><p>#{@text}</div>\n"
19
+ s += "<div class=\"blockquote\"><p>#{f_text}</div>\n"
19
20
  return s
20
21
  end
21
22
  end
@@ -19,12 +19,13 @@ class ControlledParagraph < Paragraph
19
19
  s = ''
20
20
  unless @@htmlTableRenderInProgress
21
21
  s += "<table class=\"controlled\">\n"
22
- s += "\t<thead> <th>#</th> <th>Text</th> <th>UL</th> <th>DL</th> <th>COV</th> </thead>\n"
22
+ s += "\t<thead> <th>#</th> <th></th> <th>UL</th> <th>DL</th> <th>COV</th> </thead>\n"
23
23
  @@htmlTableRenderInProgress = true
24
24
  end
25
+ f_text = format_string(@text)
25
26
  s += "\t<tr>\n"
26
27
  s += "\t\t<td class=\"item_id\"> <a name=\"#{@id}\" id=\"#{@id}\" href=\"##{@id}\">#{@id}</a></td>\n"
27
- s += "\t\t<td class=\"item_text\">#{@text}</td>\n"
28
+ s += "\t\t<td class=\"item_text\">#{f_text}</td>\n"
28
29
 
29
30
  if @up_link
30
31
  if tmp = /^([a-zA-Z]+)[-]\d+/.match(@up_link)
@@ -39,7 +40,11 @@ class ControlledParagraph < Paragraph
39
40
  if tmp = /^([a-zA-Z]+)[-]\d+/.match(@down_links[0].id) # guessing that all the links refer to one document
40
41
  down_link_doc_name = tmp[1].downcase
41
42
  end
42
- s += "\t\t<td class=\"item_id\"><a href=\"./../#{down_link_doc_name}/#{down_link_doc_name}.html\" class=\"external\">#{@down_links.length}</a></td>\n"
43
+ if @down_links.length == 1
44
+ s += "\t\t<td class=\"item_id\"><a href=\"./../#{down_link_doc_name}/#{down_link_doc_name}.html##{@down_links[0].id}\" class=\"external\">#{@down_links[0].id}</a></td>\n"
45
+ else
46
+ s += "\t\t<td class=\"item_id\"><a href=\"./../#{down_link_doc_name}/#{down_link_doc_name}.html\" class=\"external\">#{@down_links.length}</a></td>\n"
47
+ end
43
48
  else
44
49
  s += "\t\t<td class=\"item_id\"></td>\n"
45
50
  end
@@ -1,7 +1,7 @@
1
1
  require_relative "controlled_table_row"
2
+ require_relative "text_line"
2
3
 
3
-
4
- class ControlledTableColumn
4
+ class ControlledTableColumn < TextLine
5
5
 
6
6
  attr_accessor :text
7
7
 
@@ -10,7 +10,8 @@ class ControlledTableColumn
10
10
  end
11
11
 
12
12
  def to_html
13
- "\t\t<td>#{@text}</td>\n\r"
13
+ f_text = format_string(@text)
14
+ "\t\t<td>#{f_text}</td>\n\r"
14
15
  end
15
16
  end
16
17
 
@@ -41,12 +42,13 @@ end
41
42
  class TestStepResultColumn < ControlledTableColumn
42
43
 
43
44
  def to_html
45
+ f_text = format_string(@text)
44
46
  if @text.downcase == "pass"
45
- "\t\t<td style=\"background-color: #cfc;\">#{@text}</td>\n\r"
47
+ "\t\t<td style=\"background-color: #cfc;\">#{f_text}</td>\n\r"
46
48
  elsif @text.downcase == "fail"
47
- "\t\t<td style=\"background-color: #fcc;\">#{@text}</td>\n\r"
49
+ "\t\t<td style=\"background-color: #fcc;\">#{f_text}</td>\n\r"
48
50
  else
49
- "\t\t<td>#{@text}</td>\n\r"
51
+ "\t\t<td>#{f_text}</td>\n\r"
50
52
  end
51
53
  end
52
54
  end
@@ -126,9 +128,9 @@ class ControlledTable < DocItem
126
128
  new_row.columns.append col
127
129
  # save uplink key but do not rewrite
128
130
  if col.up_link_doc_id != nil
129
- if @parent_doc.up_link_doc_id == ""
130
- @parent_doc.up_link_doc_id = col.up_link_doc_id
131
- end
131
+
132
+ @parent_doc.up_link_doc_id[ col.up_link_doc_id.to_s ] = col.up_link_doc_id
133
+
132
134
  # save reference to the test step
133
135
  new_row.up_link = col.up_link
134
136
  @parent_doc.controlled_items.append new_row
@@ -1,4 +1,6 @@
1
- class DocItem
1
+ require_relative "text_line"
2
+
3
+ class DocItem < TextLine
2
4
  attr_accessor :parent_doc
3
5
 
4
6
  @parent_doc = nil
@@ -8,7 +8,7 @@ class Heading < Paragraph
8
8
  def initialize(text, level)
9
9
  @text = text
10
10
  @level = level
11
- @anchor_id = self.getTextWithoutSpaces()
11
+ @anchor_id = getTextWithoutSpaces()
12
12
  end
13
13
 
14
14
  def to_html
@@ -21,7 +21,7 @@ class Image < DocItem
21
21
  @@htmlTableRenderInProgress = false
22
22
  end
23
23
 
24
- s += "<img src=\"#{@path}\" alt=\"#{@text}\">"
24
+ s += "<p style=\"margin-top: 15px;\"><img src=\"#{@path}\" alt=\"#{@text}\">"
25
25
  return s
26
26
  end
27
27
  end
@@ -3,14 +3,113 @@ require_relative "doc_item"
3
3
  class MarkdownList < DocItem
4
4
 
5
5
  attr_accessor :rows
6
+ attr_accessor :text
7
+ attr_accessor :is_ordered
8
+ attr_accessor :indent_position
9
+ attr_accessor :current_nesting_level
6
10
 
7
- def initialize(first_row)
11
+ @@lists_stack = Array.new
12
+
13
+ def initialize(is_ordered)
8
14
  @rows = Array.new
9
- @rows.append(first_row)
15
+ @is_ordered = is_ordered
16
+ @current_nesting_level = 0
17
+ @indent_position = 0
18
+ @text = ''
19
+
20
+ @@lists_stack.push(self)
21
+ end
22
+
23
+ def addRow(raw_text)
24
+ pos = calculate_text_position(raw_text)
25
+ row = raw_text[pos..-1]
26
+
27
+ pos = calculate_indent_position(raw_text)
28
+
29
+ if pos > @@lists_stack[-1].indent_position
30
+
31
+ prev_lists_stack_item = @@lists_stack[-1]
32
+ # the following line pushes new list to the lists_stack in the constructor!
33
+ nested_list = MarkdownList.new( MarkdownList.ordered_list_item?(raw_text) )
34
+ nested_list.current_nesting_level = @current_nesting_level + 1
35
+ nested_list.indent_position = pos
36
+
37
+ prev_row = prev_lists_stack_item.rows[-1]
38
+ if prev_row.is_a?(MarkdownList)
39
+ #cannot be there
40
+ else
41
+ nested_list.text = prev_row
42
+ #puts "Length: " + prev_lists_stack_item.rows.length.to_s
43
+ prev_lists_stack_item.rows[-1] = nested_list
44
+ end
45
+
46
+ nested_list.addRow(raw_text)
47
+
48
+ elsif pos < @@lists_stack[-1].indent_position
49
+
50
+ @@lists_stack.pop
51
+ @@lists_stack[-1].rows.append(row)
52
+
53
+ else
54
+ @@lists_stack[-1].rows.append(row)
55
+
56
+ end
57
+ end
58
+
59
+ def calculate_indent_position(s)
60
+ s.downcase
61
+ pos = 0
62
+ s.each_char do |c|
63
+ if c != ' ' && c != '\t'
64
+ break
65
+ end
66
+ pos += 1
67
+ end
68
+ return pos
69
+ end
70
+ def calculate_text_position(s)
71
+ s.downcase
72
+ pos = 0
73
+ space_detected = false
74
+ s.each_char do |c|
75
+ if space_detected
76
+ if c != ' ' && c != '\t' && c != '*' && c != '.' && !numeric?(c)
77
+ break
78
+ end
79
+ elsif c == ' ' || c == '\t'
80
+ space_detected = true
81
+ end
82
+ pos += 1
83
+ end
84
+ return pos
85
+ end
86
+
87
+ def letter?(c)
88
+ c.match?(/[[:alpha:]]/)
89
+ end
90
+
91
+ def numeric?(c)
92
+ c.match?(/[[:digit:]]/)
10
93
  end
11
94
 
12
- def addRow(row)
13
- @rows.append(row)
95
+ def non_blank?(c)
96
+ c.match?(/[[:graph:]]/)
97
+ end
98
+
99
+ def self.unordered_list_item?(raw_text)
100
+
101
+ if res = /(\*\s?)(.*)/.match(raw_text)
102
+ return true
103
+ end
104
+ return false
105
+ end
106
+
107
+ def self.ordered_list_item?(raw_text)
108
+
109
+ if res = /\d[.]\s(.*)/.match(raw_text)
110
+ return true
111
+ end
112
+ return false
14
113
  end
15
114
 
16
115
  def to_html
@@ -20,11 +119,30 @@ class MarkdownList < DocItem
20
119
  @@htmlTableRenderInProgress = false
21
120
  end
22
121
 
23
- s += "<ul>\n"
122
+ if @is_ordered
123
+ s += "<ol>\n"
124
+ else
125
+ s += "<ul>\n"
126
+ end
127
+
24
128
  @rows.each do |r|
25
- s += "\t<li>#{r}</li>\n"
129
+ if r.is_a?(MarkdownList)
130
+ f_text = format_string(r.text)
131
+ s += "\t<li>#{f_text}\n"
132
+ s += r.to_html()
133
+ s += "</li>\n"
134
+ else
135
+ f_text = format_string(r)
136
+ #puts f_text
137
+ s += "\t<li>#{f_text}</li>\n"
138
+ end
26
139
  end
27
- s += "</ul>\n"
140
+
141
+ if @is_ordered
142
+ s += "</ol>\n"
143
+ else
144
+ s += "</ul>\n"
145
+ end
28
146
 
29
147
  return s
30
148
  end
@@ -44,7 +44,8 @@ class MarkdownTable < DocItem
44
44
  if col.to_i > 0 && col.to_i.to_s == col # autoalign cells with numbers
45
45
  s += "\t\t<td style=\"text-align: center;\">#{col}</td>\n"
46
46
  else
47
- s += "\t\t<td>#{col}</td>\n"
47
+ f_text = format_string(col)
48
+ s += "\t\t<td>#{f_text}</td>\n"
48
49
  end
49
50
  end
50
51
  s += "\t</tr>\n"
@@ -9,7 +9,7 @@ class Paragraph < DocItem
9
9
  end
10
10
 
11
11
  def getTextWithoutSpaces
12
- return @text.split.join('-')
12
+ return @text.split.join('-').downcase
13
13
  end
14
14
 
15
15
  def to_html
@@ -19,7 +19,7 @@ class Paragraph < DocItem
19
19
  @@htmlTableRenderInProgress = false
20
20
  end
21
21
 
22
- s += "<p>#{@text}"
22
+ s += "<p>" + format_string(@text)
23
23
  return s
24
24
  end
25
25
  end
@@ -0,0 +1,183 @@
1
+ class TextLine
2
+
3
+ @@lazy_doc_id_dict = Hash.new
4
+
5
+ def self.add_lazy_doc_id(id)
6
+ doc_id = id.to_s.downcase
7
+ @@lazy_doc_id_dict[doc_id] = doc_id
8
+ end
9
+
10
+ def format_string(str)
11
+ state = 'default'
12
+ prev_state = 'default'
13
+ result = ''
14
+ stack = ''
15
+ prev_c = ''
16
+ link_text = ''
17
+ link_url = ''
18
+ str.each_char do |c|
19
+ if c == '*'
20
+ if state == 'default'
21
+ prev_state, state = change_state(c, state, 'first_asterisk_detected')
22
+
23
+ elsif state == 'first_asterisk_detected'
24
+ prev_state, state = change_state(c, state, 'second_asterisk_detected')
25
+
26
+ elsif state == 'second_asterisk_detected'
27
+ prev_state, state = change_state(c, state, 'third_asterisk_detected')
28
+
29
+ elsif state == 'second_asterisk_detected'
30
+ prev_state, state = change_state(c, state, 'third_asterisk_detected')
31
+
32
+ elsif state == 'italic_started'
33
+ prev_state, state = change_state(c, state, 'default')
34
+ result += italic(stack)
35
+
36
+ elsif state == 'bold_started'
37
+ prev_state, state = change_state(c, state, 'first_asterisk_after_bold_detected')
38
+
39
+ elsif state == 'first_asterisk_after_bold_detected'
40
+ prev_state, state = change_state(c, state, 'default')
41
+ result += bold(stack)
42
+
43
+ elsif state == 'bold_and_italic_started'
44
+ prev_state, state = change_state(c, state, 'first_asterisk_after_bold_and_italic_detected')
45
+
46
+ elsif state == 'first_asterisk_after_bold_and_italic_detected'
47
+ prev_state, state = change_state(c, state, 'second_asterisk_after_bold_and_italic_detected')
48
+
49
+ elsif state == 'second_asterisk_after_bold_and_italic_detected'
50
+ prev_state, state = change_state(c, state, 'default')
51
+ result += bold_and_italic(stack)
52
+
53
+ else
54
+ end
55
+ elsif c == '['
56
+ if state == 'default'
57
+ prev_state, state = change_state(c, state, 'square_bracket_left_detected')
58
+ else
59
+ end
60
+ elsif c == ']'
61
+ if state == 'square_bracket_left_detected'
62
+ prev_state, state = change_state(c, state, 'default')
63
+ result += '[]'
64
+
65
+ elsif state == 'link_text_started'
66
+ prev_state, state = change_state(c, state, 'square_bracket_right_detected')
67
+ link_text = stack
68
+
69
+ else
70
+ end
71
+ elsif c == '('
72
+ if state == 'square_bracket_right_detected'
73
+ prev_state, state = change_state(c, state, 'brace_left_detected')
74
+ else
75
+ result += c
76
+ end
77
+ elsif c == ')'
78
+ if state == 'brace_left_detected'
79
+ prev_state, state = change_state(c, state, 'default')
80
+ result += '()'
81
+
82
+ elsif state == 'link_url_started'
83
+ prev_state, state = change_state(c, state, 'default')
84
+ link_url = stack
85
+ result += link(link_text, link_url)
86
+
87
+ else
88
+ result += c
89
+ end
90
+ else
91
+ if state == 'default'
92
+ result += c
93
+ else
94
+ if state == 'first_asterisk_detected'
95
+ prev_state, state = change_state(c, state, 'italic_started')
96
+ stack = ''
97
+
98
+ elsif state == 'second_asterisk_detected'
99
+ prev_state, state = change_state(c, state, 'bold_started')
100
+ stack = ''
101
+
102
+ elsif state == 'third_asterisk_detected'
103
+ prev_state, state = change_state(c, state, 'bold_and_italic_started')
104
+ stack = ''
105
+
106
+ elsif state == 'first_asterisk_after_bold_detected'
107
+ prev_state, state = change_state(c, state, 'bold_started')
108
+
109
+ elsif state == 'first_asterisk_after_bold_and_italic_detected'
110
+ prev_state, state = change_state(c, state, 'bold_and_italic_started')
111
+
112
+ elsif state == 'second_asterisk_after_bold_and_italic_detected'
113
+ prev_state, state = change_state(c, state, 'bold_and_italic_started')
114
+
115
+ elsif state == 'square_bracket_left_detected'
116
+ prev_state, state = change_state(c, state, 'link_text_started')
117
+ stack = ''
118
+
119
+ elsif state == 'square_bracket_right_detected'
120
+ prev_state, state = change_state(c, state, 'default')
121
+ result += stack + c
122
+ c = ''
123
+
124
+ elsif state == 'brace_left_detected'
125
+ prev_state, state = change_state(c, state, 'link_url_started')
126
+ stack = ''
127
+
128
+ else
129
+ end
130
+ stack += c
131
+ end
132
+ end
133
+ prev_c = c
134
+ end
135
+ return result
136
+ end
137
+
138
+ def change_state(c, cur_state, new_state)
139
+ # puts "[#{c}] Transition: #{cur_state} --> #{new_state}"
140
+ return cur_state, new_state
141
+ end
142
+
143
+ def italic(str)
144
+ "<i>#{str}</i>"
145
+ end
146
+
147
+ def bold(str)
148
+ "<b>#{str}</b>"
149
+ end
150
+
151
+ def bold_and_italic(str)
152
+ "<b><i>#{str}</i></b>"
153
+ end
154
+
155
+ def link(link_text, link_url)
156
+
157
+ # define default result first
158
+ result = "<a href=\"#{link_url}\" class=\"external\">#{link_text}</a>"
159
+
160
+ lazy_doc_id, anchor = nil, nil
161
+
162
+ if res = /(\w+)[.]md$/.match(link_url) #link
163
+ lazy_doc_id = res[1].to_s.downcase
164
+
165
+ elsif res = /(\w*)[.]md(#.*)$/.match(link_url) # link with anchor
166
+ if res && res.length > 2
167
+ lazy_doc_id = res[1]
168
+ anchor = res[2]
169
+ end
170
+ end
171
+
172
+ if lazy_doc_id
173
+ if @@lazy_doc_id_dict.has_key?(lazy_doc_id)
174
+ if anchor
175
+ result = "<a href=\".\\..\\#{lazy_doc_id}\\#{lazy_doc_id}.html#{anchor}\" class=\"external\">#{link_text}</a>"
176
+ else
177
+ result = "<a href=\".\\..\\#{lazy_doc_id}\\#{lazy_doc_id}.html\" class=\"external\">#{link_text}</a>"
178
+ end
179
+ end
180
+ end
181
+ return result
182
+ end
183
+ end
@@ -25,7 +25,11 @@ class BaseDocument
25
25
  file_data = file.readlines
26
26
  file.close
27
27
 
28
- output_file_path += "#{@id}/#{@id}.html"
28
+ if @id == 'index'
29
+ output_file_path += "#{@id}.html"
30
+ else
31
+ output_file_path += "#{@id}/#{@id}.html"
32
+ end
29
33
  file = File.open( output_file_path, "w" )
30
34
  file_data.each do |s|
31
35
  if s.include?('{{CONTENT}}')
@@ -0,0 +1,107 @@
1
+ require_relative "base_document"
2
+
3
+ class Index < BaseDocument
4
+
5
+ attr_accessor :items
6
+ attr_accessor :project
7
+
8
+ def initialize(project)
9
+ @items = Array.new
10
+ @project = project
11
+
12
+ @title = "Document Index"
13
+ @id = "index"
14
+ end
15
+
16
+ def to_console
17
+ puts "\e[36m" + "Index: " + @id + "\e[0m"
18
+ end
19
+
20
+ def to_html(output_file_path)
21
+
22
+ html_rows = Array.new
23
+
24
+ html_rows.append('')
25
+ s = "<h1>#{@title}</h1>\n"
26
+
27
+ # Specifications
28
+ s = "<h2>Specifications</h2>\n"
29
+ s += "<table class=\"controlled\">\n"
30
+ s += "\t<thead>\n"
31
+ s += "\t\t<th>Title</th>\n"
32
+ s += "\t\t<th>Items</th>\n"
33
+ s += "\t\t<th>Items<br>w/ Uplinks</th>\n"
34
+ s += "\t\t<th>Items<br>w/ Downlinks</th>\n"
35
+ s += "\t\t<th>Covered<br>by Tests</th>\n"
36
+ s += "\t\t<th>Duplicated<br>ids</th>\n"
37
+ s += "\t\t<th>Last Used<br>id</th>\n"
38
+ s += "</thead>\n"
39
+ html_rows.append s
40
+
41
+ sorted_items = @project.specifications.sort_by { |w| w.id }
42
+
43
+ sorted_items.each do |doc|
44
+ s = "\t<tr>\n"
45
+ s += "\t\t<td class=\"item_text\" style='padding: 5px;'><a href=\"./specifications/#{doc.id}/#{doc.id}.html\" class=\"external\">#{doc.title}</a></td>\n"
46
+ s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.controlled_items.length.to_s}</td>\n"
47
+ s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.items_with_uplinks_number.to_s}</td>\n"
48
+ s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.items_with_downlinks_number.to_s}</td>\n"
49
+ s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.items_with_coverage_number.to_s}</td>\n"
50
+ s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.duplicated_ids_number.to_s}</td>\n"
51
+ s += "\t\t<td class=\"item_id\" style='width: 7%;'>#{doc.last_used_id.to_s}</td>\n"
52
+ s += "</tr>\n"
53
+ html_rows.append s
54
+ end
55
+ html_rows.append "</table>\n"
56
+
57
+ # Traceability Matrices
58
+ s = "<h2>Traceability Matrices</h2>\n"
59
+ s += "<table class=\"controlled\">\n"
60
+ s += "\t<thead>\n"
61
+ s += "\t\t<th>Title</th>\n"
62
+ s += "\t\t<th>Top Document</th>\n"
63
+ s += "\t\t<th>Bottom Document</th>\n"
64
+ s += "</thead>\n"
65
+ html_rows.append s
66
+
67
+ sorted_items = @project.traceability_matrices.sort_by { |w| w.id }
68
+
69
+ sorted_items.each do |doc|
70
+ s = "\t<tr>\n"
71
+ s += "\t\t<td class=\"item_text\" style='padding: 5px;'><a href=\"./specifications/#{doc.id}/#{doc.id}.html\" class=\"external\">#{doc.title}</a></td>\n"
72
+ s += "\t\t<td class=\"item_text\" style='width: 25%; padding: 5px;'>#{doc.top_doc.title}</td>\n"
73
+ s += "\t\t<td class=\"item_text\" style='width: 25%; padding: 5px;'>#{doc.bottom_doc.title}</td>\n"
74
+ s += "</tr>\n"
75
+ html_rows.append s
76
+ end
77
+ html_rows.append "</table>\n"
78
+
79
+ # Coverage Matrices
80
+ if @project.coverage_matrices.length > 0
81
+ s = "<h2>Coverage Matrices</h2>\n"
82
+ s += "<table class=\"controlled\">\n"
83
+ s += "\t<thead>\n"
84
+ s += "\t\t<th>Title</th>\n"
85
+ s += "\t\t<th>Specification Covered</th>\n"
86
+ s += "</thead>\n"
87
+ html_rows.append s
88
+
89
+ sorted_items = @project.coverage_matrices.sort_by { |w| w.id }
90
+
91
+ sorted_items.each do |doc|
92
+ s = "\t<tr>\n"
93
+ s += "\t\t<td class=\"item_text\" style='padding: 5px;'><a href=\"./specifications/#{doc.id}/#{doc.id}.html\" class=\"external\">#{doc.title}</a></td>\n"
94
+ s += "\t\t<td class=\"item_text\" style='width: 25%; padding: 5px;'>#{doc.top_doc.title}</td>\n"
95
+ s += "</tr>\n"
96
+ html_rows.append s
97
+ end
98
+ html_rows.append "</table>\n"
99
+ end
100
+
101
+ self.save_html_to_file(html_rows, nil, output_file_path)
102
+
103
+ end
104
+
105
+
106
+
107
+ end
@@ -16,7 +16,7 @@ class Protocol < BaseDocument
16
16
  #@dictionary = Hash.new
17
17
 
18
18
  @id = File.basename(fele_path, File.extname(fele_path)).downcase
19
- @up_link_doc_id = ""
19
+ @up_link_doc_id = Hash.new
20
20
  end
21
21
 
22
22
  def to_html(nav_pane, output_file_path)
@@ -30,7 +30,7 @@ class Specification < BaseDocument
30
30
  @last_used_id_number = 0
31
31
 
32
32
  @id = File.basename(fele_path, File.extname(fele_path)).downcase
33
- @up_link_doc_id = ""
33
+ @up_link_doc_id = Hash.new
34
34
  end
35
35
 
36
36
  def to_console
@@ -67,6 +67,7 @@ class Specification < BaseDocument
67
67
 
68
68
  @items.each do |item|
69
69
  a = item.to_html
70
+ #a = adjust_internal_links(a, nav_pane.specifications)
70
71
  html_rows.append a
71
72
  end
72
73
 
@@ -74,4 +75,29 @@ class Specification < BaseDocument
74
75
 
75
76
  end
76
77
 
78
+ def adjust_internal_links(line, specifications)
79
+ # check if there are internal links to md files and replace them
80
+ if tmp = /<a\shref="(.*)"\sclass="external">.*<\/a>/.match(line)
81
+ if res = /(\w*)[.]md/.match(tmp[1])
82
+ id = res[1].downcase
83
+ res = /(\w*)[.]md(#.*)/.match(tmp[1])
84
+
85
+ specifications.each do |spec|
86
+ if spec.id.downcase == id
87
+ if res && res.length > 2
88
+ anchor = res[2]
89
+ line.sub!(/<a\shref="(.*)"\sclass="external">/,
90
+ "<a href=\".\\..\\#{id}\\#{id}.html#{anchor}\" class=\"external\">")
91
+ else
92
+ line.sub!(/<a\shref="(.*)"\sclass="external">/,
93
+ "<a href=\".\\..\\#{id}\\#{id}.html\" class=\"external\">")
94
+ end
95
+ break
96
+ end
97
+ end
98
+ end
99
+ end
100
+ return line
101
+ end
102
+
77
103
  end
@@ -5,16 +5,23 @@ class Traceability < BaseDocument
5
5
  attr_accessor :top_doc
6
6
  attr_accessor :bottom_doc
7
7
  attr_accessor :items
8
+ attr_accessor :is_agregated
8
9
 
9
- def initialize(top_doc, bottom_doc)
10
+ def initialize(top_doc, bottom_doc, is_agregated)
10
11
 
11
12
  @top_doc = top_doc
12
13
  @bottom_doc = bottom_doc
14
+ @is_agregated = is_agregated
13
15
 
14
16
  @items = Array.new
15
17
  @headings = Array.new
16
18
 
17
- @id = top_doc.id + "-" + bottom_doc.id
19
+ if @is_agregated
20
+ @id = top_doc.id + "-all"
21
+ else
22
+ @id = top_doc.id + "-" + bottom_doc.id
23
+ end
24
+
18
25
  @title = "Traceability Matrix: " + @id
19
26
  end
20
27
 
@@ -46,24 +53,49 @@ class Traceability < BaseDocument
46
53
 
47
54
  def render_table_row(top_item)
48
55
  s = ""
56
+ top_f_text = top_item.format_string( top_item.text )
57
+
49
58
  if top_item.down_links
50
- if top_item.down_links.length > 1
51
- id_color = "style='background-color: #fff8c5;'"
59
+
60
+ if @is_agregated
61
+
62
+ if top_item.down_links.length > 1
63
+ id_color = "style='background-color: #fff8c5;'"
64
+ else
65
+ id_color = ""
66
+ end
67
+
68
+ top_item.down_links.each do |bottom_item|
69
+ bottom_f_text = bottom_item.format_string( bottom_item.text )
70
+ s += "\t<tr>\n"
71
+ s += "\t\t<td class=\"item_id\" #{id_color}><a href=\"./../#{top_item.parent_doc.id}/#{top_item.parent_doc.id}.html##{top_item.id}\" class=\"external\">#{top_item.id}</a></td>\n"
72
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_f_text}</td>\n"
73
+ s += "\t\t<td class=\"item_id\"><a href=\"./../#{bottom_item.parent_doc.id}/#{bottom_item.parent_doc.id}.html##{bottom_item.id}\" class=\"external\">#{bottom_item.id}</a></td>\n"
74
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{bottom_f_text}</td>\n"
75
+ s += "\t</tr>\n"
76
+ end
77
+
52
78
  else
53
- id_color = ""
54
- end
55
- top_item.down_links.each do |bottom_item|
56
- s += "\t<tr>\n"
57
- s += "\t\t<td class=\"item_id\" #{id_color}><a href=\"./../#{top_item.parent_doc.id}/#{top_item.parent_doc.id}.html##{top_item.id}\" class=\"external\">#{top_item.id}</a></td>\n"
58
- s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_item.text}</td>\n"
59
- s += "\t\t<td class=\"item_id\"><a href=\"./../#{bottom_item.parent_doc.id}/#{bottom_item.parent_doc.id}.html##{bottom_item.id}\" class=\"external\">#{bottom_item.id}</a></td>\n"
60
- s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{bottom_item.text}</td>\n"
61
- s += "\t</tr>\n"
79
+ top_item.down_links.each do |bottom_item|
80
+
81
+ id_color = ""
82
+
83
+ if bottom_item.parent_doc.id == @bottom_doc.id
84
+
85
+ bottom_f_text = bottom_item.format_string( bottom_item.text )
86
+ s += "\t<tr>\n"
87
+ s += "\t\t<td class=\"item_id\" #{id_color}><a href=\"./../#{top_item.parent_doc.id}/#{top_item.parent_doc.id}.html##{top_item.id}\" class=\"external\">#{top_item.id}</a></td>\n"
88
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_f_text}</td>\n"
89
+ s += "\t\t<td class=\"item_id\"><a href=\"./../#{bottom_item.parent_doc.id}/#{bottom_item.parent_doc.id}.html##{bottom_item.id}\" class=\"external\">#{bottom_item.id}</a></td>\n"
90
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{bottom_f_text}</td>\n"
91
+ s += "\t</tr>\n"
92
+ end
93
+ end
62
94
  end
63
95
  else
64
96
  s += "\t<tr>\n"
65
97
  s += "\t\t<td class=\"item_id\"><a href=\"./../#{top_item.parent_doc.id}/#{top_item.parent_doc.id}.html##{top_item.id}\" class=\"external\">#{top_item.id}</a></td>\n"
66
- s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_item.text}</td>\n"
98
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_f_text}</td>\n"
67
99
  s += "\t\t<td class=\"item_id\"></td>\n"
68
100
  s += "\t\t<td class=\"item_text\" style='width: 42%;'></td>\n"
69
101
  s += "\t</tr>\n"
@@ -1,21 +1,31 @@
1
+ require 'fileutils'
1
2
  require_relative "doc_fabric"
2
3
  require_relative "navigation_pane"
3
4
  require_relative "doc_types/traceability"
4
5
  require_relative "doc_types/coverage"
6
+ require_relative "doc_types/index"
5
7
 
6
8
  class Project
7
9
 
8
10
  attr_accessor :specifications
9
11
  attr_accessor :protocols
12
+ attr_accessor :traceability_matrices
13
+ attr_accessor :coverage_matrices
10
14
  attr_accessor :project_root_directory
11
15
  attr_accessor :specifications_dictionary
16
+ attr_accessor :index
17
+ attr_accessor :project
12
18
 
13
19
  def initialize(path)
14
20
  @project_root_directory = path
15
21
  @specifications = Array.new
16
22
  @protocols = Array.new
23
+ @traceability_matrices = Array.new
24
+ @coverage_matrices = Array.new
17
25
  @specifications_dictionary = Hash.new
18
-
26
+ @index = nil
27
+ @project = self
28
+
19
29
  FileUtils.remove_dir(@project_root_directory + "/build", true)
20
30
  end
21
31
 
@@ -25,8 +35,12 @@ class Project
25
35
  parse_all_protocols
26
36
  link_all_specifications
27
37
  link_all_protocols
28
- render_all_specifications
38
+ create_index
39
+ render_all_specifications(@specifications)
40
+ render_all_specifications(@traceability_matrices)
41
+ render_all_specifications(@coverage_matrices)
29
42
  render_all_protocols
43
+ render_index
30
44
  end
31
45
 
32
46
  def specifications_and_results( test_run )
@@ -35,13 +49,41 @@ class Project
35
49
  parse_test_run test_run
36
50
  link_all_specifications
37
51
  link_all_protocols
38
- render_all_specifications
52
+ create_index
53
+ render_all_specifications(@specifications)
54
+ render_all_specifications(@traceability_matrices)
55
+ render_all_specifications(@coverage_matrices)
39
56
  render_all_protocols
57
+ render_index
58
+ end
59
+
60
+ def transform( file_extension )
61
+ transform_all_specifications file_extension
62
+ end
63
+
64
+ def transform_all_specifications( file_extension )
65
+
66
+ path = @project_root_directory
67
+
68
+ # find all specifications
69
+ Dir.glob( "#{@project_root_directory}/specifications/**/*.md" ).each do |f|
70
+ puts f
71
+ # make a copy with another extention to preserve the content
72
+ f_directory = File.dirname(f)
73
+ f_name = File.basename(f, File.extname(f)).downcase + "._md"
74
+ FileUtils.copy_file( f, "#{f_directory}/#{f_name}")
75
+ # transform the original one
76
+ # but do nothing for now - TODO
77
+ end
40
78
  end
41
79
 
42
- def parse_all_specifications
80
+ def parse_all_specifications
81
+ # do a lasy pass first to get the list of documents id
82
+ Dir.glob( "#{@project_root_directory}/specifications/**/*.md" ).each do |f|
83
+ DocFabric.add_lazy_doc_id(f)
84
+ end
85
+ # parse documents in the second pass
43
86
  Dir.glob( "#{@project_root_directory}/specifications/**/*.md" ).each do |f|
44
- puts "Spec: " + f
45
87
  doc = DocFabric.create_specification(f)
46
88
  @specifications.append(doc)
47
89
  end
@@ -67,13 +109,14 @@ class Project
67
109
  combList = @specifications.combination(2)
68
110
  combList.each do |c|
69
111
  link_two_specifications(c[0], c[1])
112
+ # puts "Link: #{c[0].id} - #{c[1].id}"
70
113
  end
71
114
  end
72
115
 
73
116
  def link_all_protocols
74
117
  @protocols.each do |p|
75
118
  @specifications.each do |s|
76
- if s.id == p.up_link_doc_id
119
+ if p.up_link_doc_id.has_key?(s.id.to_s)
77
120
  link_protocol_to_spec(p,s)
78
121
  end
79
122
  end
@@ -82,17 +125,16 @@ class Project
82
125
 
83
126
  def link_two_specifications(doc_A, doc_B)
84
127
 
85
- if doc_A.id == doc_B.up_link_doc_id
128
+ if doc_B.up_link_doc_id.has_key?(doc_A.id.to_s)
86
129
  top_document = doc_A
87
130
  bottom_document = doc_B
88
- elsif doc_B.id == doc_A.up_link_doc_id
131
+ elsif doc_A.up_link_doc_id.has_key?(doc_B.id.to_s)
89
132
  top_document = doc_B
90
133
  bottom_document = doc_A
91
134
  else
92
- puts "No Links"
93
135
  return # no links
94
136
  end
95
-
137
+ #puts "Link: #{doc_A.id} - #{doc_B.id}"
96
138
  bottom_document.controlled_items.each do |item|
97
139
 
98
140
  if top_document.dictionary.has_key?(item.up_link.to_s)
@@ -107,8 +149,8 @@ class Project
107
149
  end
108
150
  end
109
151
  # create treceability document
110
- trx = Traceability.new top_document, bottom_document
111
- @specifications.append trx
152
+ trx = Traceability.new top_document, bottom_document, false
153
+ @traceability_matrices.append trx
112
154
  end
113
155
 
114
156
  def link_protocol_to_spec(protocol, specification)
@@ -131,19 +173,23 @@ class Project
131
173
  end
132
174
  # create coverage document
133
175
  trx = Coverage.new top_document
134
- @specifications.append trx
176
+ @coverage_matrices.append trx
177
+ end
178
+
179
+ def create_index
180
+ @index = Index.new( @project )
135
181
  end
136
182
 
137
- def render_all_specifications
183
+ def render_all_specifications(spec_list)
138
184
 
139
185
  # create a sidebar first
140
- nav_pane = NavigationPane.new(@specifications)
186
+ # nav_pane = NavigationPane.new(@specifications)
141
187
 
142
188
  pass = @project_root_directory
143
189
 
144
190
  FileUtils.mkdir_p(pass + "/build/specifications")
145
191
 
146
- @specifications.each do |doc|
192
+ spec_list.each do |doc|
147
193
 
148
194
  doc.to_console
149
195
 
@@ -156,14 +202,14 @@ class Project
156
202
  FileUtils.copy_entry( img_src_dir, img_dst_dir )
157
203
  end
158
204
 
159
- doc.to_html( nav_pane, "#{pass}/build/specifications/" )
205
+ doc.to_html( nil, "#{pass}/build/specifications/" )
160
206
  end
161
207
  end
162
208
 
163
209
  def render_all_protocols
164
210
 
165
211
  # create a sidebar first
166
- nav_pane = NavigationPane.new(@specifications)
212
+ # nav_pane = NavigationPane.new(@specifications)
167
213
 
168
214
  pass = @project_root_directory
169
215
 
@@ -181,7 +227,17 @@ class Project
181
227
  FileUtils.copy_entry( img_src_dir, img_dst_dir )
182
228
  end
183
229
 
184
- doc.to_html( nav_pane, "#{pass}/build/tests/protocols/" )
230
+ doc.to_html( nil, "#{pass}/build/tests/protocols/" )
185
231
  end
186
232
  end
233
+
234
+ def render_index
235
+
236
+ path = @project_root_directory
237
+
238
+ doc = @index
239
+ doc.to_console
240
+
241
+ doc.to_html("#{path}/build/")
242
+ end
187
243
  end
@@ -93,6 +93,7 @@
93
93
  border: 1px solid #bbb;
94
94
  }
95
95
  table.controlled td {
96
+ padding: 4px;
96
97
  text-align:center;
97
98
  vertical-align:middle;
98
99
  padding-right:10px;
@@ -197,8 +198,8 @@ function closeNav() {
197
198
  </head>
198
199
  <body>
199
200
  <div id="top_nav">
200
- <a href="javascript:void(0)" onclick="openNav()"><span><i class="fa fa-bars" aria-hidden="true"></i></span>&nbsp;Navigation</a>
201
- <a href="javascript:void(0)"> About</a>
201
+ <a href="./../../index.html"><span><i class="fa fa-home" aria-hidden="true"></i></span>&nbsp;Home</a>
202
+ <!--a href="javascript:void(0)"> About</a-->
202
203
  </div>
203
204
  <div id="main">
204
205
  <div id="nav_pane">
data/lib/almirah.rb CHANGED
@@ -2,8 +2,8 @@ require "thor"
2
2
  require_relative "almirah/project"
3
3
 
4
4
  class CLI < Thor
5
- desc "please <project_folder>", "say <project_folder>"
6
5
  option :results
6
+ desc "please <project_folder>", "say <project_folder>"
7
7
  def please(project_folder)
8
8
  a = Almirah.new project_folder
9
9
  if options[:results]
@@ -12,6 +12,12 @@ class CLI < Thor
12
12
  a.default
13
13
  end
14
14
  end
15
+
16
+ desc "transform <project_folder>", "say <project_folder>"
17
+ def transform(project_folder)
18
+ a = Almirah.new project_folder
19
+ a.transform "docx"
20
+ end
15
21
  end
16
22
 
17
23
  class Almirah
@@ -30,6 +36,10 @@ class Almirah
30
36
  @project.specifications_and_results test_run
31
37
  end
32
38
 
39
+ def transform( file_extension )
40
+ @project.transform file_extension
41
+ end
42
+
33
43
  def default()
34
44
  @project.specifications_and_protocols
35
45
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Almirah
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleksandr Ivanov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-17 00:00:00.000000000 Z
11
+ date: 2024-03-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: The software part of the Almirah system
13
+ description: The software part of the Almirah framework
14
14
  email: oleksandr.ivanov.development@gmail.com
15
15
  executables:
16
16
  - almirah
@@ -30,8 +30,10 @@ files:
30
30
  - lib/almirah/doc_items/markdown_list.rb
31
31
  - lib/almirah/doc_items/markdown_table.rb
32
32
  - lib/almirah/doc_items/paragraph.rb
33
+ - lib/almirah/doc_items/text_line.rb
33
34
  - lib/almirah/doc_types/base_document.rb
34
35
  - lib/almirah/doc_types/coverage.rb
36
+ - lib/almirah/doc_types/index.rb
35
37
  - lib/almirah/doc_types/protocol.rb
36
38
  - lib/almirah/doc_types/specification.rb
37
39
  - lib/almirah/doc_types/traceability.rb
@@ -57,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
59
  - !ruby/object:Gem::Version
58
60
  version: '0'
59
61
  requirements: []
60
- rubygems_version: 3.1.6
62
+ rubygems_version: 3.5.6
61
63
  signing_key:
62
64
  specification_version: 4
63
65
  summary: Almirah