ruby.md

  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- Debug Adapter: [`rdbg`](https://github.com/ruby/debug)
 13
 14The Ruby extension also provides support for ERB files.
 15
 16## Language Servers
 17
 18There are multiple language servers available for Ruby. Zed supports the two following:
 19
 20- [solargraph](https://github.com/castwide/solargraph)
 21- [ruby-lsp](https://github.com/Shopify/ruby-lsp)
 22
 23They 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.
 24
 25In addition to these two language servers, Zed also supports:
 26
 27- [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.
 28- [sorbet](https://sorbet.org/) which is a static type checker for Ruby with a custom gradual type system.
 29- [steep](https://github.com/soutaro/steep) which is a static type checker for Ruby that leverages Ruby Signature (RBS).
 30
 31When 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.
 32
 33## Configuring a language server
 34
 35The [Ruby extension](https://github.com/zed-extensions/ruby) offers both `solargraph` and `ruby-lsp` language server support.
 36
 37### Language Server Activation
 38
 39For all supported Ruby language servers (`solargraph`, `ruby-lsp`, `rubocop`, `sorbet`, and `steep`), the Ruby extension follows this activation sequence:
 40
 411. If the language server is found in your project's `Gemfile`, it will be used through `bundle exec`.
 422. If not found in the `Gemfile`, the Ruby extension will look for the executable in your system `PATH`.
 433. 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).
 44
 45You can skip step 1 and force using the system executable by setting `use_bundler` to `false` in your settings:
 46
 47```json
 48{
 49  "lsp": {
 50    "<SERVER_NAME>": {
 51      "settings": {
 52        "use_bundler": false
 53      }
 54    }
 55  }
 56}
 57```
 58
 59### Using `solargraph`
 60
 61`solargraph` is enabled by default in the Ruby extension.
 62
 63### Using `ruby-lsp`
 64
 65To switch to `ruby-lsp`, add the following to your `settings.json`:
 66
 67```json
 68{
 69  "languages": {
 70    "Ruby": {
 71      "language_servers": ["ruby-lsp", "!solargraph", "!rubocop", "..."]
 72    }
 73  }
 74}
 75```
 76
 77That disables `solargraph` and `rubocop` and enables `ruby-lsp`.
 78
 79### Using `rubocop`
 80
 81The Ruby extension also provides support for `rubocop` language server for offense detection and autocorrection.
 82
 83To enable it, add the following to your `settings.json`:
 84
 85```json
 86{
 87  "languages": {
 88    "Ruby": {
 89      "language_servers": ["ruby-lsp", "rubocop", "!solargraph", "..."]
 90    }
 91  }
 92}
 93```
 94
 95Or, conversely, you can disable `ruby-lsp` and enable `solargraph` and `rubocop` by adding the following to your `settings.json`:
 96
 97```json
 98{
 99  "languages": {
100    "Ruby": {
101      "language_servers": ["solargraph", "rubocop", "!ruby-lsp", "..."]
102    }
103  }
104}
105```
106
107## Setting up `solargraph`
108
109Solargraph has formatting and diagnostics disabled by default. We can tell Zed to enable them by adding the following to your `settings.json`:
110
111```json
112{
113  "lsp": {
114    "solargraph": {
115      "initialization_options": {
116        "diagnostics": true,
117        "formatting": true
118      }
119    }
120  }
121}
122```
123
124### Configuration
125
126Solargraph 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).
127
128## Setting up `ruby-lsp`
129
130Ruby LSP uses pull-based diagnostics which Zed doesn't support yet. We can tell Zed to disable it by adding the following to your `settings.json`:
131
132```json
133{
134  "languages": {
135    "Ruby": {
136      "language_servers": ["ruby-lsp", "!solargraph", "..."]
137    }
138  },
139  "lsp": {
140    "ruby-lsp": {
141      "initialization_options": {
142        "enabledFeatures": {
143          // This disables diagnostics
144          "diagnostics": false
145        }
146      }
147    }
148  }
149}
150```
151
152LSP `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:
153
154```json
155{
156  "lsp": {
157    "ruby-lsp": {
158      "initialization_options": {
159        "formatter": "standard",
160        "linters": ["standard"]
161      }
162    }
163  }
164}
165```
166
167## Setting up `rubocop` LSP
168
169Rubocop has unsafe autocorrection disabled by default. We can tell Zed to enable it by adding the following to your `settings.json`:
170
171```json
172{
173  "languages": {
174    "Ruby": {
175      // Use ruby-lsp as the primary language server and rubocop as the secondary.
176      "language_servers": ["ruby-lsp", "rubocop", "!solargraph", "..."]
177    }
178  },
179  "lsp": {
180    "rubocop": {
181      "initialization_options": {
182        "safeAutocorrect": false
183      }
184    },
185    "ruby-lsp": {
186      "initialization_options": {
187        "enabledFeatures": {
188          "diagnostics": false
189        }
190      }
191    }
192  }
193}
194```
195
196## Setting up Sorbet
197
198[Sorbet](https://sorbet.org/) is a popular static type checker for Ruby that includes a language server.
199
200To 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.
201
202```json
203{
204  "languages": {
205    "Ruby": {
206      "language_servers": [
207        "ruby-lsp",
208        "sorbet",
209        "!rubocop",
210        "!solargraph",
211        "..."
212      ]
213    }
214  }
215}
216```
217
218For 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).
219
220## Setting up Steep
221
222[Steep](https://github.com/soutaro/steep) is a static type checker for Ruby that uses RBS files to define types.
223
224To 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.
225
226```json
227{
228  "languages": {
229    "Ruby": {
230      "language_servers": [
231        "ruby-lsp",
232        "steep",
233        "!solargraph",
234        "!rubocop",
235        "..."
236      ]
237    }
238  }
239}
240```
241
242## Using the Tailwind CSS Language Server with Ruby
243
244It'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.
245
246In 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`:
247
248```json
249{
250  "languages": {
251    "Ruby": {
252      "language_servers": ["tailwindcss-language-server", "..."]
253    }
254  },
255  "lsp": {
256    "tailwindcss-language-server": {
257      "settings": {
258        "includeLanguages": {
259          "html/erb": "html",
260          "ruby": "html"
261        },
262        "experimental": {
263          "classRegex": ["\\bclass:\\s*['\"]([^'\"]*)['\"]"]
264        }
265      }
266    }
267  }
268}
269```
270
271With 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:
272
273```rb
274# Ruby file:
275def method
276  div(class: "pl-2 <completion here>") do
277    p(class: "mt-2 <completion here>") { "Hello World" }
278  end
279end
280
281# ERB file:
282<%= link_to "Hello", "/hello", class: "pl-2 <completion here>" %>
283<a href="/hello" class="pl-2 <completion here>">Hello</a>
284```
285
286## Running tests
287
288To 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.
289
290### Minitest with Rails
291
292```json
293[
294  {
295    "label": "test $ZED_RELATIVE_FILE -n /$ZED_CUSTOM_RUBY_TEST_NAME/",
296    "command": "bin/rails",
297    "args": [
298      "test",
299      "$ZED_RELATIVE_FILE",
300      "-n",
301      "\"$ZED_CUSTOM_RUBY_TEST_NAME\""
302    ],
303    "tags": ["ruby-test"]
304  }
305]
306```
307
308### Minitest
309
310Plain minitest does not support running tests by line number, only by name, so we need to use `$ZED_CUSTOM_RUBY_TEST_NAME` instead:
311
312```json
313[
314  {
315    "label": "-Itest $ZED_RELATIVE_FILE -n /$ZED_CUSTOM_RUBY_TEST_NAME/",
316    "command": "bundle",
317    "args": [
318      "exec",
319      "ruby",
320      "-Itest",
321      "$ZED_RELATIVE_FILE",
322      "-n",
323      "\"$ZED_CUSTOM_RUBY_TEST_NAME\""
324    ],
325    "tags": ["ruby-test"]
326  }
327]
328```
329
330### RSpec
331
332```json
333[
334  {
335    "label": "test $ZED_RELATIVE_FILE:$ZED_ROW",
336    "command": "bundle",
337    "args": ["exec", "rspec", "\"$ZED_RELATIVE_FILE:$ZED_ROW\""],
338    "tags": ["ruby-test"]
339  }
340]
341```
342
343Similar task syntax can be used for other test frameworks such as `quickdraw` or `tldr`.
344
345## Debugging
346
347The 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.
348
349### Examples
350
351#### Debug a Ruby script
352
353```json
354[
355  {
356    "label": "Debug current file",
357    "adapter": "rdbg",
358    "request": "launch",
359    "script": "$ZED_FILE",
360    "cwd": "$ZED_WORKTREE_ROOT"
361  }
362]
363```
364
365#### Debug Rails server
366
367```json
368[
369  {
370    "label": "Debug Rails server",
371    "adapter": "rdbg",
372    "request": "launch",
373    "command": "$ZED_WORKTREE_ROOT/bin/rails",
374    "args": ["server"],
375    "cwd": "$ZED_WORKTREE_ROOT",
376    "env": {
377      "RUBY_DEBUG_OPEN": "true"
378    }
379  }
380]
381```
382
383## Formatters
384
385### `erb-formatter`
386
387To 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.
388
389```jsonc
390{
391  "HTML/ERB": {
392    "formatter": {
393      "external": {
394        "command": "erb-formatter",
395        "arguments": ["--stdin-filename", "{buffer_path}"],
396      },
397    },
398  },
399}
400```