Module: Spoom::Context::Sorbet

Defined in:
lib/spoom/context/sorbet.rb

Overview

Sorbet features for a context @requires_ancestor: Context

Instance Method Summary collapse

Instance Method Details

#has_sorbet_config?Boolean

Does this context has a ‘sorbet/config` file? : -> bool

Returns:

  • (Boolean)


108
109
110
# File 'lib/spoom/context/sorbet.rb', line 108

def has_sorbet_config?
  file?(Spoom::Sorbet::CONFIG_PATH)
end

#read_file_strictness(relative_path) ⇒ Object

Read the strictness sigil from the file at ‘relative_path` (returns `nil` if no sigil) : (String relative_path) -> String?



131
132
133
# File 'lib/spoom/context/sorbet.rb', line 131

def read_file_strictness(relative_path)
  Spoom::Sorbet::Sigils.file_strictness(absolute_path_to(relative_path))
end

#read_sorbet_configObject

Read the contents of ‘sorbet/config` in this context directory : -> String



119
120
121
# File 'lib/spoom/context/sorbet.rb', line 119

def read_sorbet_config
  read(Spoom::Sorbet::CONFIG_PATH)
end

#sorbet_configObject

: -> Spoom::Sorbet::Config



113
114
115
# File 'lib/spoom/context/sorbet.rb', line 113

def sorbet_config
  Spoom::Sorbet::Config.parse_string(read_sorbet_config)
end

#sorbet_intro_commitObject

Get the commit introducing the ‘sorbet/config` file : -> Spoom::Git::Commit?



137
138
139
140
141
142
143
144
145
# File 'lib/spoom/context/sorbet.rb', line 137

def sorbet_intro_commit
  res = git_log("--diff-filter=A --format='%h %at' -1 -- sorbet/config")
  return unless res.status

  out = res.out.strip
  return if out.empty?

  Spoom::Git::Commit.parse_line(out)
end

#sorbet_removal_commitObject

Get the commit removing the ‘sorbet/config` file : -> Spoom::Git::Commit?



149
150
151
152
153
154
155
156
157
# File 'lib/spoom/context/sorbet.rb', line 149

def sorbet_removal_commit
  res = git_log("--diff-filter=D --format='%h %at' -1 -- sorbet/config")
  return unless res.status

  out = res.out.strip
  return if out.empty?

  Spoom::Git::Commit.parse_line(out)
end

#srb(*arg, sorbet_bin: nil, capture_err: true) ⇒ Object

Run ‘bundle exec srb` in this context directory : (*String arg, ?sorbet_bin: String?, ?capture_err: bool) -> ExecResult



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/spoom/context/sorbet.rb', line 11

def srb(*arg, sorbet_bin: nil, capture_err: true)
  res = if sorbet_bin
    exec("#{sorbet_bin} #{arg.join(" ")}", capture_err: capture_err)
  else
    bundle_exec("srb #{arg.join(" ")}", capture_err: capture_err)
  end

  case res.exit_code
  when Spoom::Sorbet::KILLED_CODE
    raise Spoom::Sorbet::Error::Killed.new("Sorbet was killed.", res)
  when Spoom::Sorbet::SEGFAULT_CODE
    raise Spoom::Sorbet::Error::Segfault.new("Sorbet segfaulted.", res)
  end

  res
end

#srb_files(with_config: nil, include_rbis: true) ⇒ Object

List all files typechecked by Sorbet from its ‘config` : (?with_config: Spoom::Sorbet::Config?, ?include_rbis: bool) -> Array



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/spoom/context/sorbet.rb', line 60

def srb_files(with_config: nil, include_rbis: true)
  config = with_config || sorbet_config

  allowed_extensions = config.allowed_extensions
  allowed_extensions = Spoom::Sorbet::Config::DEFAULT_ALLOWED_EXTENSIONS if allowed_extensions.empty?
  allowed_extensions -= [".rbi"] unless include_rbis

  excluded_patterns = config.ignore.map do |string|
    # We need to simulate the behavior of Sorbet's `--ignore` flag.
    #
    # From Sorbet docs on `--ignore`:
    # > Ignores input files that contain the given string in their paths (relative to the input path passed to
    # > Sorbet). Strings beginning with / match against the prefix of these relative paths; others are substring
    # > matches. Matches must be against whole folder and file names, so `foo` matches `/foo/bar.rb` and
    # > `/bar/foo/baz.rb` but not `/foo.rb` or `/foo2/bar.rb`.
    string = if string.start_with?("/")
      # Strings beginning with / match against the prefix of these relative paths
      File.join(absolute_path, string)
    else
      # Others are substring matches
      File.join(absolute_path, "**", string)
    end
    # Matches must be against whole folder and file names
    "#{string.delete_suffix("/")}{,/**}"
  end

  collector = FileCollector.new(allow_extensions: allowed_extensions, exclude_patterns: excluded_patterns)
  collector.visit_paths(config.paths.map { |path| absolute_path_to(path) })
  collector.files.map { |file| file.delete_prefix("#{absolute_path}/") }.sort
end

#srb_files_with_strictness(strictness, with_config: nil, include_rbis: true) ⇒ Object

List all files typechecked by Sorbet from its ‘config` that matches `strictness` : (String strictness, ?with_config: Spoom::Sorbet::Config?, ?include_rbis: bool) -> Array



93
94
95
96
# File 'lib/spoom/context/sorbet.rb', line 93

def srb_files_with_strictness(strictness, with_config: nil, include_rbis: true)
  srb_files(with_config: with_config, include_rbis: include_rbis)
    .select { |file| read_file_strictness(file) == strictness }
end

#srb_metrics(*arg, sorbet_bin: nil, capture_err: true) ⇒ Object

: (*String arg, ?sorbet_bin: String?, ?capture_err: bool) -> Hash[String, Integer]?



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/spoom/context/sorbet.rb', line 35

def srb_metrics(*arg, sorbet_bin: nil, capture_err: true)
  metrics_file = "metrics.tmp"

  T.unsafe(self).srb_tc(
    "--metrics-file",
    metrics_file,
    *arg,
    sorbet_bin: sorbet_bin,
    capture_err: capture_err,
  )

  metrics_path = absolute_path_to(metrics_file)

  begin
    metrics = Spoom::Sorbet::Metrics::MetricsFileParser.parse_file(metrics_path)
  rescue Errno::ENOENT, Errno::EACCES
    return
  end

  remove!(metrics_file)
  metrics
end

#srb_tc(*arg, sorbet_bin: nil, capture_err: true) ⇒ Object

: (*String arg, ?sorbet_bin: String?, ?capture_err: bool) -> ExecResult



29
30
31
32
# File 'lib/spoom/context/sorbet.rb', line 29

def srb_tc(*arg, sorbet_bin: nil, capture_err: true)
  arg.prepend("tc") unless sorbet_bin
  T.unsafe(self).srb(*arg, sorbet_bin: sorbet_bin, capture_err: capture_err)
end

#srb_version(*arg, sorbet_bin: nil, capture_err: true) ⇒ Object

: (*String arg, ?sorbet_bin: String?, ?capture_err: bool) -> String?



99
100
101
102
103
104
# File 'lib/spoom/context/sorbet.rb', line 99

def srb_version(*arg, sorbet_bin: nil, capture_err: true)
  res = T.unsafe(self).srb_tc("--no-config", "--version", *arg, sorbet_bin: sorbet_bin, capture_err: capture_err)
  return unless res.status

  res.out.split(" ")[2]
end

#write_sorbet_config!(contents, append: false) ⇒ Object

Set the ‘contents` of `sorbet/config` in this context directory : (String contents, ?append: bool) -> void



125
126
127
# File 'lib/spoom/context/sorbet.rb', line 125

def write_sorbet_config!(contents, append: false)
  write!(Spoom::Sorbet::CONFIG_PATH, contents, append: append)
end