condition_coverage 0.0.4 → 0.0.5

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: eb36ad570a0050db876bba37548a59c929604eb35b88ed4b8ac4a155dde4db6e
4
- data.tar.gz: 77f2dd1b7da7815a216fac0bee73f251f1c8d2c9490ad416d26125ac1adcfbe8
3
+ metadata.gz: a61c323a92442b231f61a10ea7ee622ee5e3b957f9818819e56aefda2ed75efd
4
+ data.tar.gz: eba0b9b94f2ba0756f0549d9675a4d3cb4c548df4854114df6e76e7ce09cdbeb
5
5
  SHA512:
6
- metadata.gz: 5571a2753478ab9ed18b6a1e04b47df6f4f96b03f10637ac9bf8e0ad4149b8a02d6b6abf754b45e533c0eb37a417fffe9a7a937c3c86a6bf15b51fe13d2bed03
7
- data.tar.gz: 5d97b90e7c1bff46242a833f234ef1a5ef62e8732bd2a2fe3f9b1f65fe441b0bcad5da1eeaf2ad0912ae7406ce3baf1c77067571b0751e6a9c6f602e831eca62
6
+ metadata.gz: f84973aba8aa9323ba03323f5fabe1b99feda591d0973a715e27f792a61971c50fb87b90680db5245451f16a90180dcae7272a8bdc33fd25998429d63860cd45
7
+ data.tar.gz: b992c871ed4f1bd658d828fec3da583199a4ddf3a44c26f0cb79b142f57f74e294a5f9c50e672780fb4f213986163f9c5b0a64e03903e462aebaf8c7a78e07ae
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Condition coverage for Ruby, to run alongside SimpleCov's line and branch
4
4
  coverage.
5
5
 
6
- Status: 0.0.4 covers `&&`, `||`, `and` and `or`: each leaf operand of a
6
+ Status: 0.0.5 covers `&&`, `||`, `and` and `or`: each leaf operand of a
7
7
  condition, however its operators are chained, nested or grouped. Decisions
8
8
  hidden inside calls come next (see Roadmap).
9
9
 
@@ -77,8 +77,9 @@ nothing.
77
77
 
78
78
  An operand whose form allows one outcome only needs only to be evaluated:
79
79
  its other outcome is impossible, not a gap. `Foo.new`, literals (`'s'`,
80
- `1`, `:k`, `[]`, `{}`, `true`) and lambdas can only be truthy; `nil` and
81
- `false` only falsy:
80
+ `1`, `:k`, `[]`, `{}`, `true`), lambdas and constants (`LATEST`,
81
+ `Config::DEFAULT`, since one holding nil or false is rare) can only be
82
+ truthy; `nil` and `false` only falsy:
82
83
 
83
84
  ```ruby
84
85
  @clock = options[:clock] || MonotonicClock.new # operand 1: never evaluated, or no gap
@@ -92,7 +93,10 @@ its other outcome is impossible, not a gap. `Foo.new`, literals (`'s'`,
92
93
  missing) that opens a tree of the condition: its operators, nested as
93
94
  Ruby groups them, and each leaf operand's true and false counts and its
94
95
  gap. A condition written over several lines has one button over all of
95
- its line numbers.
96
+ its line numbers. Trees with gaps start open. A header that stays at
97
+ the top of the page lists every site as a link to its line, covered
98
+ sites first, then those with gaps, and arrows beside each site with
99
+ gaps jump to the previous and next one, wrapping round at either end.
96
100
 
97
101
  ## How it works
98
102
 
@@ -12,8 +12,11 @@
12
12
  </head>
13
13
  <body>
14
14
  <main class="page">
15
+ <header class="head" data-head="">
15
16
  <p class="back"><a data-index="" href="{{index}}">Condition coverage</a></p>
16
17
  <h1 class="path">{{path}}</h1>
18
+ {{jumps}}
19
+ </header>
17
20
  <div class="box">
18
21
  {{listing}}
19
22
  </div>
@@ -13,6 +13,13 @@
13
13
  --bad: #B54708;
14
14
  --on-status: #FFFFFF;
15
15
  --link: #1F5FBF;
16
+ /* The tree is inverted from the page, so it never reads as
17
+ more source lines. */
18
+ --tree-bg: #1E2638;
19
+ --tree-fg: #E8ECF4;
20
+ --tree-muted: #A3AEC2;
21
+ --tree-rule: #3A4560;
22
+ --tree-gap: #F5A25D;
16
23
  --font-body: "Helvetica Neue", Arial, sans-serif;
17
24
  --font-code: Menlo, Consolas, "DejaVu Sans Mono", monospace;
18
25
  }
@@ -21,6 +28,8 @@
21
28
  --bg: #12151C; --surface: #181C25; --panel: #212633; --fg: #E4E8EF;
22
29
  --muted: #9AA4B5; --rule: #323949; --ok: #7FB0FF; --ok-tint: #1A2740;
23
30
  --warn: #F0A35E; --bad: #F08A3C; --on-status: #12151C; --link: #7FB0FF;
31
+ --tree-bg: #E6EAF2; --tree-fg: #1C2230; --tree-muted: #4E5869;
32
+ --tree-rule: #BCC4D2; --tree-gap: #A8480A;
24
33
  color-scheme: dark;
25
34
  }
26
35
  }
@@ -52,6 +61,39 @@ th button:focus-visible { outline: 3px solid var(--link); outline-offset: 2px; }
52
61
  digits stay aligned whether or not they are on a button. */
53
62
  .back { margin: 0; font-size: 14px; }
54
63
  h1.path { font-family: var(--font-code); font-size: 20px; }
64
+ /* The back link, path and site lists stick together as one
65
+ header. */
66
+ .head {
67
+ position: sticky; top: 0; z-index: 5;
68
+ display: flex; flex-direction: column; gap: 10px;
69
+ margin: 0 -16px; padding: 12px 16px; background: var(--bg);
70
+ border-bottom: 1px solid var(--rule);
71
+ }
72
+ .jumps { display: flex; flex-direction: column; gap: 8px; }
73
+ .jump-list { display: flex; gap: 6px; align-items: center; overflow-x: auto; white-space: nowrap; min-width: 0; }
74
+ .jump-label { width: 64px; flex-shrink: 0; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; }
75
+ a.jump {
76
+ font: 600 13px/22px var(--font-code); padding: 0 9px; border-radius: 999px;
77
+ text-decoration: none; border: 1px solid; font-variant-numeric: tabular-nums;
78
+ }
79
+ a.jump[data-status="covered"] { background: var(--ok-tint); color: var(--ok); border-color: var(--ok); }
80
+ a.jump[data-status="gaps"] { background: var(--bad); color: var(--on-status); border-color: var(--bad); }
81
+ a.jump:focus-visible, .nav a:focus-visible { outline: 3px solid var(--link); outline-offset: 2px; }
82
+ /* The source pane's border and background start after the nav
83
+ column, so the arrows sit outside the pane yet scroll with
84
+ their line. */
85
+ .box:has(> .code) { position: relative; isolation: isolate; border: 0; background: none; border-radius: 0; }
86
+ .box:has(> .code)::before {
87
+ content: ""; position: absolute; inset: 0 0 0 48px; z-index: -1;
88
+ border: 1px solid var(--rule); border-radius: 8px;
89
+ background: var(--surface); pointer-events: none;
90
+ }
91
+ .nav { display: flex; width: 48px; flex-shrink: 0; }
92
+ .nav a { width: 22px; text-align: center; line-height: 32px; font-size: 18px; color: var(--bad); text-decoration: none; }
93
+ .nav a:hover { color: var(--fg); }
94
+ /* Clears the sticky header when a link jumps to a line. */
95
+ .lineno { scroll-margin-top: 190px; }
96
+ button.lnum:has(.lineno:target) { outline: 3px solid var(--link); outline-offset: 2px; }
55
97
  .code { font-family: var(--font-code); font-size: 14px; line-height: 32px; padding: 10px 0; min-width: 720px; }
56
98
  .line, .block { display: flex; align-items: flex-start; }
57
99
  .srcs { display: flex; flex-direction: column; }
@@ -84,7 +126,7 @@ button.lnum:has(.lineno + .lineno)::before { top: auto; bottom: 2px; line-height
84
126
  /* The rule between sites spans the tree's full width, through
85
127
  its 16px side padding. */
86
128
  .site + .site {
87
- border-top: 1px solid var(--rule); margin: 6px -16px 0; padding: 6px 16px 0;
129
+ border-top: 1px solid var(--tree-rule); margin: 6px -16px 0; padding: 6px 16px 0;
88
130
  }
89
131
  button.lnum .lineno { width: 50px; padding-right: 19px; color: inherit; line-height: 32px; margin: -4px 0; }
90
132
  button.lnum[data-status="covered"] { background: var(--ok-tint); color: var(--ok); border-color: var(--ok); }
@@ -92,15 +134,16 @@ button.lnum[data-status="gaps"] { background: var(--bad); color: var(--on-status
92
134
  button.lnum:hover { filter: brightness(1.1); }
93
135
  button.lnum:focus-visible { outline: 3px solid var(--link); outline-offset: 2px; }
94
136
  .tree {
95
- margin: 4px 20px 12px 72px; padding: 10px 16px; border: 1px solid var(--rule);
96
- border-radius: 8px; background: var(--panel); line-height: 30px;
137
+ margin: 4px 20px 12px 120px; padding: 10px 16px; border: 1px solid var(--tree-rule);
138
+ border-radius: 8px; background: var(--tree-bg); color: var(--tree-fg); line-height: 30px;
139
+ box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
97
140
  }
98
141
  .row { display: grid; grid-template-columns: auto minmax(200px, 1fr) 70px 70px 160px; column-gap: 16px; }
99
- .row.headings { font-family: var(--font-body); font-size: 12px; color: var(--muted); }
142
+ .row.headings { font-family: var(--font-body); font-size: 12px; color: var(--tree-muted); }
100
143
  .row.headings span:first-child { grid-column: span 2; }
101
144
  .row.headings span:nth-child(2), .row.headings span:nth-child(3) { text-align: right; }
102
145
  .operator { grid-column: span 2; font-weight: 600; }
103
- .branch { white-space: pre; color: var(--muted); margin-right: -16px; }
146
+ .branch { white-space: pre; color: var(--tree-muted); margin-right: -16px; }
104
147
  .row .text { white-space: pre; }
105
148
  .row .truthy, .row .falsy { text-align: right; font-variant-numeric: tabular-nums; }
106
- .row .gap { color: var(--bad); }
149
+ .row .gap { color: var(--tree-gap); font-weight: 600; }
@@ -1,5 +1,7 @@
1
1
  require 'cgi/escape'
2
+ require_relative 'html_nav'
2
3
  require_relative 'html_template'
4
+ require_relative 'html_tree'
3
5
 
4
6
  module ConditionCoverage
5
7
  # One covered file's HTML page: its source, with the numbers
@@ -16,6 +18,7 @@ module ConditionCoverage
16
18
  'index' => "#{'../' * (path.count('/') + 1)}index.html",
17
19
  'style' => HtmlTemplate.asset('style.css'),
18
20
  'script' => HtmlTemplate.asset('toggle.js'),
21
+ 'jumps' => HtmlNav.jumps(lines),
19
22
  'listing' => listing(lines, trees)
20
23
  )
21
24
  end
@@ -28,30 +31,36 @@ module ConditionCoverage
28
31
  blocks = lines.chunk_while do |line, following|
29
32
  line[:span] && line[:span] == following[:span]
30
33
  end
31
- body = blocks.map { |block| block(block, trees) }.join("\n")
32
- %(<div class="code">\n#{body}\n</div>)
34
+ gaps = HtmlNav.gap_lines(blocks)
35
+ body = blocks.map { |block| block(block, trees, gaps) }
36
+ %(<div class="code">\n#{body.join("\n")}\n</div>)
33
37
  end
34
38
 
35
39
  # A plain line, or the lines of one span behind one button
36
- # with the span's tree straight after them.
37
- def self.block(lines, trees)
40
+ # with the span's tree straight after them; either way after
41
+ # its nav cell.
42
+ def self.block(lines, trees, gaps)
38
43
  first = lines[0]
39
- return plain_line(first) if first[:span].nil?
40
-
41
44
  number = first[:number]
45
+ cell = HtmlNav.cell(number, gaps)
46
+ return plain_line(first, cell) if first[:span].nil?
47
+
42
48
  site_trees = trees.fetch(number, [])
43
- span_block(lines, site_trees.size) + tree(number, site_trees)
49
+ open = first[:status] == :gaps
50
+ span_block(lines, site_trees.size, cell) +
51
+ HtmlTree.of(number, site_trees, open)
44
52
  end
45
53
 
46
- # The lines of one span: one button over all their numbers,
47
- # and how many sites it opens when that is two or more,
48
- # beside their code.
49
- def self.span_block(lines, sites)
54
+ # The lines of one span after their nav cell: one button over
55
+ # all their numbers, and how many sites it opens when that is
56
+ # two or more, beside their code.
57
+ def self.span_block(lines, sites, cell)
50
58
  numbers = lines.map { |line| number(line[:number]) }.join
51
59
  codes = lines.map { |line| code(line) }.join
52
60
  srcs = %(<div class="srcs">#{codes}</div>)
53
61
  content = site_count(sites) + numbers
54
- %(<div class="block">#{button(lines[0], content)}#{srcs}</div>)
62
+ button = button(lines[0], content)
63
+ %(<div class="block">#{cell}#{button}#{srcs}</div>)
55
64
  end
56
65
 
57
66
  # The count of a button's sites, shown only for two or more.
@@ -61,93 +70,28 @@ module ConditionCoverage
61
70
  %(<span class="site-count" data-site-count="">#{sites}</span>)
62
71
  end
63
72
 
64
- HEADINGS = %w[condition true false gap].freeze
65
-
66
- # The hidden tree of a span: a heading row, then each site's
67
- # rows in a group of their own.
68
- def self.tree(number, site_trees)
69
- groups = site_trees.map do |site|
70
- rows = site_rows(site).join
71
- %(<div class="site" data-site="">#{rows}</div>)
72
- end
73
- id = "tree-#{number}"
74
- body = [heading_row, *groups].join
75
- %(<div class="tree" id="#{id}" hidden="hidden">#{body}</div>)
76
- end
77
-
78
- # The row naming each column of a tree.
79
- def self.heading_row
80
- cells = HEADINGS.map { |name| %(<span>#{name}</span>) }.join
81
- %(<div class="row headings" data-heading="">#{cells}</div>)
82
- end
83
-
84
- # A site's operator row, then the rows of its operands.
85
- def self.site_rows(site)
86
- row = %(<div class="row">#{operator(site)}</div>)
87
- [row, *operand_rows(site, '')]
88
- end
89
-
90
- # The rows of a condition's operands, each branching from
91
- # its operator after indent; a nested condition's operands
92
- # follow its own row, indented under its branch.
93
- def self.operand_rows(condition, indent)
94
- last = condition[:operands].size - 1
95
- condition[:operands].each_with_index.flat_map do |operand, i|
96
- tip = i == last
97
- branch = indent + (tip ? '└─ ' : '├─ ')
98
- next [operand_row(operand, branch)] unless operand[:operator]
99
-
100
- nested = operand_rows(operand, indent + (tip ? ' ' : '│ '))
101
- [subtree_row(operand, branch), *nested]
102
- end
103
- end
104
-
105
- # A nested condition's row: its branch and its operator.
106
- def self.subtree_row(condition, branch)
107
- cells = branch_cell(branch) + operator(condition)
108
- %(<div class="row" data-subtree="">#{cells}</div>)
109
- end
110
-
111
- # The cell naming a condition's operator.
112
- def self.operator(condition)
113
- name = CGI.escapeHTML(condition[:operator])
114
- %(<span class="operator" data-operator="">#{name}</span>)
115
- end
116
-
117
- # One operand's row: its branch, text, true and false
118
- # counts, and gap.
119
- def self.operand_row(operand, branch)
120
- cells = %i[text truthy falsy gap].map do |name|
121
- value = CGI.escapeHTML(operand[name].to_s)
122
- %(<span class="#{name}" data-#{name}="">#{value}</span>)
123
- end
124
- lead = branch_cell(branch)
125
- %(<div class="row" data-operand="">#{lead}#{cells.join}</div>)
126
- end
127
-
128
- # The cell drawing a row's branch from its operator.
129
- def self.branch_cell(branch)
130
- %(<span class="branch" data-branch="">#{branch}</span>)
131
- end
132
-
133
- # A line with no condition: its number, then its code.
134
- def self.plain_line(line)
135
- %(<div class="line">#{number(line[:number])}#{code(line)}</div>)
73
+ # A line with no condition: its nav cell, number and code.
74
+ def self.plain_line(line, cell)
75
+ parts = cell + number(line[:number]) + code(line)
76
+ %(<div class="line">#{parts}</div>)
136
77
  end
137
78
 
138
- # The closed button over a span's numbers, opening the tree
139
- # named after its first line.
79
+ # The button over a span's numbers, toggling the tree named
80
+ # after its first line; expanded when that tree starts open.
140
81
  def self.button(first, numbers)
82
+ expanded = first[:status] == :gaps
141
83
  [
142
84
  %(<button type="button" class="lnum"),
143
- %( data-status="#{first[:status]}" aria-expanded="false"),
85
+ %( data-status="#{first[:status]}"),
86
+ %( aria-expanded="#{expanded}"),
144
87
  %( aria-controls="tree-#{first[:number]}">#{numbers}</button>)
145
88
  ].join
146
89
  end
147
90
 
148
- # One line's number.
91
+ # One line's number, the target of a link to #L<number>.
149
92
  def self.number(number)
150
- %(<span class="lineno" data-line="#{number}">#{number}</span>)
93
+ attributes = %(id="L#{number}" data-line="#{number}")
94
+ %(<span class="lineno" #{attributes}>#{number}</span>)
151
95
  end
152
96
 
153
97
  # One line's code, escaped.
@@ -0,0 +1,67 @@
1
+ module ConditionCoverage
2
+ # The ways around a file's page: the header's lists of links to
3
+ # each span, and the arrows between the spans with gaps.
4
+ module HtmlNav
5
+ JUMP_LISTS = { 'covered' => 'Covered', 'gaps' => 'Gaps' }.freeze
6
+
7
+ # The header's lists of links to the first line of each span:
8
+ # those covered, then those with gaps.
9
+ def self.jumps(lines)
10
+ firsts = lines.select { |line| first_of_span?(line) }
11
+ lists = JUMP_LISTS.map do |status, label|
12
+ spans = firsts.select { |line| line[:status].to_s == status }
13
+ jump_list(status, label, spans.map { |line| line[:number] })
14
+ end
15
+ %(<nav class="jumps" aria-label="Sites">#{lists.join}</nav>)
16
+ end
17
+
18
+ # True for the line a span starts on.
19
+ def self.first_of_span?(line)
20
+ line[:span]&.begin == line[:number]
21
+ end
22
+
23
+ # One labelled list of links to lines.
24
+ def self.jump_list(status, label, numbers)
25
+ links = numbers.map { |number| jump(status, number) }
26
+ name = %(<span class="jump-label">#{label}</span>)
27
+ list = %(<div class="jump-list" data-jumps="#{status}">)
28
+ "#{list}#{name}#{links.join}</div>"
29
+ end
30
+
31
+ # One link to a line.
32
+ def self.jump(status, number)
33
+ attributes = %(data-status="#{status}" href="#L#{number}")
34
+ %(<a class="jump" #{attributes}>#{number}</a>)
35
+ end
36
+
37
+ # The first line of each span whose sites have gaps, given the
38
+ # listing's blocks.
39
+ def self.gap_lines(blocks)
40
+ firsts = blocks.map(&:first)
41
+ firsts.select { |line| line[:status] == :gaps }.map do |line|
42
+ line[:number]
43
+ end
44
+ end
45
+
46
+ # The cell left of a row's number: at a span with gaps, links
47
+ # to the previous and next such span, wrapping round at the
48
+ # ends; empty on every other row, so the numbers stay aligned.
49
+ def self.cell(number, gaps)
50
+ index = gaps.index(number)
51
+ links = index ? arrows(gaps, index) : ''
52
+ %(<span class="nav" data-nav="">#{links}</span>)
53
+ end
54
+
55
+ # The links to the spans with gaps either side of gaps[index].
56
+ def self.arrows(gaps, index)
57
+ previous = gaps[index - 1]
58
+ following = gaps[(index + 1) % gaps.size]
59
+ [
60
+ %(<a data-prev="" href="#L#{previous}"),
61
+ %( aria-label="Previous gap, line #{previous}">&#9650;</a>),
62
+ %(<a data-next="" href="#L#{following}"),
63
+ %( aria-label="Next gap, line #{following}">&#9660;</a>)
64
+ ].join
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,77 @@
1
+ require 'cgi/escape'
2
+
3
+ module ConditionCoverage
4
+ # The tree of a span's sites on a file's page, from SiteTree.of
5
+ # for each site.
6
+ module HtmlTree
7
+ HEADINGS = %w[condition true false gap].freeze
8
+
9
+ # The tree of a span, open when its sites have gaps, else
10
+ # hidden: a heading row, then each site's rows in a group of
11
+ # their own.
12
+ def self.of(number, site_trees, open)
13
+ groups = site_trees.map do |site|
14
+ rows = site_rows(site).join
15
+ %(<div class="site" data-site="">#{rows}</div>)
16
+ end
17
+ hidden = open ? '' : ' hidden="hidden"'
18
+ body = [heading_row, *groups].join
19
+ %(<div class="tree" id="tree-#{number}"#{hidden}>#{body}</div>)
20
+ end
21
+
22
+ # The row naming each column of a tree.
23
+ def self.heading_row
24
+ cells = HEADINGS.map { |name| %(<span>#{name}</span>) }.join
25
+ %(<div class="row headings" data-heading="">#{cells}</div>)
26
+ end
27
+
28
+ # A site's operator row, then the rows of its operands.
29
+ def self.site_rows(site)
30
+ row = %(<div class="row">#{operator(site)}</div>)
31
+ [row, *operand_rows(site, '')]
32
+ end
33
+
34
+ # The rows of a condition's operands, each branching from
35
+ # its operator after indent; a nested condition's operands
36
+ # follow its own row, indented under its branch.
37
+ def self.operand_rows(condition, indent)
38
+ last = condition[:operands].size - 1
39
+ condition[:operands].each_with_index.flat_map do |operand, i|
40
+ tip = i == last
41
+ branch = indent + (tip ? '└─ ' : '├─ ')
42
+ next [operand_row(operand, branch)] unless operand[:operator]
43
+
44
+ nested = operand_rows(operand, indent + (tip ? ' ' : '│ '))
45
+ [subtree_row(operand, branch), *nested]
46
+ end
47
+ end
48
+
49
+ # A nested condition's row: its branch and its operator.
50
+ def self.subtree_row(condition, branch)
51
+ cells = branch_cell(branch) + operator(condition)
52
+ %(<div class="row" data-subtree="">#{cells}</div>)
53
+ end
54
+
55
+ # The cell naming a condition's operator.
56
+ def self.operator(condition)
57
+ name = CGI.escapeHTML(condition[:operator])
58
+ %(<span class="operator" data-operator="">#{name}</span>)
59
+ end
60
+
61
+ # One operand's row: its branch, text, true and false
62
+ # counts, and gap.
63
+ def self.operand_row(operand, branch)
64
+ cells = %i[text truthy falsy gap].map do |name|
65
+ value = CGI.escapeHTML(operand[name].to_s)
66
+ %(<span class="#{name}" data-#{name}="">#{value}</span>)
67
+ end
68
+ lead = branch_cell(branch)
69
+ %(<div class="row" data-operand="">#{lead}#{cells.join}</div>)
70
+ end
71
+
72
+ # The cell drawing a row's branch from its operator.
73
+ def self.branch_cell(branch)
74
+ %(<span class="branch" data-branch="">#{branch}</span>)
75
+ end
76
+ end
77
+ end
@@ -89,9 +89,11 @@ module ConditionCoverage
89
89
  range
90
90
  end
91
91
 
92
+ # A constant is taken to be truthy, as one holding nil or
93
+ # false is rare.
92
94
  TRUTHY_TYPES = %i[
93
95
  string_node integer_node symbol_node array_node hash_node
94
- true_node lambda_node
96
+ true_node lambda_node constant_read_node constant_path_node
95
97
  ].freeze
96
98
  FALSY_TYPES = %i[nil_node false_node].freeze
97
99
 
@@ -1,3 +1,3 @@
1
1
  module ConditionCoverage
2
- VERSION = '0.0.4'.freeze
2
+ VERSION = '0.0.5'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: condition_coverage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Jagger
@@ -42,8 +42,10 @@ files:
42
42
  - lib/condition_coverage/html/toggle.js
43
43
  - lib/condition_coverage/html_file.rb
44
44
  - lib/condition_coverage/html_index.rb
45
+ - lib/condition_coverage/html_nav.rb
45
46
  - lib/condition_coverage/html_report.rb
46
47
  - lib/condition_coverage/html_template.rb
48
+ - lib/condition_coverage/html_tree.rb
47
49
  - lib/condition_coverage/json_writer.rb
48
50
  - lib/condition_coverage/kernel.rb
49
51
  - lib/condition_coverage/manifest.rb