cover_rage 0.0.1 → 0.0.4
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 +4 -4
- data/bin/cover_rage +34 -2
- data/lib/cover_rage/config.rb +4 -0
- data/lib/cover_rage/reporters/html_reporter/index.html.erb +215 -0
- data/lib/cover_rage/reporters/html_reporter.rb +15 -0
- data/lib/cover_rage/reporters/json_reporter.rb +13 -0
- data/lib/cover_rage/stores/redis.rb +1 -0
- metadata +27 -10
- data/bin/config.ru +0 -5
- data/lib/cover_rage/viewer/file.erb +0 -51
- data/lib/cover_rage/viewer/index.erb +0 -28
- data/lib/cover_rage/viewer/layout.erb +0 -9
- data/lib/cover_rage/viewer.rb +0 -80
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 56c953122e72d8aaa3a4a50129595cfc36fb20f1c2feea245b255295a5ba8a90
         | 
| 4 | 
            +
              data.tar.gz: 7b5b4972c31670c4c9ab6b5298682ce7b8d258f4a0ff31faf8790856f1691428
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 26cd15a4e159851270b8c9b351e1047049eb509e1ebc322634d94ab8c53f2e8e42d22ca4521c07af7d784e3d8fa5993fc59e57bbeba0d2c49fa83b86ba5b5a88
         | 
| 7 | 
            +
              data.tar.gz: 38e670bed372e6117c64967fc32a124e2dcac34734e14f05e954b282de01cd557af0847a69c16474e3e13c4352ec57a878d96b95925fc08c88612a5774b6c89c
         | 
    
        data/bin/cover_rage
    CHANGED
    
    | @@ -1,5 +1,37 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 4 | 
            +
            if ARGV.first == 'clear'
         | 
| 5 | 
            +
              require 'cover_rage/config'
         | 
| 6 | 
            +
              CoverRage::Config.store.clear
         | 
| 7 | 
            +
              exit
         | 
| 8 | 
            +
            end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            require 'optparse'
         | 
| 11 | 
            +
            options = { format: 'html' }
         | 
| 12 | 
            +
            OptionParser.new do |parser|
         | 
| 13 | 
            +
              parser.banner = <<~USAGE
         | 
| 14 | 
            +
                Clear store:
         | 
| 15 | 
            +
                  #{$PROGRAM_NAME} clear
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                Export report:
         | 
| 18 | 
            +
                  #{$PROGRAM_NAME} [options]
         | 
| 19 | 
            +
              USAGE
         | 
| 20 | 
            +
              parser.on('-fFORMAT', '--format=FORMAT', 'output format (json|html)') { options[:format] = _1 }
         | 
| 21 | 
            +
            end.parse!
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            reporter =
         | 
| 24 | 
            +
              case options[:format]
         | 
| 25 | 
            +
              when 'json'
         | 
| 26 | 
            +
                require 'cover_rage/reporters/json_reporter'
         | 
| 27 | 
            +
                CoverRage::Reporters::JsonReporter.new
         | 
| 28 | 
            +
              when 'html'
         | 
| 29 | 
            +
                require 'cover_rage/reporters/html_reporter'
         | 
| 30 | 
            +
                CoverRage::Reporters::HtmlReporter.new
         | 
| 31 | 
            +
              else
         | 
| 32 | 
            +
                warn "Unknown format: #{options[:format]}"
         | 
| 33 | 
            +
                exit 1
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            require 'cover_rage/config'
         | 
| 37 | 
            +
            puts reporter.report(CoverRage::Config.store.list)
         | 
    
        data/lib/cover_rage/config.rb
    CHANGED
    
    
| @@ -0,0 +1,215 @@ | |
| 1 | 
            +
            <!DOCTYPE html>
         | 
| 2 | 
            +
            <html lang="en">
         | 
| 3 | 
            +
              <head>
         | 
| 4 | 
            +
                <meta charset="UTF-8" />
         | 
| 5 | 
            +
                <meta http-equiv="X-UA-Compatible" content="IE=edge" />
         | 
| 6 | 
            +
                <meta name="viewport" content="width=device-width, initial-scale=1.0" />
         | 
| 7 | 
            +
                <title>CoverRage</title>
         | 
| 8 | 
            +
                <link
         | 
| 9 | 
            +
                  rel="stylesheet"
         | 
| 10 | 
            +
                  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css"
         | 
| 11 | 
            +
                />
         | 
| 12 | 
            +
                <style>
         | 
| 13 | 
            +
                  .line {
         | 
| 14 | 
            +
                    width: 100%;
         | 
| 15 | 
            +
                    display: inline-block;
         | 
| 16 | 
            +
                    counter-increment: line_number;
         | 
| 17 | 
            +
                  }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  .green {
         | 
| 20 | 
            +
                    background-color: rgb(221, 255, 221);
         | 
| 21 | 
            +
                  }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  .red {
         | 
| 24 | 
            +
                    background-color: rgb(255, 212, 212);
         | 
| 25 | 
            +
                  }
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  .number {
         | 
| 28 | 
            +
                    display: inline-block;
         | 
| 29 | 
            +
                    text-align: right;
         | 
| 30 | 
            +
                    margin-right: 0.5em;
         | 
| 31 | 
            +
                    background-color: lightgray;
         | 
| 32 | 
            +
                    padding: 0 0.5em 0 1.5em;
         | 
| 33 | 
            +
                  }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  .nav {
         | 
| 36 | 
            +
                    display: flex;
         | 
| 37 | 
            +
                    list-style: none;
         | 
| 38 | 
            +
                    padding-left: 0;
         | 
| 39 | 
            +
                  }
         | 
| 40 | 
            +
                  .nav > * {
         | 
| 41 | 
            +
                    margin-left: 8px;
         | 
| 42 | 
            +
                  }
         | 
| 43 | 
            +
                </style>
         | 
| 44 | 
            +
              </head>
         | 
| 45 | 
            +
              <body>
         | 
| 46 | 
            +
                <main id="main"></main>
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                <div style="display: none">
         | 
| 49 | 
            +
                  <div id="page-index">
         | 
| 50 | 
            +
                    <nav>
         | 
| 51 | 
            +
                      <ul class="nav">
         | 
| 52 | 
            +
                        <li><a href="#/">Index</a></li>
         | 
| 53 | 
            +
                      </ul>
         | 
| 54 | 
            +
                    </nav>
         | 
| 55 | 
            +
                    <table>
         | 
| 56 | 
            +
                      <thead>
         | 
| 57 | 
            +
                        <tr>
         | 
| 58 | 
            +
                          <th>path</th>
         | 
| 59 | 
            +
                          <th>lines</th>
         | 
| 60 | 
            +
                          <th>relevancy</th>
         | 
| 61 | 
            +
                          <th>hit</th>
         | 
| 62 | 
            +
                          <th>miss</th>
         | 
| 63 | 
            +
                          <th>coverage (%)</th>
         | 
| 64 | 
            +
                        </tr>
         | 
| 65 | 
            +
                      </thead>
         | 
| 66 | 
            +
                      <tbody></tbody>
         | 
| 67 | 
            +
                    </table>
         | 
| 68 | 
            +
                  </div>
         | 
| 69 | 
            +
                  <div id="page-file">
         | 
| 70 | 
            +
                    <nav>
         | 
| 71 | 
            +
                      <ul class="nav">
         | 
| 72 | 
            +
                        <li><a href="#/">Index</a></li>
         | 
| 73 | 
            +
                        <li>></li>
         | 
| 74 | 
            +
                        <li id="title"></li>
         | 
| 75 | 
            +
                      </ul>
         | 
| 76 | 
            +
                    </nav>
         | 
| 77 | 
            +
                    <pre><code id="code"></code></pre>
         | 
| 78 | 
            +
                  </div>
         | 
| 79 | 
            +
                </div>
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                <script id="records" type="application/json"><%= records %></script>
         | 
| 82 | 
            +
                <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
         | 
| 83 | 
            +
                <script>
         | 
| 84 | 
            +
                  const main = document.getElementById("main");
         | 
| 85 | 
            +
                  const page_index = document.getElementById("page-index");
         | 
| 86 | 
            +
                  const title = document.createTextNode("");
         | 
| 87 | 
            +
                  document.getElementById("title").appendChild(title);
         | 
| 88 | 
            +
                  const code = document.getElementById("code");
         | 
| 89 | 
            +
                  const page_file = document.getElementById("page-file");
         | 
| 90 | 
            +
                  const records = JSON.parse(
         | 
| 91 | 
            +
                    document.getElementById("records").childNodes[0].nodeValue
         | 
| 92 | 
            +
                  );
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  const route = (path) => {
         | 
| 95 | 
            +
                    if (path.startsWith("/file/")) {
         | 
| 96 | 
            +
                      const filepath = path.slice(6);
         | 
| 97 | 
            +
                      if (records.find((record) => record.path === filepath))
         | 
| 98 | 
            +
                        return { page: "file", path: filepath };
         | 
| 99 | 
            +
                    }
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                    return { page: "index" };
         | 
| 102 | 
            +
                  };
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  const render = (routing) => {
         | 
| 105 | 
            +
                    let page;
         | 
| 106 | 
            +
                    if (routing.page === "file") {
         | 
| 107 | 
            +
                      const record = records.find(({ path }) => path === routing.path);
         | 
| 108 | 
            +
                      page = page_file;
         | 
| 109 | 
            +
                      title.nodeValue = routing.path;
         | 
| 110 | 
            +
                      const digit_width =
         | 
| 111 | 
            +
                        Math.floor(Math.log10(Math.max(...record.execution_count))) + 1;
         | 
| 112 | 
            +
                      code.innerHTML = hljs
         | 
| 113 | 
            +
                        .highlight(
         | 
| 114 | 
            +
                          records.find(({ path }) => path === routing.path).source,
         | 
| 115 | 
            +
                          {
         | 
| 116 | 
            +
                            language: "ruby",
         | 
| 117 | 
            +
                          }
         | 
| 118 | 
            +
                        )
         | 
| 119 | 
            +
                        .value.split("\n")
         | 
| 120 | 
            +
                        .map((line, index) => {
         | 
| 121 | 
            +
                          const value = record.execution_count[index];
         | 
| 122 | 
            +
                          let color = "";
         | 
| 123 | 
            +
                          if (typeof value === "number")
         | 
| 124 | 
            +
                            color = value > 0 ? "green" : "red";
         | 
| 125 | 
            +
                          const number = typeof value === "number" ? value : "-";
         | 
| 126 | 
            +
                          return `<span class="line ${color}"><span class="number">${number
         | 
| 127 | 
            +
                            .toString()
         | 
| 128 | 
            +
                            .padStart(digit_width, " ")}</span>${line}</span>`;
         | 
| 129 | 
            +
                        })
         | 
| 130 | 
            +
                        .join("\n");
         | 
| 131 | 
            +
                    }
         | 
| 132 | 
            +
                    if (routing.page === "index") {
         | 
| 133 | 
            +
                      page = page_index;
         | 
| 134 | 
            +
                    }
         | 
| 135 | 
            +
                    if (main.childNodes.length === 0) main.appendChild(page);
         | 
| 136 | 
            +
                    else main.replaceChild(page, main.childNodes[0]);
         | 
| 137 | 
            +
                  };
         | 
| 138 | 
            +
                  const createTdTextNode = (text) => {
         | 
| 139 | 
            +
                    const td = document.createElement("td");
         | 
| 140 | 
            +
                    td.appendChild(document.createTextNode(text));
         | 
| 141 | 
            +
                    return td;
         | 
| 142 | 
            +
                  };
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                  page_index.querySelector("tbody").appendChild(
         | 
| 145 | 
            +
                    records
         | 
| 146 | 
            +
                      .map(({ path, revision, source, execution_count }) => {
         | 
| 147 | 
            +
                        const hit = execution_count.reduce(
         | 
| 148 | 
            +
                          (accumulator, current) =>
         | 
| 149 | 
            +
                            current > 0 ? accumulator + 1 : accumulator,
         | 
| 150 | 
            +
                          0
         | 
| 151 | 
            +
                        );
         | 
| 152 | 
            +
                        const miss = execution_count.reduce(
         | 
| 153 | 
            +
                          (accumulator, current) =>
         | 
| 154 | 
            +
                            current === 0 ? accumulator + 1 : accumulator,
         | 
| 155 | 
            +
                          0
         | 
| 156 | 
            +
                        );
         | 
| 157 | 
            +
                        const relevancy = execution_count.reduce(
         | 
| 158 | 
            +
                          (accumulator, current) =>
         | 
| 159 | 
            +
                            current !== null ? accumulator + 1 : accumulator,
         | 
| 160 | 
            +
                          0
         | 
| 161 | 
            +
                        );
         | 
| 162 | 
            +
                        const coverage = hit / relevancy;
         | 
| 163 | 
            +
                        return {
         | 
| 164 | 
            +
                          path,
         | 
| 165 | 
            +
                          lines: execution_count.length,
         | 
| 166 | 
            +
                          hit,
         | 
| 167 | 
            +
                          miss,
         | 
| 168 | 
            +
                          relevancy,
         | 
| 169 | 
            +
                          coverage,
         | 
| 170 | 
            +
                        };
         | 
| 171 | 
            +
                      })
         | 
| 172 | 
            +
                      .sort(({ coverage: a }, { coverage: b }) => {
         | 
| 173 | 
            +
                        if (isNaN(b)) return -1;
         | 
| 174 | 
            +
                        if (isNaN(a)) return 1;
         | 
| 175 | 
            +
                        return a - b;
         | 
| 176 | 
            +
                      })
         | 
| 177 | 
            +
                      .reduce(
         | 
| 178 | 
            +
                        (fragment, { path, lines, hit, miss, relevancy, coverage }) => {
         | 
| 179 | 
            +
                          const tr = document.createElement("tr");
         | 
| 180 | 
            +
                          tr.appendChild(
         | 
| 181 | 
            +
                            (() => {
         | 
| 182 | 
            +
                              const anchor = document.createElement("a");
         | 
| 183 | 
            +
                              anchor.href = `#/file/${path}`;
         | 
| 184 | 
            +
                              anchor.appendChild(document.createTextNode(path));
         | 
| 185 | 
            +
                              const td = document.createElement("td");
         | 
| 186 | 
            +
                              td.appendChild(anchor);
         | 
| 187 | 
            +
                              return td;
         | 
| 188 | 
            +
                            })()
         | 
| 189 | 
            +
                          );
         | 
| 190 | 
            +
                          tr.appendChild(createTdTextNode(lines));
         | 
| 191 | 
            +
                          tr.appendChild(createTdTextNode(relevancy));
         | 
| 192 | 
            +
                          tr.appendChild(createTdTextNode(hit));
         | 
| 193 | 
            +
                          tr.appendChild(createTdTextNode(miss));
         | 
| 194 | 
            +
                          tr.appendChild(
         | 
| 195 | 
            +
                            createTdTextNode(Math.round(coverage * 10000) / 100)
         | 
| 196 | 
            +
                          );
         | 
| 197 | 
            +
                          fragment.appendChild(tr);
         | 
| 198 | 
            +
                          return fragment;
         | 
| 199 | 
            +
                        },
         | 
| 200 | 
            +
                        document.createDocumentFragment()
         | 
| 201 | 
            +
                      )
         | 
| 202 | 
            +
                  );
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                  document.addEventListener("DOMContentLoaded", () => {
         | 
| 205 | 
            +
                    const routing = route(window.location.hash.slice(1));
         | 
| 206 | 
            +
                    render(routing);
         | 
| 207 | 
            +
                  });
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                  window.addEventListener("popstate", (event) => {
         | 
| 210 | 
            +
                    const routing = route(window.location.hash.slice(1));
         | 
| 211 | 
            +
                    render(routing);
         | 
| 212 | 
            +
                  });
         | 
| 213 | 
            +
                </script>
         | 
| 214 | 
            +
              </body>
         | 
| 215 | 
            +
            </html>
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'erb'
         | 
| 4 | 
            +
            require 'json'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module CoverRage
         | 
| 7 | 
            +
              module Reporters
         | 
| 8 | 
            +
                class HtmlReporter
         | 
| 9 | 
            +
                  def report(records)
         | 
| 10 | 
            +
                    records = JSON.dump(records.map(&:to_h))
         | 
| 11 | 
            +
                    ERB.new(File.read("#{__dir__}/html_reporter/index.html.erb")).result(binding)
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: cover_rage
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.4
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Weihang Jian
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-05-19 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rake
         | 
| @@ -24,14 +24,32 @@ dependencies: | |
| 24 24 | 
             
                - - "~>"
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 26 | 
             
                    version: '13.0'
         | 
| 27 | 
            -
             | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: minitest
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '5.18'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '5.18'
         | 
| 41 | 
            +
            description: |
         | 
| 42 | 
            +
              A Ruby production code coverage tool designed to assist you in identifying unused code, offering the following features:
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              1. easy setup
         | 
| 45 | 
            +
              2. minimal performance overhead
         | 
| 46 | 
            +
              3. minimal external dependencies
         | 
| 28 47 | 
             
            email: tonytonyjan@gmail.com
         | 
| 29 48 | 
             
            executables:
         | 
| 30 49 | 
             
            - cover_rage
         | 
| 31 50 | 
             
            extensions: []
         | 
| 32 51 | 
             
            extra_rdoc_files: []
         | 
| 33 52 | 
             
            files:
         | 
| 34 | 
            -
            - bin/config.ru
         | 
| 35 53 | 
             
            - bin/cover_rage
         | 
| 36 54 | 
             
            - lib/cover_rage.rb
         | 
| 37 55 | 
             
            - lib/cover_rage/config.rb
         | 
| @@ -39,12 +57,11 @@ files: | |
| 39 57 | 
             
            - lib/cover_rage/launcher.rb
         | 
| 40 58 | 
             
            - lib/cover_rage/record.rb
         | 
| 41 59 | 
             
            - lib/cover_rage/recorder.rb
         | 
| 60 | 
            +
            - lib/cover_rage/reporters/html_reporter.rb
         | 
| 61 | 
            +
            - lib/cover_rage/reporters/html_reporter/index.html.erb
         | 
| 62 | 
            +
            - lib/cover_rage/reporters/json_reporter.rb
         | 
| 42 63 | 
             
            - lib/cover_rage/stores/redis.rb
         | 
| 43 64 | 
             
            - lib/cover_rage/stores/sqlite.rb
         | 
| 44 | 
            -
            - lib/cover_rage/viewer.rb
         | 
| 45 | 
            -
            - lib/cover_rage/viewer/file.erb
         | 
| 46 | 
            -
            - lib/cover_rage/viewer/index.erb
         | 
| 47 | 
            -
            - lib/cover_rage/viewer/layout.erb
         | 
| 48 65 | 
             
            homepage: https://github.com/tonytonyjan/cover_rage
         | 
| 49 66 | 
             
            licenses:
         | 
| 50 67 | 
             
            - MIT
         | 
| @@ -64,8 +81,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 64 81 | 
             
                - !ruby/object:Gem::Version
         | 
| 65 82 | 
             
                  version: '0'
         | 
| 66 83 | 
             
            requirements: []
         | 
| 67 | 
            -
            rubygems_version: 3.4. | 
| 84 | 
            +
            rubygems_version: 3.4.12
         | 
| 68 85 | 
             
            signing_key:
         | 
| 69 86 | 
             
            specification_version: 4
         | 
| 70 | 
            -
            summary: coverage  | 
| 87 | 
            +
            summary: A Ruby production code coverage tool
         | 
| 71 88 | 
             
            test_files: []
         | 
    
        data/bin/config.ru
    DELETED
    
    
| @@ -1,51 +0,0 @@ | |
| 1 | 
            -
            <link
         | 
| 2 | 
            -
              rel="stylesheet"
         | 
| 3 | 
            -
              href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css"
         | 
| 4 | 
            -
            />
         | 
| 5 | 
            -
            <style>
         | 
| 6 | 
            -
              .line {
         | 
| 7 | 
            -
                width: 100%;
         | 
| 8 | 
            -
                display: inline-block;
         | 
| 9 | 
            -
                counter-increment: line_number;
         | 
| 10 | 
            -
              }
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              .green {
         | 
| 13 | 
            -
                background-color: rgb(221, 255, 221);
         | 
| 14 | 
            -
              }
         | 
| 15 | 
            -
             | 
| 16 | 
            -
              .red {
         | 
| 17 | 
            -
                background-color: rgb(255, 212, 212);
         | 
| 18 | 
            -
              }
         | 
| 19 | 
            -
             | 
| 20 | 
            -
              .number {
         | 
| 21 | 
            -
                display: inline-block;
         | 
| 22 | 
            -
                text-align: right;
         | 
| 23 | 
            -
                margin-right: 0.5em;
         | 
| 24 | 
            -
                background-color: lightgray;
         | 
| 25 | 
            -
                padding: 0 0.5em 0 1.5em;
         | 
| 26 | 
            -
              }
         | 
| 27 | 
            -
            </style>
         | 
| 28 | 
            -
            <h1><%= path %></h1>
         | 
| 29 | 
            -
            <pre><code id="code"><%= source_code.encode(xml: :text) %></code></pre>
         | 
| 30 | 
            -
            <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
         | 
| 31 | 
            -
            <script id="execution_count" type="application/json"><%= execution_count.encode(xml: :text) %></script>
         | 
| 32 | 
            -
            <script>
         | 
| 33 | 
            -
              const execution_count = JSON.parse(
         | 
| 34 | 
            -
                document.querySelector("#execution_count").childNodes[0].nodeValue
         | 
| 35 | 
            -
              );
         | 
| 36 | 
            -
              const digit_width = Math.floor(Math.log10(Math.max(...execution_count))) + 1;
         | 
| 37 | 
            -
              const $code = document.querySelector("#code");
         | 
| 38 | 
            -
              $code.innerHTML = hljs
         | 
| 39 | 
            -
                .highlight($code.textContent, {
         | 
| 40 | 
            -
                  language: "ruby",
         | 
| 41 | 
            -
                })
         | 
| 42 | 
            -
                .value.split("\n")
         | 
| 43 | 
            -
                .map((line, index) => {
         | 
| 44 | 
            -
                  const value = execution_count[index];
         | 
| 45 | 
            -
                  let color = "";
         | 
| 46 | 
            -
                  if (typeof value === "number") color = value > 0 ? "green" : "red";
         | 
| 47 | 
            -
                  const number = typeof value === "number" ? value : "-";
         | 
| 48 | 
            -
                  return `<span class="line ${color}"><span class="number">${number.toString().padStart(digit_width, ' ')}</span>${line}</span>`;
         | 
| 49 | 
            -
                })
         | 
| 50 | 
            -
                .join("\n");
         | 
| 51 | 
            -
            </script>
         | 
| @@ -1,28 +0,0 @@ | |
| 1 | 
            -
            <table>
         | 
| 2 | 
            -
              <thead>
         | 
| 3 | 
            -
                <tr>
         | 
| 4 | 
            -
                  <th>path</th>
         | 
| 5 | 
            -
                  <th>lines</th>
         | 
| 6 | 
            -
                  <th>relevancy</th>
         | 
| 7 | 
            -
                  <th>hit</th>
         | 
| 8 | 
            -
                  <th>miss</th>
         | 
| 9 | 
            -
                  <th>coverage (%)</th>
         | 
| 10 | 
            -
                </tr>
         | 
| 11 | 
            -
              </thead>
         | 
| 12 | 
            -
              <tbody>
         | 
| 13 | 
            -
                <% items.each do |item| %>
         | 
| 14 | 
            -
                <tr>
         | 
| 15 | 
            -
                  <td>
         | 
| 16 | 
            -
                    <a href="/file?path=<%= URI.encode_uri_component(item.path) %>"
         | 
| 17 | 
            -
                      ><%= item.path %></a
         | 
| 18 | 
            -
                    >
         | 
| 19 | 
            -
                  </td>
         | 
| 20 | 
            -
                  <td style="text-align: right"><%= item.number_of_lines %></td>
         | 
| 21 | 
            -
                  <td style="text-align: right"><%= item.number_of_relevancies %></td>
         | 
| 22 | 
            -
                  <td style="text-align: right"><%= item.number_of_hits %></td>
         | 
| 23 | 
            -
                  <td style="text-align: right"><%= item.number_of_misses %></td>
         | 
| 24 | 
            -
                  <td style="text-align: right"><%= '%.2f' % (item.coverage * 100) %></td>
         | 
| 25 | 
            -
                </tr>
         | 
| 26 | 
            -
                <% end %>
         | 
| 27 | 
            -
              </tbody>
         | 
| 28 | 
            -
            </table>
         | 
    
        data/lib/cover_rage/viewer.rb
    DELETED
    
    | @@ -1,80 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require 'cover_rage/record'
         | 
| 4 | 
            -
            require 'erb'
         | 
| 5 | 
            -
            require 'json'
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            module CoverRage
         | 
| 8 | 
            -
              class Viewer
         | 
| 9 | 
            -
                LAYOUT_PAGE = ERB.new(File.read("#{__dir__}/viewer/layout.erb"))
         | 
| 10 | 
            -
                INDEX_PAGE = ERB.new(File.read("#{__dir__}/viewer/index.erb"))
         | 
| 11 | 
            -
                FILE_PAGE = ERB.new(File.read("#{__dir__}/viewer/file.erb"))
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                class Item
         | 
| 14 | 
            -
                  attr_reader(
         | 
| 15 | 
            -
                    :path,
         | 
| 16 | 
            -
                    :execution_count,
         | 
| 17 | 
            -
                    :number_of_lines,
         | 
| 18 | 
            -
                    :number_of_hits,
         | 
| 19 | 
            -
                    :number_of_misses,
         | 
| 20 | 
            -
                    :number_of_relevancies,
         | 
| 21 | 
            -
                    :coverage
         | 
| 22 | 
            -
                  )
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  def initialize(record)
         | 
| 25 | 
            -
                    @path = record.path
         | 
| 26 | 
            -
                    @execution_count = record.execution_count
         | 
| 27 | 
            -
                    @number_of_lines = record.execution_count.length
         | 
| 28 | 
            -
                    @number_of_hits = record.execution_count.count { _1&.positive? }
         | 
| 29 | 
            -
                    @number_of_misses = record.execution_count.count { _1&.zero? }
         | 
| 30 | 
            -
                    @number_of_relevancies = record.execution_count.count { !_1.nil? }
         | 
| 31 | 
            -
                    @coverage = @number_of_hits.to_f / @number_of_relevancies
         | 
| 32 | 
            -
                  end
         | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                def initialize(store:)
         | 
| 36 | 
            -
                  @store = store
         | 
| 37 | 
            -
                end
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                def call(env)
         | 
| 40 | 
            -
                  template =
         | 
| 41 | 
            -
                    case env['PATH_INFO']
         | 
| 42 | 
            -
                    when '/'
         | 
| 43 | 
            -
                      items =
         | 
| 44 | 
            -
                        @store
         | 
| 45 | 
            -
                        .list
         | 
| 46 | 
            -
                        .map! { Item.new(_1) }
         | 
| 47 | 
            -
                        .sort! do |a, b|
         | 
| 48 | 
            -
                          next -1 if b.coverage.nan?
         | 
| 49 | 
            -
                          next 1 if a.coverage.nan?
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                          a.coverage <=> b.coverage
         | 
| 52 | 
            -
                        end
         | 
| 53 | 
            -
                      INDEX_PAGE
         | 
| 54 | 
            -
                    when '/file'
         | 
| 55 | 
            -
                      path = URI.decode_www_form(env['QUERY_STRING']).assoc('path').last
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                      record = @store.find(path)
         | 
| 58 | 
            -
                      return [404, {}, []] if record.nil?
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                      source_code = record.source
         | 
| 61 | 
            -
                      execution_count = JSON.dump(record.execution_count)
         | 
| 62 | 
            -
                      FILE_PAGE
         | 
| 63 | 
            -
                    when '/clear'
         | 
| 64 | 
            -
                      return [405, {}, []] unless env['REQUEST_METHOD'] == 'DELETE'
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                      @store.clear
         | 
| 67 | 
            -
                      return [302, { 'location' => '/' }, []]
         | 
| 68 | 
            -
                    else return [404, {}, []]
         | 
| 69 | 
            -
                    end
         | 
| 70 | 
            -
                  body = layout { template.result(binding) }
         | 
| 71 | 
            -
                  [200, {}, [body]]
         | 
| 72 | 
            -
                end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                private
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                def layout
         | 
| 77 | 
            -
                  LAYOUT_PAGE.result(binding)
         | 
| 78 | 
            -
                end
         | 
| 79 | 
            -
              end
         | 
| 80 | 
            -
            end
         |