Almirah 0.0.7 → 0.0.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 877a4c7b296af5fa0418113a4287df82661d23903764f73a74b8794d2be22d9a
4
- data.tar.gz: 4195b1434e0ca4c75177c4af9ea3e97ffa9a373106bda58fa11621ba273df7cf
3
+ metadata.gz: 9e500204a8575e500989c7d86e4db4dff7a6247b14d3768904620be7a3cef356
4
+ data.tar.gz: a12d76101a33fc1938c0c42d361f84ae9a8c796684becd1567e154e67f345cad
5
5
  SHA512:
6
- metadata.gz: 4425611cadee99f5686c79abbc853d93bbfeb0e729a97168f93842d998daf8e1a879de8e25918fcbd01bd49abe2b842cc192f24d137cd987d77816f606abed15
7
- data.tar.gz: ca609c497ebde13428c516a0369f860c323f7bcaba740424d125b9a3c4bd2e1955f8f8aec665d6afd088cc44772c4edfaba5dc64f47827be631253111f82a446
6
+ metadata.gz: eff42c3d45f0be71488484ce864740c5363e9169450d32469b9044136ea47af2989b32c4cb526c176c4d4721e60be0c5f484db8ed2245285eb042187a9c5df57
7
+ data.tar.gz: 2e5c4887b584428a71db8cbd33d244242c90df9b7b02aca8804f72f97fb017dfebc4aa8ff2ae52f924ae9895f7ac1b075cac2407ba84888db55cd36d97984344
@@ -52,6 +52,7 @@ class DocFabric
52
52
  level = res[1].length
53
53
  value = res[2]
54
54
  item = Heading.new(value, level)
55
+ item.parent_doc = doc
55
56
  doc.items.append(item)
56
57
  doc.headings.append(item)
57
58
 
@@ -85,12 +86,25 @@ class DocFabric
85
86
  end
86
87
 
87
88
  item = ControlledParagraph.new( text, id )
88
- item.up_link = up_link
89
+ item.parent_doc = doc
90
+ if up_link
91
+ item.up_link = up_link
92
+ doc.items_with_uplinks_number += 1 #for statistics
93
+ end
89
94
 
90
95
  doc.items.append(item)
91
96
  doc.dictionary[ id.to_s ] = item #for fast search
92
97
  doc.controlled_items.append(item) #for fast search
93
98
 
99
+ #for statistics
100
+ n = /\d+/.match(id)[0].to_i
101
+ if n == doc.last_used_id_number
102
+ doc.duplicated_ids_number += 1
103
+ elsif n > doc.last_used_id_number
104
+ doc.last_used_id = id
105
+ doc.last_used_id_number = n
106
+ end
107
+
94
108
  elsif res = /^[!]\[(.*)\]\((.*)\)/.match(s) # Image
95
109
 
96
110
  if tempMdTable
@@ -106,10 +120,11 @@ class DocFabric
106
120
  img_path = res[2]
107
121
 
108
122
  item = Image.new( img_text, img_path )
123
+ item.parent_doc = doc
109
124
 
110
125
  doc.items.append(item)
111
126
 
112
- elsif res = /^(\*\s?)+(.*)/.match(s) #check if bullet list
127
+ elsif res = /^(\*\s?)(.*)/.match(s) #check if unordered list start
113
128
 
114
129
  if tempMdTable
115
130
  doc.items.append tempMdTable
@@ -121,7 +136,27 @@ class DocFabric
121
136
  if tempMdList
122
137
  tempMdList.addRow(row)
123
138
  else
124
- item = MarkdownList.new(row)
139
+ item = MarkdownList.new(false)
140
+ item.addRow(s)
141
+ item.parent_doc = doc
142
+ tempMdList = item
143
+ end
144
+
145
+ elsif res = /^\d[.]\s(.*)/.match(s) #check if ordered list start
146
+
147
+ if tempMdTable
148
+ doc.items.append tempMdTable
149
+ tempMdTable = nil
150
+ end
151
+
152
+ row = res[1]
153
+
154
+ if tempMdList
155
+ tempMdList.addRow(row)
156
+ else
157
+ item = MarkdownList.new(true)
158
+ item.addRow(s)
159
+ item.parent_doc = doc
125
160
  tempMdList = item
126
161
  end
127
162
 
@@ -139,6 +174,7 @@ class DocFabric
139
174
  else
140
175
  #separator out of table scope consider it just as a regular paragraph
141
176
  item = Paragraph.new(s)
177
+ item.parent_doc = doc
142
178
  doc.items.append(item)
143
179
  end
144
180
 
@@ -150,11 +186,13 @@ class DocFabric
150
186
  # check if it is a controlled table
151
187
  unless tempMdTable.addRow(row)
152
188
  tempMdTable = ControlledTable.new(tempMdTable, doc)
189
+ tempMdTable.parent_doc = doc
153
190
  tempMdTable.addRow(row)
154
191
  end
155
192
  else
156
193
  #start table from heading
157
194
  tempMdTable = MarkdownTable.new(row)
195
+ tempMdTable.parent_doc = doc
158
196
  end
159
197
  end
160
198
 
@@ -170,6 +208,7 @@ class DocFabric
170
208
  end
171
209
 
172
210
  item = Blockquote.new(res[1])
211
+ item.parent_doc = doc
173
212
  doc.items.append(item)
174
213
 
175
214
  else # Reqular Paragraph
@@ -178,13 +217,24 @@ class DocFabric
178
217
  tempMdTable = nil
179
218
  end
180
219
  if tempMdList
181
- doc.items.append tempMdList
182
- tempMdList = nil
220
+ if MarkdownList.unordered_list_item?(s) || MarkdownList.ordered_list_item?(s)
221
+ tempMdList.addRow(s)
222
+ next
223
+ else
224
+ doc.items.append tempMdList
225
+ tempMdList = nil
226
+ end
183
227
  end
184
228
 
185
229
  item = Paragraph.new(s)
230
+ item.parent_doc = doc
186
231
  doc.items.append(item)
187
232
  end
233
+ else
234
+ if tempMdList # lists are separated by emty line from each other
235
+ doc.items.append tempMdList
236
+ tempMdList = nil
237
+ end
188
238
  end
189
239
  end
190
240
  # 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
@@ -8,7 +8,7 @@ class ControlledParagraph < Paragraph
8
8
  attr_accessor :coverage_links
9
9
 
10
10
  def initialize(text, id)
11
- @text = text
11
+ @text = text.strip
12
12
  @id = id
13
13
  @up_link = nil
14
14
  @down_links = nil
@@ -22,15 +22,16 @@ class ControlledParagraph < Paragraph
22
22
  s += "\t<thead> <th>#</th> <th>Text</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
- s += "\t\t<td class=\"item_id\"> <a name=\"#{@id}\"></a>#{@id} </td>\n"
27
- s += "\t\t<td class=\"item_text\">#{@text}</td>\n"
27
+ s += "\t\t<td class=\"item_id\"> <a name=\"#{@id}\" id=\"#{@id}\" href=\"##{@id}\">#{@id}</a></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)
31
32
  up_link_doc_name = tmp[1].downcase
32
33
  end
33
- s += "\t\t<td class=\"item_id\"><a href=\"./../#{up_link_doc_name}/#{up_link_doc_name}.html\" class=\"external\">#{@up_link}</a></td>\n"
34
+ s += "\t\t<td class=\"item_id\"><a href=\"./../#{up_link_doc_name}/#{up_link_doc_name}.html##{@up_link}\" class=\"external\">#{@up_link}</a></td>\n"
34
35
  else
35
36
  s += "\t\t<td class=\"item_id\"></td>\n"
36
37
  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
 
@@ -23,15 +24,17 @@ end
23
24
  class TestStepNumberColumn < ControlledTableColumn
24
25
 
25
26
  attr_accessor :step_number
27
+ attr_accessor :row_id
26
28
 
27
29
  def initialize(text)
28
30
  text = text.strip
29
31
  @step_number = text.to_i
30
32
  @text = text
33
+ @row_id = ""
31
34
  end
32
35
 
33
36
  def to_html
34
- "\t\t<td style=\"text-align: center;\">#{@text}</td>\n\r"
37
+ "\t\t<td style=\"text-align: center;\"><a name=\"#{@row_id}\" id=\"#{@row_id}\" href=\"##{@row_id}\">#{@text}</a></td>\n\r"
35
38
  end
36
39
  end
37
40
 
@@ -39,12 +42,13 @@ end
39
42
  class TestStepResultColumn < ControlledTableColumn
40
43
 
41
44
  def to_html
45
+ f_text = format_string(@text)
42
46
  if @text.downcase == "pass"
43
- "\t\t<td style=\"background-color: #cfc;\">#{@text}</td>\n\r"
47
+ "\t\t<td style=\"background-color: #cfc;\">#{f_text}</td>\n\r"
44
48
  elsif @text.downcase == "fail"
45
- "\t\t<td style=\"background-color: #fcc;\">#{@text}</td>\n\r"
49
+ "\t\t<td style=\"background-color: #fcc;\">#{f_text}</td>\n\r"
46
50
  else
47
- "\t\t<td>#{@text}</td>\n\r"
51
+ "\t\t<td>#{f_text}</td>\n\r"
48
52
  end
49
53
  end
50
54
  end
@@ -70,7 +74,7 @@ class TestStepReferenceColumn < ControlledTableColumn
70
74
 
71
75
  def to_html
72
76
  if @up_link
73
- "\t\t<td class=\"item_id\"><a href=\"./../../../specifications/#{@up_link_doc_id}/#{@up_link_doc_id}.html\" class=\"external\">#{@up_link}</a></td>\n\r"
77
+ "\t\t<td class=\"item_id\"><a href=\"./../../../specifications/#{@up_link_doc_id}/#{@up_link_doc_id}.html##{@up_link}\" class=\"external\">#{@up_link}</a></td>\n\r"
74
78
  else
75
79
  "\t\t<td style=\"text-align: center;\"></td>\n\r"
76
80
  end
@@ -83,7 +87,6 @@ class ControlledTable < DocItem
83
87
 
84
88
  attr_accessor :column_names
85
89
  attr_accessor :rows
86
- attr_accessor :parent_doc
87
90
 
88
91
  def initialize(markdown_table, parent_doc)
89
92
  @parent_doc = parent_doc
@@ -108,6 +111,7 @@ class ControlledTable < DocItem
108
111
  def format_columns(columns)
109
112
 
110
113
  new_row = ControlledTableRow.new
114
+ new_row.parent_doc = @parent_doc
111
115
 
112
116
  columns.each_with_index do | element, index |
113
117
 
@@ -116,6 +120,7 @@ class ControlledTable < DocItem
116
120
  col = TestStepNumberColumn.new element
117
121
  new_row.columns.append col
118
122
  new_row.id = @parent_doc.id + '.' + col.text
123
+ col.row_id = new_row.id
119
124
 
120
125
  elsif index + 1 == columns.length # it is expected that a link is placed to the last column only
121
126
 
@@ -1,4 +1,10 @@
1
- class DocItem
1
+ require_relative "text_line"
2
+
3
+ class DocItem < TextLine
4
+ attr_accessor :parent_doc
5
+
6
+ @parent_doc = nil
7
+
2
8
  @@htmlTableRenderInProgress = false
3
9
  end
4
10
 
@@ -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
@@ -3,14 +3,107 @@ 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
+ puts raw_text
25
+ pos = calculate_text_position(raw_text)
26
+ row = raw_text[pos..-1]
27
+
28
+ pos = calculate_indent_position(raw_text)
29
+
30
+ if pos > @@lists_stack[-1].indent_position
31
+
32
+ prev_lists_stack_item = @@lists_stack[-1]
33
+ # the following line pushes new list to the lists_stack in the constructor!
34
+ nested_list = MarkdownList.new( MarkdownList.ordered_list_item?(raw_text) )
35
+ nested_list.current_nesting_level = @current_nesting_level + 1
36
+ nested_list.indent_position = pos
37
+
38
+ prev_row = prev_lists_stack_item.rows[-1]
39
+ if prev_row.is_a?(MarkdownList)
40
+ #cannot be there
41
+ else
42
+ nested_list.text = prev_row
43
+ puts "Length: " + prev_lists_stack_item.rows.length.to_s
44
+ prev_lists_stack_item.rows[-1] = nested_list
45
+ end
46
+
47
+ nested_list.addRow(raw_text)
48
+
49
+ elsif pos < @@lists_stack[-1].indent_position
50
+
51
+ @@lists_stack.pop
52
+ @@lists_stack[-1].rows.append(row)
53
+
54
+ else
55
+ @@lists_stack[-1].rows.append(row)
56
+
57
+ end
58
+ end
59
+
60
+ def calculate_indent_position(s)
61
+ pos = 0
62
+ s.each_char do |c|
63
+ if non_blank?(c)
64
+ break
65
+ end
66
+ pos += 1
67
+ end
68
+ return pos
69
+ end
70
+ def calculate_text_position(s)
71
+ pos = 0
72
+ s.each_char do |c|
73
+ if letter?(c)
74
+ break
75
+ end
76
+ pos += 1
77
+ end
78
+ return pos
79
+ end
80
+
81
+ def letter?(c)
82
+ c.match?(/[[:alpha:]]/)
83
+ end
84
+
85
+ def numeric?(c)
86
+ c.match?(/[[:digit:]]/)
10
87
  end
11
88
 
12
- def addRow(row)
13
- @rows.append(row)
89
+ def non_blank?(c)
90
+ c.match?(/[[:graph:]]/)
91
+ end
92
+
93
+ def self.unordered_list_item?(raw_text)
94
+
95
+ if res = /(\*\s?)(.*)/.match(raw_text)
96
+ return true
97
+ end
98
+ return false
99
+ end
100
+
101
+ def self.ordered_list_item?(raw_text)
102
+
103
+ if res = /\d[.]\s(.*)/.match(raw_text)
104
+ return true
105
+ end
106
+ return false
14
107
  end
15
108
 
16
109
  def to_html
@@ -20,11 +113,29 @@ class MarkdownList < DocItem
20
113
  @@htmlTableRenderInProgress = false
21
114
  end
22
115
 
23
- s += "<ul>\n"
116
+ if @is_ordered
117
+ s += "<ol>\n"
118
+ else
119
+ s += "<ul>\n"
120
+ end
121
+
24
122
  @rows.each do |r|
25
- s += "\t<li>#{r}</li>\n"
123
+ if r.is_a?(MarkdownList)
124
+ f_text = format_string(r.text)
125
+ s += "\t<li>#{f_text}\n"
126
+ s += r.to_html()
127
+ s += "</li>\n"
128
+ else
129
+ f_text = format_string(r)
130
+ s += "\t<li>#{f_text}</li>\n"
131
+ end
26
132
  end
27
- s += "</ul>\n"
133
+
134
+ if @is_ordered
135
+ s += "</ol>\n"
136
+ else
137
+ s += "</ul>\n"
138
+ end
28
139
 
29
140
  return s
30
141
  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,169 @@
1
+ class TextLine
2
+
3
+ def format_string(str)
4
+ state = 'default'
5
+ prev_state = 'default'
6
+ result = ''
7
+ stack = ''
8
+ prev_c = ''
9
+ link_text = ''
10
+ link_url = ''
11
+ str.each_char do |c|
12
+ if c == '*'
13
+ if state == 'default'
14
+ prev_state = state
15
+ state = 'first_asterisk_detected'
16
+
17
+ elsif state == 'first_asterisk_detected'
18
+ prev_state = state
19
+ state = 'second_asterisk_detected'
20
+
21
+ elsif state == 'second_asterisk_detected'
22
+ prev_state = state
23
+ state = 'third_asterisk_detected'
24
+
25
+ elsif state == 'second_asterisk_detected'
26
+ prev_state = state
27
+ state = 'third_asterisk_detected'
28
+
29
+ elsif state == 'italic_started'
30
+ prev_state = state
31
+ state = 'default'
32
+ result += italic(stack)
33
+
34
+ elsif state == 'bold_started'
35
+ prev_state = state
36
+ state = 'first_asterisk_after_bold_detected'
37
+
38
+ elsif state == 'first_asterisk_after_bold_detected'
39
+ prev_state = state
40
+ state = 'default'
41
+ result += bold(stack)
42
+
43
+ elsif state == 'bold_and_italic_started'
44
+ prev_state = state
45
+ state = 'first_asterisk_after_bold_and_italic_detected'
46
+
47
+ elsif state == 'first_asterisk_after_bold_and_italic_detected'
48
+ prev_state = state
49
+ state = 'second_asterisk_after_bold_and_italic_detected'
50
+
51
+ elsif state == 'second_asterisk_after_bold_and_italic_detected'
52
+ prev_state = state
53
+ state = 'default'
54
+ result += bold_and_italic(stack)
55
+
56
+ else
57
+ end
58
+ elsif c == '['
59
+ if state == 'default'
60
+ prev_state = state
61
+ state = 'square_bracket_left_detected'
62
+ else
63
+ end
64
+ elsif c == ']'
65
+ if state == 'square_bracket_left_detected'
66
+ prev_state = state
67
+ state = 'default'
68
+ result += '[]'
69
+
70
+ elsif state == 'link_text_started'
71
+ prev_state = state
72
+ state = 'square_bracket_right_detected'
73
+ link_text = stack
74
+
75
+ else
76
+ end
77
+ elsif c == '('
78
+ if state == 'square_bracket_right_detected'
79
+ prev_state = state
80
+ state = 'brace_left_detected'
81
+ else
82
+ end
83
+ elsif c == ')'
84
+ if state == 'brace_left_detected'
85
+ prev_state = state
86
+ state = 'default'
87
+ result += '()'
88
+
89
+ elsif state == 'link_url_started'
90
+ prev_state = state
91
+ state = 'default'
92
+ link_url = stack
93
+ result += link(link_text, link_url)
94
+
95
+ else
96
+ end
97
+ else
98
+ if state == 'default'
99
+ result += c
100
+ else
101
+ if state == 'first_asterisk_detected'
102
+ prev_state = state
103
+ state = 'italic_started'
104
+ stack = ''
105
+
106
+ elsif state == 'second_asterisk_detected'
107
+ prev_state = state
108
+ state = 'bold_started'
109
+ stack = ''
110
+
111
+ elsif state == 'third_asterisk_detected'
112
+ prev_state = state
113
+ state = 'bold_and_italic_started'
114
+ stack = ''
115
+
116
+ elsif state == 'first_asterisk_after_bold_detected'
117
+ prev_state = state
118
+ state = 'bold_started'
119
+
120
+ elsif state == 'first_asterisk_after_bold_and_italic_detected'
121
+ prev_state = state
122
+ state = 'bold_and_italic_started'
123
+
124
+ elsif state == 'second_asterisk_after_bold_and_italic_detected'
125
+ prev_state = state
126
+ state = 'bold_and_italic_started'
127
+
128
+ elsif state == 'square_bracket_left_detected'
129
+ prev_state = state
130
+ state = 'link_text_started'
131
+ stack = ''
132
+
133
+ elsif state == 'square_bracket_right_detected'
134
+ prev_state = state
135
+ state = 'default'
136
+ result += stack + c
137
+ c = ''
138
+
139
+ elsif state == 'brace_left_detected'
140
+ prev_state = state
141
+ state = 'link_url_started'
142
+ stack = ''
143
+
144
+ else
145
+ end
146
+ stack += c
147
+ end
148
+ end
149
+ prev_c = c
150
+ end
151
+ return result
152
+ end
153
+
154
+ def italic(str)
155
+ "<i>#{str}</i>"
156
+ end
157
+
158
+ def bold(str)
159
+ "<b>#{str}</b>"
160
+ end
161
+
162
+ def bold_and_italic(str)
163
+ "<b><i>#{str}</i></b>"
164
+ end
165
+
166
+ def link(link_text, link_url)
167
+ "<a href=\"#{link_url}\" class=\"external\">#{link_text}</a>"
168
+ end
169
+ end
@@ -15,4 +15,31 @@ class BaseDocument
15
15
  @title = ""
16
16
  @id = ""
17
17
  end
18
+
19
+ def save_html_to_file html_rows, nav_pane, output_file_path
20
+
21
+ gem_root = File.expand_path './../../..', File.dirname(__FILE__)
22
+ template_file = gem_root + "/lib/almirah/templates/page.html"
23
+
24
+ file = File.open( template_file )
25
+ file_data = file.readlines
26
+ file.close
27
+
28
+ output_file_path += "#{@id}/#{@id}.html"
29
+ file = File.open( output_file_path, "w" )
30
+ file_data.each do |s|
31
+ if s.include?('{{CONTENT}}')
32
+ html_rows.each do |r|
33
+ file.puts r
34
+ end
35
+ elsif s.include?('{{NAV_PANE}}')
36
+ if nav_pane
37
+ file.puts nav_pane.to_html
38
+ end
39
+ else
40
+ file.puts s
41
+ end
42
+ end
43
+ file.close
44
+ end
18
45
  end
@@ -0,0 +1,82 @@
1
+ require_relative "base_document"
2
+
3
+ class Coverage < BaseDocument
4
+
5
+ attr_accessor :top_doc
6
+ attr_accessor :bottom_doc
7
+ attr_accessor :items
8
+
9
+ def initialize(top_doc)
10
+
11
+ @top_doc = top_doc
12
+ @bottom_doc = bottom_doc
13
+
14
+ @items = Array.new
15
+ @headings = Array.new
16
+
17
+ @id = top_doc.id + "-" + "tests"
18
+ @title = "Coverage Matrix: " + @id
19
+ end
20
+
21
+ def to_console
22
+ puts "\e[35m" + "Traceability: " + @id + "\e[0m"
23
+ end
24
+
25
+ def to_html(nav_pane, output_file_path)
26
+
27
+ html_rows = Array.new
28
+
29
+ html_rows.append('')
30
+ s = "<h1>#{@title}</h1>\n"
31
+ s += "<table class=\"controlled\">\n"
32
+ s += "\t<thead> <th>#</th> <th style='font-weight: bold;'>#{@top_doc.title}</th> <th>#</th> <th style='font-weight: bold;'>Test CaseId.StepId</th> </thead>\n"
33
+ html_rows.append s
34
+
35
+ sorted_items = @top_doc.controlled_items.sort_by { |w| w.id }
36
+
37
+ sorted_items.each do |top_item|
38
+ row = render_table_row top_item
39
+ html_rows.append row
40
+ end
41
+ html_rows.append "</table>\n"
42
+
43
+ self.save_html_to_file(html_rows, nav_pane, output_file_path)
44
+
45
+ end
46
+
47
+ def render_table_row(top_item)
48
+ s = ""
49
+ if top_item.coverage_links
50
+ if top_item.coverage_links.length > 1
51
+ id_color = "" # "style='background-color: #fff8c5;'" # disabled for now
52
+ else
53
+ id_color = ""
54
+ end
55
+ top_item.coverage_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
+
60
+ if bottom_item.columns[-2].text.downcase == "pass"
61
+ test_step_color = "style='background-color: #cfc;'"
62
+ elsif bottom_item.columns[-2].text.downcase == "fail"
63
+ test_step_color = "style='background-color: #fcc;'"
64
+ else
65
+ test_step_color = ""
66
+ end
67
+
68
+ s += "\t\t<td class=\"item_id\" #{test_step_color}><a href=\"./../../tests/protocols/#{bottom_item.parent_doc.id}/#{bottom_item.parent_doc.id}.html##{bottom_item.id}\" class=\"external\">#{bottom_item.id}</a></td>\n"
69
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{bottom_item.columns[1].text}</td>\n"
70
+ s += "\t</tr>\n"
71
+ end
72
+ else
73
+ s += "\t<tr>\n"
74
+ 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"
75
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'>#{top_item.text}</td>\n"
76
+ s += "\t\t<td class=\"item_id\"></td>\n"
77
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'></td>\n"
78
+ s += "\t</tr>\n"
79
+ end
80
+ return s
81
+ end
82
+ end
@@ -19,4 +19,19 @@ class Protocol < BaseDocument
19
19
  @up_link_doc_id = ""
20
20
  end
21
21
 
22
+ def to_html(nav_pane, output_file_path)
23
+
24
+ html_rows = Array.new
25
+
26
+ html_rows.append('')
27
+
28
+ @items.each do |item|
29
+ a = item.to_html
30
+ html_rows.append a
31
+ end
32
+
33
+ self.save_html_to_file(html_rows, nav_pane, output_file_path)
34
+
35
+ end
36
+
22
37
  end
@@ -6,6 +6,13 @@ class Specification < BaseDocument
6
6
  attr_accessor :dictionary
7
7
  attr_accessor :controlled_items
8
8
 
9
+ attr_accessor :items_with_uplinks_number
10
+ attr_accessor :items_with_downlinks_number
11
+ attr_accessor :items_with_coverage_number
12
+ attr_accessor :duplicated_ids_number
13
+ attr_accessor :last_used_id
14
+ attr_accessor :last_used_id_number
15
+
9
16
  def initialize(fele_path)
10
17
 
11
18
  @path = fele_path
@@ -15,8 +22,82 @@ class Specification < BaseDocument
15
22
  @controlled_items = Array.new
16
23
  @dictionary = Hash.new
17
24
 
25
+ @items_with_uplinks_number = 0
26
+ @items_with_downlinks_number = 0
27
+ @items_with_coverage_number = 0
28
+ @duplicated_ids_number = 0
29
+ @last_used_id = ""
30
+ @last_used_id_number = 0
31
+
18
32
  @id = File.basename(fele_path, File.extname(fele_path)).downcase
19
33
  @up_link_doc_id = ""
20
34
  end
21
35
 
36
+ def to_console
37
+ puts ""
38
+ puts "\e[33m" + "Specification: " + @title + "\e[0m"
39
+ puts "-" * 53
40
+ puts "| Number of Controlled Items | %10d |" % @controlled_items.length
41
+ puts "| Number of Items w/ Up-links | %10d |" % @items_with_uplinks_number
42
+ puts "| Number of Items w/ Down-links | %10d |" % @items_with_downlinks_number
43
+
44
+ # coverage
45
+ if (@controlled_items.length > 0) && (@controlled_items.length == @items_with_coverage_number)
46
+ puts "| Number of Items w/ Test Coverage |\e[1m\e[32m %10d \e[0m|" % @items_with_coverage_number
47
+ else
48
+ puts "| Number of Items w/ Test Coverage | %10d |" % @items_with_coverage_number
49
+ end
50
+
51
+ # duplicates
52
+ if @duplicated_ids_number >0
53
+ puts "| Duplicated Item Ids found |\e[1m\e[31m %10d \e[0m|" % @duplicated_ids_number
54
+ else
55
+ puts "| Duplicated Item Ids found | %10d |" % @duplicated_ids_number
56
+ end
57
+
58
+ puts "| Last used Item Id |\e[1m\e[37m %10s \e[0m|" % @last_used_id
59
+ puts "-" * 53
60
+ end
61
+
62
+ def to_html(nav_pane, output_file_path)
63
+
64
+ html_rows = Array.new
65
+
66
+ html_rows.append('')
67
+
68
+ @items.each do |item|
69
+ a = item.to_html
70
+ a = adjust_internal_links(a, nav_pane.specifications)
71
+ html_rows.append a
72
+ end
73
+
74
+ self.save_html_to_file(html_rows, nav_pane, output_file_path)
75
+
76
+ end
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
+
22
103
  end
@@ -0,0 +1,73 @@
1
+ require_relative "base_document"
2
+
3
+ class Traceability < BaseDocument
4
+
5
+ attr_accessor :top_doc
6
+ attr_accessor :bottom_doc
7
+ attr_accessor :items
8
+
9
+ def initialize(top_doc, bottom_doc)
10
+
11
+ @top_doc = top_doc
12
+ @bottom_doc = bottom_doc
13
+
14
+ @items = Array.new
15
+ @headings = Array.new
16
+
17
+ @id = top_doc.id + "-" + bottom_doc.id
18
+ @title = "Traceability Matrix: " + @id
19
+ end
20
+
21
+ def to_console
22
+ puts "\e[35m" + "Traceability: " + @id + "\e[0m"
23
+ end
24
+
25
+ def to_html(nav_pane, output_file_path)
26
+
27
+ html_rows = Array.new
28
+
29
+ html_rows.append('')
30
+ s = "<h1>#{@title}</h1>\n"
31
+ s += "<table class=\"controlled\">\n"
32
+ s += "\t<thead> <th>#</th> <th style='font-weight: bold;'>#{@top_doc.title}</th> <th>#</th> <th style='font-weight: bold;'>#{@bottom_doc.title}</th> </thead>\n"
33
+ html_rows.append s
34
+
35
+ sorted_items = @top_doc.controlled_items.sort_by { |w| w.id }
36
+
37
+ sorted_items.each do |top_item|
38
+ row = render_table_row top_item
39
+ html_rows.append row
40
+ end
41
+ html_rows.append "</table>\n"
42
+
43
+ self.save_html_to_file(html_rows, nav_pane, output_file_path)
44
+
45
+ end
46
+
47
+ def render_table_row(top_item)
48
+ s = ""
49
+ if top_item.down_links
50
+ if top_item.down_links.length > 1
51
+ id_color = "style='background-color: #fff8c5;'"
52
+ 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"
62
+ end
63
+ else
64
+ s += "\t<tr>\n"
65
+ 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"
67
+ s += "\t\t<td class=\"item_id\"></td>\n"
68
+ s += "\t\t<td class=\"item_text\" style='width: 42%;'></td>\n"
69
+ s += "\t</tr>\n"
70
+ end
71
+ return s
72
+ end
73
+ end
@@ -1,20 +1,20 @@
1
+ require 'fileutils'
1
2
  require_relative "doc_fabric"
2
- require_relative "html_render"
3
3
  require_relative "navigation_pane"
4
+ require_relative "doc_types/traceability"
5
+ require_relative "doc_types/coverage"
4
6
 
5
7
  class Project
6
8
 
7
9
  attr_accessor :specifications
8
10
  attr_accessor :protocols
9
11
  attr_accessor :project_root_directory
10
- attr_accessor :gem_root
11
12
  attr_accessor :specifications_dictionary
12
13
 
13
- def initialize(path, gem_root)
14
+ def initialize(path)
14
15
  @project_root_directory = path
15
16
  @specifications = Array.new
16
17
  @protocols = Array.new
17
- @gem_root = gem_root
18
18
  @specifications_dictionary = Hash.new
19
19
 
20
20
  FileUtils.remove_dir(@project_root_directory + "/build", true)
@@ -102,14 +102,14 @@ class Project
102
102
 
103
103
  unless topItem.down_links
104
104
  topItem.down_links = Array.new
105
+ top_document.items_with_downlinks_number += 1 # for statistics
105
106
  end
106
107
  topItem.down_links.append(item)
107
-
108
- #if tmp = /^([a-zA-Z]+)[-]\d+/.match(item.id)
109
- # top_document.downlinkKey = tmp[1].upcase
110
- #end
111
108
  end
112
109
  end
110
+ # create treceability document
111
+ trx = Traceability.new top_document, bottom_document
112
+ @specifications.append trx
113
113
  end
114
114
 
115
115
  def link_protocol_to_spec(protocol, specification)
@@ -125,10 +125,14 @@ class Project
125
125
 
126
126
  unless topItem.coverage_links
127
127
  topItem.coverage_links = Array.new
128
+ top_document.items_with_coverage_number += 1 # for statistics
128
129
  end
129
130
  topItem.coverage_links.append(item)
130
131
  end
131
132
  end
133
+ # create coverage document
134
+ trx = Coverage.new top_document
135
+ @specifications.append trx
132
136
  end
133
137
 
134
138
  def render_all_specifications
@@ -142,6 +146,8 @@ class Project
142
146
 
143
147
  @specifications.each do |doc|
144
148
 
149
+ doc.to_console
150
+
145
151
  img_src_dir = pass + "/specifications/" + doc.id + "/img"
146
152
  img_dst_dir = pass + "/build/specifications/" + doc.id + "/img"
147
153
 
@@ -151,16 +157,14 @@ class Project
151
157
  FileUtils.copy_entry( img_src_dir, img_dst_dir )
152
158
  end
153
159
 
154
- HtmlRender.new( doc, nav_pane,
155
- @gem_root + "/lib/almirah/templates/page.html",
156
- "#{pass}/build/specifications/#{doc.id}/#{doc.id}.html" )
160
+ doc.to_html( nav_pane, "#{pass}/build/specifications/" )
157
161
  end
158
162
  end
159
163
 
160
164
  def render_all_protocols
161
165
 
162
166
  # create a sidebar first
163
- #nav_pane = NavigationPane.new(@specifications)
167
+ nav_pane = NavigationPane.new(@specifications)
164
168
 
165
169
  pass = @project_root_directory
166
170
 
@@ -178,9 +182,7 @@ class Project
178
182
  FileUtils.copy_entry( img_src_dir, img_dst_dir )
179
183
  end
180
184
 
181
- HtmlRender.new( doc, nil,
182
- @gem_root + "/lib/almirah/templates/page.html",
183
- "#{pass}/build/tests/protocols/#{doc.id}/#{doc.id}.html" )
185
+ doc.to_html( nav_pane, "#{pass}/build/tests/protocols/" )
184
186
  end
185
187
  end
186
188
  end
@@ -126,6 +126,13 @@
126
126
  a, a:link, a:visited {
127
127
  color: #169;
128
128
  text-decoration: none;
129
+ display: inline-block;
130
+ }
131
+ a:active {
132
+ color: #555;
133
+ background-color:#deb887;
134
+ text-decoration: none;
135
+ display: inline-block;
129
136
  }
130
137
  div.blockquote {
131
138
  display: block;
data/lib/almirah.rb CHANGED
@@ -18,11 +18,11 @@ class Almirah
18
18
 
19
19
  attr_accessor :project
20
20
 
21
- def initialize project_folder
22
- @project = Project.new project_folder, getGemRoot
21
+ def initialize(project_folder)
22
+ @project = Project.new project_folder
23
23
  end
24
24
 
25
- def getGemRoot
25
+ def getGemRoot()
26
26
  File.expand_path './..', File.dirname(__FILE__)
27
27
  end
28
28
 
@@ -30,7 +30,7 @@ class Almirah
30
30
  @project.specifications_and_results test_run
31
31
  end
32
32
 
33
- def default
33
+ def default()
34
34
  @project.specifications_and_protocols
35
35
  end
36
36
 
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.7
4
+ version: 0.0.9
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-10 00:00:00.000000000 Z
11
+ date: 2024-03-03 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,10 +30,12 @@ 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
35
+ - lib/almirah/doc_types/coverage.rb
34
36
  - lib/almirah/doc_types/protocol.rb
35
37
  - lib/almirah/doc_types/specification.rb
36
- - lib/almirah/html_render.rb
38
+ - lib/almirah/doc_types/traceability.rb
37
39
  - lib/almirah/navigation_pane.rb
38
40
  - lib/almirah/project.rb
39
41
  - lib/almirah/templates/page.html
@@ -56,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
58
  - !ruby/object:Gem::Version
57
59
  version: '0'
58
60
  requirements: []
59
- rubygems_version: 3.1.6
61
+ rubygems_version: 3.5.6
60
62
  signing_key:
61
63
  specification_version: 4
62
64
  summary: Almirah
@@ -1,54 +0,0 @@
1
-
2
- class HtmlRender
3
-
4
- attr_accessor :template
5
- attr_accessor :htmlRows
6
- attr_accessor :outputFile
7
- attr_accessor :document
8
- attr_accessor :nav_pane
9
-
10
- def initialize(document, nav_pane, template, outputFile)
11
-
12
- @template = template
13
- @outputFile = outputFile
14
- @htmlRows = Array.new
15
- @document = document
16
- @nav_pane = nav_pane
17
-
18
- self.render()
19
- self.saveRenderToFile()
20
- end
21
-
22
- def render()
23
- self.htmlRows.append('')
24
-
25
- self.document.items.each do |item|
26
- a = item.to_html
27
- self.htmlRows.append a
28
- end
29
- end
30
-
31
- def saveRenderToFile()
32
-
33
- file = File.open( self.template )
34
- file_data = file.readlines
35
- file.close
36
-
37
- file = File.open( self.outputFile, "w" )
38
- file_data.each do |s|
39
- if s.include?('{{CONTENT}}')
40
- self.htmlRows.each do |r|
41
- file.puts r
42
- end
43
- elsif s.include?('{{NAV_PANE}}')
44
- if @nav_pane
45
- file.puts self.nav_pane.to_html
46
- end
47
- else
48
- file.puts s
49
- end
50
- end
51
- file.close
52
- end
53
-
54
- end