-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRakefile
More file actions
172 lines (135 loc) · 4.85 KB
/
Rakefile
File metadata and controls
172 lines (135 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# frozen_string_literal: true
require "pathname"
require "securerandom"
require "shellwords"
require "minitest/test_task"
require "rake/clean"
require "rubocop/rake_task"
tapioca = "sorbet/tapioca"
examples = "examples"
ignore_file = ".ignore"
FILES_ENV = "FORMAT_FILE"
CLEAN.push(*%w[.idea/ .ruby-lsp/ .yardoc/ doc/], *FileList["*.gem"], ignore_file)
CLOBBER.push(*%w[sorbet/rbi/annotations/ sorbet/rbi/gems/], tapioca)
multitask(:default) do
sh(*%w[rake --tasks])
end
desc("Preview docs; use `PORT=<PORT>` to change the port")
multitask(:"docs:preview") do
sh(*%w[yard server --reload --quiet --bind [::] --port], ENV.fetch("PORT", "8808"))
end
desc("Run test suites; use `TEST=path/to/test.rb` to run a specific test file")
multitask(:test) do
rb =
FileList[ENV.fetch("TEST", "./test/**/*_test.rb")]
.map { "require_relative(#{_1.dump});" }
.join
ruby(*%w[-w -e], rb, verbose: false) { fail unless _1 }
end
xargs = %w[xargs --no-run-if-empty --null --max-procs=0 --max-args=300 --]
ruby_opt = {"RUBYOPT" => [ENV["RUBYOPT"], "--encoding=UTF-8"].compact.join(" ")}
filtered = ->(ext, dirs) do
if ENV.key?(FILES_ENV)
%w[sed -E -n -e] << "/\\.#{ext}$/p" << "--" << ENV.fetch(FILES_ENV)
else
(%w[find] + dirs + %w[-type f -and -name]) << "*.#{ext}" << "-print0"
end
end
desc("Lint `*.rb(i)`")
multitask(:"lint:rubocop") do
find = %w[find ./lib ./test ./rbi ./examples -type f -and ( -name *.rb -or -name *.rbi ) -print0]
rubocop = %w[rubocop]
rubocop += %w[--format github] if ENV.key?("CI")
# some lines cannot be shortened
rubocop += %w[--except Lint/RedundantCopDisableDirective,Layout/LineLength]
lint = xargs + rubocop
sh("#{find.shelljoin} | #{lint.shelljoin}")
end
norm_lines = %w[tr -- \n \0].shelljoin
desc("Format `*.rb`")
multitask(:"format:rb") do
# while `syntax_tree` is much faster than `rubocop`, `rubocop` is the only formatter with full syntax support
files = filtered["rb", %w[./lib ./test ./examples]]
fmt = xargs + %w[rubocop --fail-level F --autocorrect --format simple --]
sh("#{files.shelljoin} | #{norm_lines} | #{fmt.shelljoin}")
end
desc("Format `*.rbi`")
multitask(:"format:rbi") do
files = filtered["rbi", %w[./rbi]]
fmt = xargs + %w[stree write --]
sh(ruby_opt, "#{files.shelljoin} | #{norm_lines} | #{fmt.shelljoin}")
end
desc("Format `*.rbs`")
multitask(:"format:rbs") do
files = filtered["rbs", %w[./sig]]
inplace = /darwin|bsd/ =~ RUBY_PLATFORM ? ["-i", ""] : %w[-i]
uuid = SecureRandom.uuid
# `syntax_tree` has trouble with `rbs`'s class & module aliases
sed_bin = /darwin/ =~ RUBY_PLATFORM ? "/usr/bin/sed" : "sed"
sed = xargs + [sed_bin, "-E", *inplace, "-e"]
# annotate unprocessable aliases with a unique comment
pre = sed + ["s/(class|module) ([^ ]+) = (.+$)/# \\1 #{uuid}\\n\\2: \\3/", "--"]
fmt = xargs + %w[stree write --plugin=rbs --]
# remove the unique comment and unprocessable aliases to type aliases
subst = <<~SED
s/# (class|module) #{uuid}/\\1/
t l1
b
: l1
N
s/\\n *([^:]+): (.+)$/ \\1 = \\2/
SED
# for each line:
# 1. try transform the unique comment into `class | module`, if successful, branch to label `l1`.
# 2. at label `l1`, join previously annotated line with `class | module` information.
pst = sed + [subst, "--"]
success = false
# transform class aliases to type aliases, which syntax tree has no trouble with
sh("#{files.shelljoin} | #{norm_lines} | #{pre.shelljoin}")
# run syntax tree to format `*.rbs` files
sh(ruby_opt, "#{files.shelljoin} | #{norm_lines} | #{fmt.shelljoin}") do
success = _1
end
# transform type aliases back to class aliases
sh("#{files.shelljoin} | #{norm_lines} | #{pst.shelljoin}")
# always run post-processing to remove comment marker
fail unless success
end
desc("Format everything")
multitask(format: [:"format:rb", :"format:rbi", :"format:rbs"])
desc("Typecheck `*.rbs`")
multitask(:"typecheck:steep") do
sh(*%w[steep check])
end
directory(examples)
desc("Typecheck `*.rbi`")
multitask("typecheck:sorbet": examples) do
sh(*%w[srb typecheck --dir], examples)
end
directory(tapioca) do
sh(*%w[tapioca init])
end
desc("Typecheck everything")
multitask(typecheck: [:"typecheck:steep", :"typecheck:sorbet"])
desc("Lint and typecheck")
multitask(lint: [:"lint:rubocop", :typecheck])
desc("Build yard docs")
multitask(:"build:docs") do
sh(*%w[yard])
end
desc("Build ruby gem")
multitask(:"build:gem") do
# optimizing for grepping through the gem bundle: many tools honour `.ignore` files, including VSCode
#
# both `rbi` and `sig` directories are navigable by their respective tool chains and therefore can be ignored by tools such as `rg`
Pathname(ignore_file).write(<<~GLOB)
rbi/*
sig/*
GLOB
sh(*%w[gem build -- docker_engine_ruby.gemspec])
rm_rf(ignore_file)
end
desc("Release ruby gem")
multitask(release: [:"build:gem"]) do
sh(*%w[gem push], *FileList["*.gem"])
end