|
| 1 | +--- |
| 2 | +layout: default |
| 3 | +title: Composed Ruby LSP bundle |
| 4 | +nav_order: 40 |
| 5 | +parent: Ruby LSP |
| 6 | +--- |
| 7 | + |
| 8 | +# Composed Ruby LSP bundle |
| 9 | + |
| 10 | +In language ecosystems other than Ruby, it is not super common to have to add editor tooling as part of your project |
| 11 | +dependencies. Usually, a language server is an executable that gets downloaded and then run independently from your |
| 12 | +projects. |
| 13 | + |
| 14 | +In the Ruby ecosystem, there are a few blockers to fully adopting this approach: |
| 15 | + |
| 16 | +1. Not writing the language server in Ruby would make it challenging to integrate seamlessly with existing tools used by |
| 17 | +the community that are already written in Ruby, like test frameworks, linters, formatters and so on |
| 18 | +2. Discovering project dependencies automatically allows the language server to detect which files on disk must be read |
| 19 | +and indexed, so that we can extract declarations from gems without requiring any configuration from the user. This means |
| 20 | +that we need to integrate directly with Bundler |
| 21 | +3. Bundler only allows requiring gems that are set up as part of the `$LOAD_PATH`. If the Ruby LSP executable was running |
| 22 | +independently from a global installation, then the Ruby process would only be able to require the Ruby LSP's own |
| 23 | +dependencies, but it would not be able to require any gems used by the project being worked on. Not being able to require |
| 24 | +the project's dependencies limits integrations that the language server can automatically make with linters, formatters, |
| 25 | +test frameworks and so on |
| 26 | + |
| 27 | +To overcome these limitations, while at the same time not requiring users to add `ruby-lsp` as a dependency of their projects, |
| 28 | +the Ruby LSP uses a composed bundle strategy. The flow of execution is as follows: |
| 29 | + |
| 30 | +1. The executable is run as `ruby-lsp` without `bundle exec` to indicate that the composed bundle must first be configured |
| 31 | +2. The executable sets up a composed bundle under `your_project/.ruby-lsp`. The generated Gemfile includes the `ruby-lsp` gem |
| 32 | +and everything in the project's Gemfile as well. It may also include `debug` and `ruby-lsp-rails` |
| 33 | +3. After the composed bundle is fully set up, then the original `ruby-lsp` Ruby process is fully replaced by |
| 34 | +`BUNDLE_GEMFILE=.ruby-lsp/Gemfile bundle exec ruby-lsp`, thus launching the real language server with access to the project's |
| 35 | +dependencies, but without requiring adding the gem to the project's own Gemfile |
| 36 | + |
| 37 | +In addition to performing this setup, the composed bundle logic will also `bundle install` and attempt to auto-update |
| 38 | +the `ruby-lsp` language server gem to ensure fast distribution of bug fixes and new features. |
| 39 | + |
| 40 | +{: .note } |
| 41 | +Setting up the composed bundle requires several integrations with Bundler and there are many edge cases to consider, |
| 42 | +like how to handle configurations or installing private dependencies. If you encounter a problem with the composed |
| 43 | +bundle setup, please let us know by [reporting an issue](https://github.com/Shopify/ruby-lsp/issues/new). |
0 commit comments