1# Ruby
2
3Ruby support is available through the [Ruby extension](https://github.com/zed-extensions/ruby).
4
5- Tree-sitters:
6 - [tree-sitter-ruby](https://github.com/tree-sitter/tree-sitter-ruby)
7 - [tree-sitter-embedded-template](https://github.com/tree-sitter/tree-sitter-embedded-template)
8- Language Servers:
9 - [ruby-lsp](https://github.com/Shopify/ruby-lsp)
10 - [solargraph](https://github.com/castwide/solargraph)
11 - [rubocop](https://github.com/rubocop/rubocop)
12 - [Herb](https://herb-tools.dev)
13- Debug Adapter: [`rdbg`](https://github.com/ruby/debug)
14
15The Ruby extension also provides support for ERB files.
16
17## Language Servers
18
19There are multiple language servers available for Ruby. Zed supports the two following:
20
21- [solargraph](https://github.com/castwide/solargraph)
22- [ruby-lsp](https://github.com/Shopify/ruby-lsp)
23
24They both have an overlapping feature set of autocomplete, diagnostics, code actions, etc. and it's up to you to decide which one you want to use. Note that you can't use both at the same time.
25
26In addition to these two language servers, Zed also supports:
27
28- [rubocop](https://github.com/rubocop/rubocop) which is a static code analyzer and linter for Ruby. Under the hood, it's also used by Zed as a language server, but its functionality is complimentary to that of solargraph and ruby-lsp.
29- [sorbet](https://sorbet.org/) which is a static type checker for Ruby with a custom gradual type system.
30- [steep](https://github.com/soutaro/steep) which is a static type checker for Ruby that leverages Ruby Signature (RBS).
31- [Herb](https://herb-tools.dev) which is a language server for ERB files.
32
33When configuring a language server, it helps to open the LSP Logs window using the 'dev: Open Language Server Logs' command. You can then choose the corresponding language instance to see any logged information.
34
35## Configuring a language server
36
37The [Ruby extension](https://github.com/zed-extensions/ruby) offers both `solargraph` and `ruby-lsp` language server support.
38
39### Language Server Activation
40
41For all supported Ruby language servers (`solargraph`, `ruby-lsp`, `rubocop`, `sorbet`, and `steep`), the Ruby extension follows this activation sequence:
42
431. If the language server is found in your project's `Gemfile`, it will be used through `bundle exec`.
442. If not found in the `Gemfile`, the Ruby extension will look for the executable in your system `PATH`.
453. If the language server is not found in either location, the Ruby extension will automatically install it as a global gem (note: this will not install to your current Ruby gemset).
46
47You can skip step 1 and force using the system executable by setting `use_bundler` to `false` in your settings:
48
49```json [settings]
50{
51 "lsp": {
52 "<SERVER_NAME>": {
53 "settings": {
54 "use_bundler": false
55 }
56 }
57 }
58}
59```
60
61### Using `solargraph`
62
63`solargraph` is enabled by default in the Ruby extension.
64
65### Using `ruby-lsp`
66
67To switch to `ruby-lsp`, add the following to your `settings.json`:
68
69```json [settings]
70{
71 "languages": {
72 "Ruby": {
73 "language_servers": ["ruby-lsp", "!solargraph", "!rubocop", "..."]
74 },
75 // Enable herb and ruby-lsp for *.html.erb files
76 "HTML+ERB": {
77 "language_servers": ["herb", "ruby-lsp", "..."]
78 },
79 // Enable ruby-lsp for *.js.erb files
80 "JS+ERB": {
81 "language_servers": ["ruby-lsp", "..."]
82 },
83 // Enable ruby-lsp for *.yaml.erb files
84 "YAML+ERB": {
85 "language_servers": ["ruby-lsp", "..."]
86 }
87 }
88}
89```
90
91That disables `solargraph` and `rubocop` and enables `ruby-lsp`.
92
93### Using `rubocop`
94
95The Ruby extension also provides support for `rubocop` language server for offense detection and autocorrection.
96
97To enable it, add the following to your `settings.json`:
98
99```json [settings]
100{
101 "languages": {
102 "Ruby": {
103 "language_servers": ["ruby-lsp", "rubocop", "!solargraph", "..."]
104 }
105 }
106}
107```
108
109Or, conversely, you can disable `ruby-lsp` and enable `solargraph` and `rubocop` by adding the following to your `settings.json`:
110
111```json [settings]
112{
113 "languages": {
114 "Ruby": {
115 "language_servers": ["solargraph", "rubocop", "!ruby-lsp", "..."]
116 }
117 }
118}
119```
120
121## Setting up `solargraph`
122
123Solargraph has formatting and diagnostics disabled by default. We can tell Zed to enable them by adding the following to your `settings.json`:
124
125```json [settings]
126{
127 "lsp": {
128 "solargraph": {
129 "initialization_options": {
130 "diagnostics": true,
131 "formatting": true
132 }
133 }
134 }
135}
136```
137
138### Configuration
139
140Solargraph reads its configuration from a file called `.solargraph.yml` in the root of your project. For more information about this file, see the [Solargraph configuration documentation](https://solargraph.org/guides/configuration).
141
142## Setting up `ruby-lsp`
143
144You can pass Ruby LSP configuration to `initialization_options`, e.g.
145
146```json [settings]
147{
148 "languages": {
149 "Ruby": {
150 "language_servers": ["ruby-lsp", "!solargraph", "..."]
151 }
152 },
153 "lsp": {
154 "ruby-lsp": {
155 "initialization_options": {
156 "enabledFeatures": {
157 // "someFeature": false
158 }
159 }
160 }
161 }
162}
163```
164
165LSP `settings` and `initialization_options` can also be project-specific. For example to use [standardrb/standard](https://github.com/standardrb/standard) as a formatter and linter for a particular project, add this to a `.zed/settings.json` inside your project repo:
166
167```json [settings]
168{
169 "lsp": {
170 "ruby-lsp": {
171 "initialization_options": {
172 "formatter": "standard",
173 "linters": ["standard"]
174 }
175 }
176 }
177}
178```
179
180## Setting up `rubocop` LSP
181
182Rubocop has unsafe autocorrection disabled by default. We can tell Zed to enable it by adding the following to your `settings.json`:
183
184```json [settings]
185{
186 "languages": {
187 "Ruby": {
188 // Use ruby-lsp as the primary language server and rubocop as the secondary.
189 "language_servers": ["ruby-lsp", "rubocop", "!solargraph", "..."]
190 }
191 },
192 "lsp": {
193 "rubocop": {
194 "initialization_options": {
195 "safeAutocorrect": false
196 }
197 },
198 "ruby-lsp": {
199 "initialization_options": {
200 "enabledFeatures": {
201 "diagnostics": false
202 }
203 }
204 }
205 }
206}
207```
208
209## Setting up Sorbet
210
211[Sorbet](https://sorbet.org/) is a popular static type checker for Ruby that includes a language server.
212
213To enable Sorbet, add `\"sorbet\"` to the `language_servers` list for Ruby in your `settings.json`. You may want to disable other language servers if Sorbet is intended to be your primary LSP, or if you plan to use it alongside another LSP for specific features like type checking.
214
215```json [settings]
216{
217 "languages": {
218 "Ruby": {
219 "language_servers": [
220 "ruby-lsp",
221 "sorbet",
222 "!rubocop",
223 "!solargraph",
224 "..."
225 ]
226 }
227 }
228}
229```
230
231For all aspects of installing Sorbet, setting it up in your project, and configuring its behavior, please refer to the [official Sorbet documentation](https://sorbet.org/docs/overview).
232
233## Setting up Steep
234
235[Steep](https://github.com/soutaro/steep) is a static type checker for Ruby that uses RBS files to define types.
236
237To enable Steep, add `\"steep\"` to the `language_servers` list for Ruby in your `settings.json`. You may need to adjust the order or disable other LSPs depending on your desired setup.
238
239```json [settings]
240{
241 "languages": {
242 "Ruby": {
243 "language_servers": [
244 "ruby-lsp",
245 "steep",
246 "!solargraph",
247 "!rubocop",
248 "..."
249 ]
250 }
251 }
252}
253```
254
255## Setting up Herb
256
257`Herb` is enabled by default for the `HTML+ERB` language.
258
259## Using the Tailwind CSS Language Server with Ruby
260
261It's possible to use the [Tailwind CSS Language Server](https://github.com/tailwindlabs/tailwindcss-intellisense/tree/HEAD/packages/tailwindcss-language-server#readme) in Ruby and ERB files.
262
263In order to do that, you need to configure the language server so that it knows about where to look for CSS classes in Ruby/ERB files by adding the following to your `settings.json`:
264
265```json [settings]
266{
267 "languages": {
268 "Ruby": {
269 "language_servers": ["tailwindcss-language-server", "..."]
270 }
271 },
272 "lsp": {
273 "tailwindcss-language-server": {
274 "settings": {
275 "experimental": {
276 "classRegex": ["\\bclass:\\s*['\"]([^'\"]*)['\"]"]
277 }
278 }
279 }
280 }
281}
282```
283
284With these settings you will get completions for Tailwind CSS classes in HTML attributes inside ERB files and inside Ruby/ERB strings that are coming after a `class:` key. Examples:
285
286```rb
287# Ruby file:
288def method
289 div(class: "pl-2 <completion here>") do
290 p(class: "mt-2 <completion here>") { "Hello World" }
291 end
292end
293
294# ERB file:
295<%= link_to "Hello", "/hello", class: "pl-2 <completion here>" %>
296<a href="/hello" class="pl-2 <completion here>">Hello</a>
297```
298
299## Running tests
300
301To run tests in your Ruby project, you can set up custom tasks in your local `.zed/tasks.json` configuration file. These tasks can be defined to work with different test frameworks like Minitest, RSpec, quickdraw, and tldr. Below are some examples of how to set up these tasks to run your tests from within your editor.
302
303### Minitest with Rails
304
305```json [tasks]
306[
307 {
308 "label": "test $ZED_RELATIVE_FILE -n /$ZED_CUSTOM_RUBY_TEST_NAME/",
309 "command": "bin/rails",
310 "args": [
311 "test",
312 "$ZED_RELATIVE_FILE",
313 "-n",
314 "\"$ZED_CUSTOM_RUBY_TEST_NAME\""
315 ],
316 "cwd": "$ZED_WORKTREE_ROOT",
317 "tags": ["ruby-test"]
318 }
319]
320```
321
322### Minitest
323
324Plain minitest does not support running tests by line number, only by name, so we need to use `$ZED_CUSTOM_RUBY_TEST_NAME` instead:
325
326```json [tasks]
327[
328 {
329 "label": "-Itest $ZED_RELATIVE_FILE -n /$ZED_CUSTOM_RUBY_TEST_NAME/",
330 "command": "bundle",
331 "args": [
332 "exec",
333 "ruby",
334 "-Itest",
335 "$ZED_RELATIVE_FILE",
336 "-n",
337 "\"$ZED_CUSTOM_RUBY_TEST_NAME\""
338 ],
339 "cwd": "$ZED_WORKTREE_ROOT",
340 "tags": ["ruby-test"]
341 }
342]
343```
344
345### RSpec
346
347```json [tasks]
348[
349 {
350 "label": "test $ZED_RELATIVE_FILE:$ZED_ROW",
351 "command": "bundle",
352 "args": ["exec", "rspec", "\"$ZED_RELATIVE_FILE:$ZED_ROW\""],
353 "cwd": "$ZED_WORKTREE_ROOT",
354 "tags": ["ruby-test"]
355 }
356]
357```
358
359Similar task syntax can be used for other test frameworks such as `quickdraw` or `tldr`.
360
361## Debugging
362
363The Ruby extension provides a debug adapter for debugging Ruby code. Zed's name for the adapter (in the UI and `debug.json`) is `rdbg`, and under the hood, it uses the [`debug`](https://github.com/ruby/debug) gem. The extension uses the [same activation logic](#language-server-activation) as the language servers.
364
365### Examples
366
367#### Debug a Ruby script
368
369```json [debug]
370[
371 {
372 "label": "Debug current file",
373 "adapter": "rdbg",
374 "request": "launch",
375 "script": "$ZED_FILE",
376 "cwd": "$ZED_WORKTREE_ROOT"
377 }
378]
379```
380
381#### Debug Rails server
382
383```json [debug]
384[
385 {
386 "label": "Debug Rails server",
387 "adapter": "rdbg",
388 "request": "launch",
389 "command": "./bin/rails",
390 "args": ["server"],
391 "cwd": "$ZED_WORKTREE_ROOT",
392 "env": {
393 "RUBY_DEBUG_OPEN": "true"
394 }
395 }
396]
397```
398
399## Formatters
400
401### `erb-formatter`
402
403To format ERB templates, you can use the `erb-formatter` formatter. This formatter uses the [`erb-formatter`](https://rubygems.org/gems/erb-formatter) gem to format ERB templates.
404
405```json [settings]
406{
407 "HTML+ERB": {
408 "formatter": {
409 "external": {
410 "command": "erb-formatter",
411 "arguments": ["--stdin-filename", "{buffer_path}"]
412 }
413 }
414 }
415}
416```