spoom 1.0.1 → 1.0.6
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/Gemfile +4 -1
- data/README.md +253 -1
- data/Rakefile +2 -0
- data/exe/spoom +7 -0
- data/lib/spoom.rb +9 -1
- data/lib/spoom/cli.rb +68 -0
- data/lib/spoom/cli/bump.rb +59 -0
- data/lib/spoom/cli/config.rb +51 -0
- data/lib/spoom/cli/coverage.rb +191 -0
- data/lib/spoom/cli/helper.rb +70 -0
- data/lib/spoom/cli/lsp.rb +165 -0
- data/lib/spoom/cli/run.rb +79 -0
- data/lib/spoom/config.rb +11 -0
- data/lib/spoom/coverage.rb +73 -0
- data/lib/spoom/coverage/d3.rb +110 -0
- data/lib/spoom/coverage/d3/base.rb +50 -0
- data/lib/spoom/coverage/d3/circle_map.rb +195 -0
- data/lib/spoom/coverage/d3/pie.rb +175 -0
- data/lib/spoom/coverage/d3/timeline.rb +486 -0
- data/lib/spoom/coverage/report.rb +308 -0
- data/lib/spoom/coverage/snapshot.rb +132 -0
- data/lib/spoom/file_tree.rb +196 -0
- data/lib/spoom/git.rb +98 -0
- data/lib/spoom/printer.rb +81 -0
- data/lib/spoom/sorbet.rb +83 -0
- data/lib/spoom/sorbet/config.rb +21 -9
- data/lib/spoom/sorbet/errors.rb +139 -0
- data/lib/spoom/sorbet/lsp.rb +196 -0
- data/lib/spoom/sorbet/lsp/base.rb +58 -0
- data/lib/spoom/sorbet/lsp/errors.rb +45 -0
- data/lib/spoom/sorbet/lsp/structures.rb +312 -0
- data/lib/spoom/sorbet/metrics.rb +33 -0
- data/lib/spoom/sorbet/sigils.rb +98 -0
- data/lib/spoom/test_helpers/project.rb +103 -0
- data/lib/spoom/timeline.rb +53 -0
- data/lib/spoom/version.rb +2 -1
- data/templates/card.erb +8 -0
- data/templates/card_snapshot.erb +22 -0
- data/templates/page.erb +50 -0
- metadata +80 -20
@@ -0,0 +1,33 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "sigils"
|
5
|
+
|
6
|
+
module Spoom
|
7
|
+
module Sorbet
|
8
|
+
module MetricsParser
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
DEFAULT_PREFIX = "ruby_typer.unknown.."
|
12
|
+
|
13
|
+
sig { params(path: String, prefix: String).returns(T::Hash[String, Integer]) }
|
14
|
+
def self.parse_file(path, prefix = DEFAULT_PREFIX)
|
15
|
+
parse_string(File.read(path), prefix)
|
16
|
+
end
|
17
|
+
|
18
|
+
sig { params(string: String, prefix: String).returns(T::Hash[String, Integer]) }
|
19
|
+
def self.parse_string(string, prefix = DEFAULT_PREFIX)
|
20
|
+
parse_hash(JSON.parse(string), prefix)
|
21
|
+
end
|
22
|
+
|
23
|
+
sig { params(obj: T::Hash[String, T.untyped], prefix: String).returns(T::Hash[String, Integer]) }
|
24
|
+
def self.parse_hash(obj, prefix = DEFAULT_PREFIX)
|
25
|
+
obj["metrics"].each_with_object(Hash.new(0)) do |metric, metrics|
|
26
|
+
name = metric["name"]
|
27
|
+
name = name.sub(prefix, '')
|
28
|
+
metrics[name] = metric["value"] || 0
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# The term "sigil" refers to the magic comment at the top of the file that has the form `# typed: <strictness>`,
|
5
|
+
# where "strictness" represents the level at which Sorbet will report errors
|
6
|
+
# See https://sorbet.org/docs/static for a more complete explanation
|
7
|
+
module Spoom
|
8
|
+
module Sorbet
|
9
|
+
module Sigils
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
STRICTNESS_IGNORE = "ignore"
|
13
|
+
STRICTNESS_FALSE = "false"
|
14
|
+
STRICTNESS_TRUE = "true"
|
15
|
+
STRICTNESS_STRICT = "strict"
|
16
|
+
STRICTNESS_STRONG = "strong"
|
17
|
+
STRICTNESS_INTERNAL = "__STDLIB_INTERNAL"
|
18
|
+
|
19
|
+
VALID_STRICTNESS = T.let([
|
20
|
+
STRICTNESS_IGNORE,
|
21
|
+
STRICTNESS_FALSE,
|
22
|
+
STRICTNESS_TRUE,
|
23
|
+
STRICTNESS_STRICT,
|
24
|
+
STRICTNESS_STRONG,
|
25
|
+
STRICTNESS_INTERNAL,
|
26
|
+
].freeze, T::Array[String])
|
27
|
+
|
28
|
+
SIGIL_REGEXP = T.let(/^#\s*typed\s*:\s*(\w*)\s*$/.freeze, Regexp)
|
29
|
+
|
30
|
+
# returns the full sigil comment string for the passed strictness
|
31
|
+
sig { params(strictness: String).returns(String) }
|
32
|
+
def self.sigil_string(strictness)
|
33
|
+
"# typed: #{strictness}"
|
34
|
+
end
|
35
|
+
|
36
|
+
# returns true if the passed string is a valid strictness (else false)
|
37
|
+
sig { params(strictness: String).returns(T::Boolean) }
|
38
|
+
def self.valid_strictness?(strictness)
|
39
|
+
VALID_STRICTNESS.include?(strictness.strip)
|
40
|
+
end
|
41
|
+
|
42
|
+
# returns the strictness of a sigil in the passed file content string (nil if no sigil)
|
43
|
+
sig { params(content: String).returns(T.nilable(String)) }
|
44
|
+
def self.strictness_in_content(content)
|
45
|
+
SIGIL_REGEXP.match(content)&.[](1)
|
46
|
+
end
|
47
|
+
|
48
|
+
# returns a string which is the passed content but with the sigil updated to a new strictness
|
49
|
+
sig { params(content: String, new_strictness: String).returns(String) }
|
50
|
+
def self.update_sigil(content, new_strictness)
|
51
|
+
content.sub(SIGIL_REGEXP, sigil_string(new_strictness))
|
52
|
+
end
|
53
|
+
|
54
|
+
# returns a string containing the strictness of a sigil in a file at the passed path
|
55
|
+
# * returns nil if no sigil
|
56
|
+
sig { params(path: T.any(String, Pathname)).returns(T.nilable(String)) }
|
57
|
+
def self.file_strictness(path)
|
58
|
+
return nil unless File.exist?(path)
|
59
|
+
content = File.read(path)
|
60
|
+
strictness_in_content(content)
|
61
|
+
end
|
62
|
+
|
63
|
+
# changes the sigil in the file at the passed path to the specified new strictness
|
64
|
+
sig { params(path: T.any(String, Pathname), new_strictness: String).returns(T::Boolean) }
|
65
|
+
def self.change_sigil_in_file(path, new_strictness)
|
66
|
+
content = File.read(path)
|
67
|
+
new_content = update_sigil(content, new_strictness)
|
68
|
+
|
69
|
+
File.write(path, new_content)
|
70
|
+
|
71
|
+
strictness_in_content(new_content) == new_strictness
|
72
|
+
end
|
73
|
+
|
74
|
+
# changes the sigil to have a new strictness in a list of files
|
75
|
+
sig { params(path_list: T::Array[String], new_strictness: String).returns(T::Array[String]) }
|
76
|
+
def self.change_sigil_in_files(path_list, new_strictness)
|
77
|
+
path_list.filter do |path|
|
78
|
+
change_sigil_in_file(path, new_strictness)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# finds all files in the specified directory with the passed strictness
|
83
|
+
sig do
|
84
|
+
params(
|
85
|
+
directory: T.any(String, Pathname),
|
86
|
+
strictness: String,
|
87
|
+
extension: String
|
88
|
+
).returns(T::Array[String])
|
89
|
+
end
|
90
|
+
def self.files_with_sigil_strictness(directory, strictness, extension = ".rb")
|
91
|
+
paths = Dir.glob("#{File.expand_path(directory)}/**/*#{extension}").sort.uniq
|
92
|
+
paths.filter do |path|
|
93
|
+
file_strictness(path) == strictness
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "fileutils"
|
5
|
+
require "open3"
|
6
|
+
require "pathname"
|
7
|
+
|
8
|
+
require_relative "../git"
|
9
|
+
|
10
|
+
module Spoom
|
11
|
+
module TestHelpers
|
12
|
+
# A simple project abstraction for testing purposes
|
13
|
+
class Project
|
14
|
+
extend T::Sig
|
15
|
+
|
16
|
+
# The absolute path to this test project
|
17
|
+
sig { returns(String) }
|
18
|
+
attr_reader :path
|
19
|
+
|
20
|
+
# Create a new test project at `path`
|
21
|
+
sig { params(path: String).void }
|
22
|
+
def initialize(path)
|
23
|
+
@path = path
|
24
|
+
FileUtils.rm_rf(@path)
|
25
|
+
FileUtils.mkdir_p(@path)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Content
|
29
|
+
|
30
|
+
# Set the content of the Gemfile in this project
|
31
|
+
sig { params(content: String).void }
|
32
|
+
def gemfile(content)
|
33
|
+
write("Gemfile", content)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Set the content of `sorbet/config` in this project
|
37
|
+
sig { params(content: String).void }
|
38
|
+
def sorbet_config(content)
|
39
|
+
write("sorbet/config", content)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Write `content` in the file at `rel_path`
|
43
|
+
sig { params(rel_path: String, content: String).void }
|
44
|
+
def write(rel_path, content = "")
|
45
|
+
path = absolute_path(rel_path)
|
46
|
+
FileUtils.mkdir_p(File.dirname(path))
|
47
|
+
File.write(path, content)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Remove `rel_path`
|
51
|
+
sig { params(rel_path: String).void }
|
52
|
+
def remove(rel_path)
|
53
|
+
FileUtils.rm_rf(absolute_path(rel_path))
|
54
|
+
end
|
55
|
+
|
56
|
+
# List all files in this project
|
57
|
+
sig { returns(T::Array[String]) }
|
58
|
+
def files
|
59
|
+
Dir.glob("#{@path}/**/*").sort
|
60
|
+
end
|
61
|
+
|
62
|
+
# Actions
|
63
|
+
|
64
|
+
# Run `git init` in this project
|
65
|
+
sig { void }
|
66
|
+
def git_init
|
67
|
+
Spoom::Git.exec("git init -q", path: path)
|
68
|
+
Spoom::Git.exec("git config user.name 'spoom-tests'", path: path)
|
69
|
+
Spoom::Git.exec("git config user.email 'spoom@shopify.com'", path: path)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Commit all new changes in this project
|
73
|
+
sig { params(message: String, date: Time).void }
|
74
|
+
def commit(message = "message", date: Time.now.utc)
|
75
|
+
Spoom::Git.exec("git add --all", path: path)
|
76
|
+
Spoom::Git.exec("GIT_COMMITTER_DATE=\"#{date}\" git commit -m '#{message}' --date '#{date}'", path: path)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Run a command with `bundle exec` in this project
|
80
|
+
sig { params(cmd: String, args: String).returns([T.nilable(String), T.nilable(String), T::Boolean]) }
|
81
|
+
def bundle_exec(cmd, *args)
|
82
|
+
opts = {}
|
83
|
+
opts[:chdir] = path
|
84
|
+
out, err, status = Open3.capture3(["bundle", "exec", cmd, *args].join(' '), opts)
|
85
|
+
[out, err, status.success?]
|
86
|
+
end
|
87
|
+
|
88
|
+
# Delete this project and its content
|
89
|
+
sig { void }
|
90
|
+
def destroy
|
91
|
+
FileUtils.rm_rf(path)
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# Create an absolute path from `self.path` and `rel_path`
|
97
|
+
sig { params(rel_path: String).returns(String) }
|
98
|
+
def absolute_path(rel_path)
|
99
|
+
(Pathname.new(path) / rel_path).to_s
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "git"
|
5
|
+
|
6
|
+
module Spoom
|
7
|
+
class Timeline
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(from: Time, to: Time, path: String).void }
|
11
|
+
def initialize(from, to, path: ".")
|
12
|
+
@from = from
|
13
|
+
@to = to
|
14
|
+
@path = path
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return one commit for each month between `from` and `to`
|
18
|
+
sig { returns(T::Array[String]) }
|
19
|
+
def ticks
|
20
|
+
commits_for_dates(months)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return all months between `from` and `to`
|
24
|
+
sig { returns(T::Array[Time]) }
|
25
|
+
def months
|
26
|
+
d = Date.new(@from.year, @from.month, 1)
|
27
|
+
to = Date.new(@to.year, @to.month, 1)
|
28
|
+
res = [d.to_time]
|
29
|
+
while d < to
|
30
|
+
d = d.next_month
|
31
|
+
res << d.to_time
|
32
|
+
end
|
33
|
+
res
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return one commit for each date in `dates`
|
37
|
+
sig { params(dates: T::Array[Time]).returns(T::Array[String]) }
|
38
|
+
def commits_for_dates(dates)
|
39
|
+
dates.map do |t|
|
40
|
+
out, _, _ = Spoom::Git.log(
|
41
|
+
"--since='#{t}'",
|
42
|
+
"--until='#{t.to_date.next_month}'",
|
43
|
+
"--format='format:%h'",
|
44
|
+
"--author-date-order",
|
45
|
+
"-1",
|
46
|
+
path: @path,
|
47
|
+
)
|
48
|
+
next if out.empty?
|
49
|
+
out
|
50
|
+
end.compact.uniq
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/spoom/version.rb
CHANGED
data/templates/card.erb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
<div class="card">
|
2
|
+
<% if title %>
|
3
|
+
<h5 class="card-header"><%= title %></h5>
|
4
|
+
<% end %>
|
5
|
+
<div class="card-body">
|
6
|
+
<div class="container-fluid">
|
7
|
+
<div class="row justify-content-md-center">
|
8
|
+
<div class="col-12 col-sm-4 col-xl-3">
|
9
|
+
<%= pie_sigils.html %>
|
10
|
+
</div>
|
11
|
+
<div class="d-none d-xl-block col-xl-1"></div>
|
12
|
+
<div class="col-12 col-sm-4 col-xl-3">
|
13
|
+
<%= pie_calls.html %>
|
14
|
+
</div>
|
15
|
+
<div class="d-none d-xl-block col-xl-1"></div>
|
16
|
+
<div class="col-12 col-sm-4 col-xl-3">
|
17
|
+
<%= pie_sigs.html %>
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
</div>
|
data/templates/page.erb
ADDED
@@ -0,0 +1,50 @@
|
|
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" />
|
7
|
+
|
8
|
+
<title><%= title %></title>
|
9
|
+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
|
10
|
+
|
11
|
+
<style>
|
12
|
+
.card {
|
13
|
+
margin: 30px 0 0 0;
|
14
|
+
}
|
15
|
+
|
16
|
+
.footer {
|
17
|
+
color: #6c757d;
|
18
|
+
text-align: center;
|
19
|
+
margin: 30px 0 0 0;
|
20
|
+
}
|
21
|
+
|
22
|
+
<%= header_style %>
|
23
|
+
</style>
|
24
|
+
</head>
|
25
|
+
<body>
|
26
|
+
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
27
|
+
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
|
28
|
+
<script src="https://d3js.org/d3.v4.min.js"></script>
|
29
|
+
|
30
|
+
<script>
|
31
|
+
<%= header_script %>
|
32
|
+
</script>
|
33
|
+
|
34
|
+
<div class="px-5 py-4 container-fluid">
|
35
|
+
<div class="row justify-content-center">
|
36
|
+
<div class="col-xs-12 col-md-12 col-lg-9 col-xl-8">
|
37
|
+
<div class="header">
|
38
|
+
<%= header_html %>
|
39
|
+
</div>
|
40
|
+
<div class="body">
|
41
|
+
<%= body_html %>
|
42
|
+
</div>
|
43
|
+
<div class="footer">
|
44
|
+
<%= footer_html %>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
</body>
|
50
|
+
</html>
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spoom
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexandre Terrasa
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: sorbet-runtime
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,14 +30,14 @@ dependencies:
|
|
44
30
|
requirements:
|
45
31
|
- - "~>"
|
46
32
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
33
|
+
version: 13.0.1
|
48
34
|
type: :development
|
49
35
|
prerelease: false
|
50
36
|
version_requirements: !ruby/object:Gem::Requirement
|
51
37
|
requirements:
|
52
38
|
- - "~>"
|
53
39
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
40
|
+
version: 13.0.1
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: minitest
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +52,20 @@ dependencies:
|
|
66
52
|
- - "~>"
|
67
53
|
- !ruby/object:Gem::Version
|
68
54
|
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sorbet-runtime
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: sorbet
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,9 +80,37 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 0.5.5
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: thor
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.19.2
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.19.2
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: colorize
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
description:
|
84
112
|
email:
|
85
|
-
-
|
113
|
+
- ruby@shopify.com
|
86
114
|
executables:
|
87
115
|
- spoom
|
88
116
|
extensions: []
|
@@ -93,8 +121,40 @@ files:
|
|
93
121
|
- Rakefile
|
94
122
|
- exe/spoom
|
95
123
|
- lib/spoom.rb
|
124
|
+
- lib/spoom/cli.rb
|
125
|
+
- lib/spoom/cli/bump.rb
|
126
|
+
- lib/spoom/cli/config.rb
|
127
|
+
- lib/spoom/cli/coverage.rb
|
128
|
+
- lib/spoom/cli/helper.rb
|
129
|
+
- lib/spoom/cli/lsp.rb
|
130
|
+
- lib/spoom/cli/run.rb
|
131
|
+
- lib/spoom/config.rb
|
132
|
+
- lib/spoom/coverage.rb
|
133
|
+
- lib/spoom/coverage/d3.rb
|
134
|
+
- lib/spoom/coverage/d3/base.rb
|
135
|
+
- lib/spoom/coverage/d3/circle_map.rb
|
136
|
+
- lib/spoom/coverage/d3/pie.rb
|
137
|
+
- lib/spoom/coverage/d3/timeline.rb
|
138
|
+
- lib/spoom/coverage/report.rb
|
139
|
+
- lib/spoom/coverage/snapshot.rb
|
140
|
+
- lib/spoom/file_tree.rb
|
141
|
+
- lib/spoom/git.rb
|
142
|
+
- lib/spoom/printer.rb
|
143
|
+
- lib/spoom/sorbet.rb
|
96
144
|
- lib/spoom/sorbet/config.rb
|
145
|
+
- lib/spoom/sorbet/errors.rb
|
146
|
+
- lib/spoom/sorbet/lsp.rb
|
147
|
+
- lib/spoom/sorbet/lsp/base.rb
|
148
|
+
- lib/spoom/sorbet/lsp/errors.rb
|
149
|
+
- lib/spoom/sorbet/lsp/structures.rb
|
150
|
+
- lib/spoom/sorbet/metrics.rb
|
151
|
+
- lib/spoom/sorbet/sigils.rb
|
152
|
+
- lib/spoom/test_helpers/project.rb
|
153
|
+
- lib/spoom/timeline.rb
|
97
154
|
- lib/spoom/version.rb
|
155
|
+
- templates/card.erb
|
156
|
+
- templates/card_snapshot.erb
|
157
|
+
- templates/page.erb
|
98
158
|
homepage: https://github.com/Shopify/spoom
|
99
159
|
licenses:
|
100
160
|
- MIT
|
@@ -108,7 +168,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
108
168
|
requirements:
|
109
169
|
- - ">="
|
110
170
|
- !ruby/object:Gem::Version
|
111
|
-
version: 2.
|
171
|
+
version: 2.3.7
|
112
172
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
173
|
requirements:
|
114
174
|
- - ">="
|