Skip to content
3 changes: 3 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ Sorbet/TrueSigil:

Sorbet/EnforceSigilOrder:
Enabled: true

Sorbet/ForbidTStruct:
Enabled: true
10 changes: 5 additions & 5 deletions lib/spoom/cli/srb/coverage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,11 @@ def report
end.filter(&:commit_timestamp).sort_by!(&:commit_timestamp)

palette = Spoom::Coverage::D3::ColorPalette.new(
ignore: options[:color_ignore],
false: options[:color_false],
true: options[:color_true],
strict: options[:color_strict],
strong: options[:color_strong],
ignore_color: options[:color_ignore],
false_color: options[:color_false],
true_color: options[:color_true],
strict_color: options[:color_strict],
strong_color: options[:color_strong],
)

report = Spoom::Coverage.report(context, snapshots, palette: palette)
Expand Down
25 changes: 20 additions & 5 deletions lib/spoom/context/exec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,26 @@
require "shellwords"

module Spoom
class ExecResult < T::Struct
const :out, String
const :err, T.nilable(String)
const :status, T::Boolean
const :exit_code, Integer
class ExecResult
#: String
attr_reader :out

#: String?
attr_reader :err

#: bool
attr_reader :status

#: Integer
attr_reader :exit_code

#: (out: String, status: bool, exit_code: Integer, ?err: String?) -> void
def initialize(out:, status:, exit_code:, err: nil)
@out = out
@err = err
@status = status
@exit_code = exit_code
end

#: -> String
def to_s
Expand Down
15 changes: 12 additions & 3 deletions lib/spoom/context/git.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

module Spoom
module Git
class Commit < T::Struct
class Commit
class << self
# Parse a line formatted as `%h %at` into a `Commit`
#: (String string) -> Commit?
Expand All @@ -16,8 +16,17 @@ def parse_line(string)
end
end

const :sha, String
const :time, Time
#: String
attr_reader :sha

#: Time
attr_reader :time

#: (sha: String, time: Time) -> void
def initialize(sha:, time:)
@sha = sha
@time = time
end

#: -> Integer
def timestamp
Expand Down
48 changes: 36 additions & 12 deletions lib/spoom/coverage/d3.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,17 @@ def header_script(palette)
function strictnessColor(strictness) {
switch(strictness) {
case "ignore":
return "#{palette.ignore}";
return "#{palette.ignore_color}";
case "false":
return "#{palette.false}";
return "#{palette.false_color}";
case "true":
return "#{palette.true}";
return "#{palette.true_color}";
case "strict":
return "#{palette.strict}";
return "#{palette.strict_color}";
case "strong":
return "#{palette.strong}";
return "#{palette.strong_color}";
}
return "#{palette.false}";
return "#{palette.false_color}";
}

function toPercent(value, sum) {
Expand All @@ -98,12 +98,36 @@ def header_script(palette)
end
end

class ColorPalette < T::Struct
prop :ignore, String
prop :false, String
prop :true, String
prop :strict, String
prop :strong, String
class ColorPalette
#: String
attr_accessor :ignore_color

#: String
attr_accessor :false_color

#: String
attr_accessor :true_color

#: String
attr_accessor :strict_color

#: String
attr_accessor :strong_color

#: (
#| ignore_color: String,
#| false_color: String,
#| true_color: String,
#| strict_color: String,
#| strong_color: String
#| ) -> void
def initialize(ignore_color:, false_color:, true_color:, strict_color:, strong_color:)
@ignore_color = ignore_color
@false_color = false_color
@true_color = true_color
@strict_color = strict_color
@strong_color = strong_color
end
end
end
end
Expand Down
168 changes: 147 additions & 21 deletions lib/spoom/coverage/snapshot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,126 @@

module Spoom
module Coverage
class Snapshot < T::Struct
prop :timestamp, Integer, default: Time.new.getutc.to_i
prop :version_static, T.nilable(String), default: nil
prop :version_runtime, T.nilable(String), default: nil
prop :duration, Integer, default: 0
prop :commit_sha, T.nilable(String), default: nil
prop :commit_timestamp, T.nilable(Integer), default: nil
prop :files, Integer, default: 0
prop :rbi_files, Integer, default: 0
prop :modules, Integer, default: 0
prop :classes, Integer, default: 0
prop :singleton_classes, Integer, default: 0
prop :methods_without_sig, Integer, default: 0
prop :methods_with_sig, Integer, default: 0
prop :calls_untyped, Integer, default: 0
prop :calls_typed, Integer, default: 0
prop :sigils, T::Hash[String, Integer], default: Hash.new(0)
prop :methods_with_sig_excluding_rbis, Integer, default: 0
prop :methods_without_sig_excluding_rbis, Integer, default: 0
prop :sigils_excluding_rbis, T::Hash[String, Integer], default: Hash.new(0)
class Snapshot
#: Integer
attr_accessor :timestamp

#: String?
attr_accessor :version_static

#: String?
attr_accessor :version_runtime

#: Integer
attr_accessor :duration

#: String?
attr_accessor :commit_sha

#: Integer?
attr_accessor :commit_timestamp

#: Integer
attr_accessor :files

#: Integer
attr_accessor :rbi_files

#: Integer
attr_accessor :modules

#: Integer
attr_accessor :classes

#: Integer
attr_accessor :singleton_classes

#: Integer
attr_accessor :methods_without_sig

#: Integer
attr_accessor :methods_with_sig

#: Integer
attr_accessor :calls_untyped

#: Integer
attr_accessor :calls_typed

#: Hash[String, Integer]
attr_accessor :sigils

#: Integer
attr_accessor :methods_with_sig_excluding_rbis

#: Integer
attr_accessor :methods_without_sig_excluding_rbis

#: Hash[String, Integer]
attr_accessor :sigils_excluding_rbis

#: (
#| ?timestamp: Integer,
#| ?version_static: String?,
#| ?version_runtime: String?,
#| ?duration: Integer,
#| ?commit_sha: String?,
#| ?commit_timestamp: Integer?,
#| ?files: Integer,
#| ?rbi_files: Integer,
#| ?modules: Integer,
#| ?classes: Integer,
#| ?singleton_classes: Integer,
#| ?methods_without_sig: Integer,
#| ?methods_with_sig: Integer,
#| ?calls_untyped: Integer,
#| ?calls_typed: Integer,
#| ?sigils: Hash[String, Integer],
#| ?methods_with_sig_excluding_rbis: Integer,
#| ?methods_without_sig_excluding_rbis: Integer,
#| ?sigils_excluding_rbis: Hash[String, Integer],
#| ) -> void
def initialize(
timestamp: Time.new.getutc.to_i,
version_static: nil,
version_runtime: nil,
duration: 0,
commit_sha: nil,
commit_timestamp: nil,
files: 0,
rbi_files: 0,
modules: 0,
classes: 0,
singleton_classes: 0,
methods_without_sig: 0,
methods_with_sig: 0,
calls_untyped: 0,
calls_typed: 0,
sigils: Hash.new(0),
methods_with_sig_excluding_rbis: 0,
methods_without_sig_excluding_rbis: 0,
sigils_excluding_rbis: Hash.new(0)
)
@timestamp = timestamp
@version_static = version_static
@version_runtime = version_runtime
@duration = duration
@commit_sha = commit_sha
@commit_timestamp = commit_timestamp
@files = files
@rbi_files = rbi_files
@modules = modules
@classes = classes
@singleton_classes = singleton_classes
@methods_without_sig = methods_without_sig
@methods_with_sig = methods_with_sig
@calls_untyped = calls_untyped
@calls_typed = calls_typed
@sigils = sigils
@methods_with_sig_excluding_rbis = methods_with_sig_excluding_rbis
@methods_without_sig_excluding_rbis = methods_without_sig_excluding_rbis
@sigils_excluding_rbis = sigils_excluding_rbis
end

# The strictness name as found in the Sorbet metrics file
STRICTNESSES = ["ignore", "false", "true", "strict", "strong", "stdlib"].freeze #: Array[String]
Expand All @@ -35,7 +135,33 @@ def print(out: $stdout, colors: true, indent_level: 0)

#: (*untyped arg) -> String
def to_json(*arg)
serialize.to_json(*arg)
to_h #: untyped
.to_json(*arg)
end

#: -> Hash[String, untyped]
def to_h
{
"timestamp" => timestamp,
"version_static" => version_static,
"version_runtime" => version_runtime,
"duration" => duration,
"commit_sha" => commit_sha,
"commit_timestamp" => commit_timestamp,
"files" => files,
"rbi_files" => rbi_files,
"modules" => modules,
"classes" => classes,
"singleton_classes" => singleton_classes,
"methods_with_sig" => methods_with_sig,
"methods_without_sig" => methods_without_sig,
"calls_typed" => calls_typed,
"calls_untyped" => calls_untyped,
"sigils" => sigils,
"methods_with_sig_excluding_rbis" => methods_with_sig_excluding_rbis,
"methods_without_sig_excluding_rbis" => methods_without_sig_excluding_rbis,
"sigils_excluding_rbis" => sigils_excluding_rbis,
}
end

class << self
Expand Down
30 changes: 24 additions & 6 deletions lib/spoom/deadcode/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
module Spoom
module Deadcode
# A definition is a class, module, method, constant, etc. being defined in the code
class Definition < T::Struct
class Definition
class Kind < T::Enum
enums do
AttrReader = new("attr_reader")
Expand All @@ -27,11 +27,29 @@ class Status < T::Enum
end
end

const :kind, Kind
const :name, String
const :full_name, String
const :location, Location
const :status, Status, default: Status::DEAD
#: Kind
attr_reader :kind

#: String
attr_reader :name

#: String
attr_reader :full_name

#: Location
attr_reader :location

#: Status
attr_reader :status

#: (kind: Kind, name: String, full_name: String, location: Location, ?status: Status) -> void
def initialize(kind:, name:, full_name:, location:, status: Status::DEAD)
@kind = kind
@name = name
@full_name = full_name
@location = location
@status = status
end

# Kind

Expand Down
Loading