Almirah 0.0.7 → 0.0.9

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: 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