ruby-lspを少し便利にするruby-lsp-addons

この記事は

私は、株式会社エニグモでチームのマネージャをしている後藤です。 マネージャ業務の傍ら開発作業を行うこともあります。

この記事はEnigmo Advent Calendar 2024の10日目の記事です。

この記事では多くのRubyを使っている人が、使っているであろうruby-lspを少し便利にする ruby-lsp-addons について紹介しながら、VSCode でどのように活用できるのかについて紹介したいと思います。

ruby-lspとは

ruby-lsp とは、Ruby言語向けに Microsoft が定義している、Language Server Protocolを実装したサーバになります。

Language Server Protocol(以下 LSP) は、プログラム中に定義されたクラス名、関数名、変数名などを取得できるAPIとデータ型を定義したものになります。プログラム中のデータを取得するAPIを定義しておくことで、エディタから対象言語に対応した LSP サーバーを通して 関数定義情報を表示、関数/変数の定義箇所へのジャンプ、関数名/変数名を使った入力補間ができるようになります。

LSP の登場以前は universal-ctags + GNU Global などを用いて同様の機能を実現することが多かったように思いますが、VSCode の登場と合わせて LSP の提案と普及が進みました。その結果、多くのエディタで LSP がサポートされるようになり、最近は補間や関数ジャンプのための機能が LSP に集約されつつあるように思います。

Visual Studio Code(VSCode) の場合は、 ruby-lsp プラグインVSCode に追加することで rubyソース編集次に ruby-lsp を使った関数ジャンプや入力補間が使えるようになります。

ruby-lsp-addons

ruby-lsp ですが、当然ながら ruby の文法しかサポートしていません。ただ、Ruby on Rails の場合はモデルの has_many、blongs_to、validates などなど多数の DSL がありこれらもOUTLINEなどに表示して欲しいところですが、その機能を ruby-lsp に実装するのも違っている気がします。

そんな問題を解決しようとしているのが、 ruby-lsp-addons 機構になります。

公式のドキュメントは Add-ons | Ruby LSP にあります。ただ、公式ドキュメントにもあるように実験的な取り組みのようで、 ruby-lsp のメジャーバージョンが変わると、インターフェイスが変わって addons が動かなくなることもありますし、将来a addons のサポートが終わってしまう可能性があることを心にとめて置いてください。

それでは、

について紹介していきたいと思います。

ruby-lsp-rails

こちらの add-on を使えるようにするには、ruby-lsp-rails gem を追加します。

名前からわかる通り、rails 固有の機能サポートを追加するadd-onになります。 今回は、gitlabhq/gitlabhqのソースの一部を表示しながら、 公式ドキュメントからいくつかの機能を抜粋して紹介したいと思います。

modelのDSLサポート

# frozen_string_literal: true

module Achievements
  class Achievement < ApplicationRecord
    include Avatarable
    include StripAttribute

    belongs_to :namespace, inverse_of: :achievements, optional: false

    has_many :user_achievements, inverse_of: :achievement
    has_many :users, through: :user_achievements, inverse_of: :achievements

    strip_attributes! :name, :description

    validates :name,
      presence: true,
      length: { maximum: 255 },
      uniqueness: { case_sensitive: false, scope: [:namespace_id] }
    validates :description, length: { maximum: 1024 }

    def uploads_sharding_key
      { namespace_id: namespace_id }
    end
  end
end

のようなコードがあると、 VSCodeOUTLINE には以下のように Rails 固有の DSL で定義された項目も表示されます。

コントローラーメソッドからviewへのジャンプ

コントローラのメソッド画面にviewを開くリンクが追加されます。

上の絵の赤枠で囲ったリンクが表示されるようになります。 この、Jump to view をクリックすることで view が表示されます。 地味に、便利です。

その他の機能

公式ドキュメントを読むと、モデルの belongs_to のアソシエーション先にジャンプできる機能、コントローラーのメソッド定義箇所からルーターの定義にジャンプできる機能などがあることになっていますが、上手く機能していないようです。この辺は実験的な取り組みということを温かく見守ることしましょう。

ruby-lsp-rspec

次は、ruby-lsp-rspec です。 こちらも add-on を使えるようにするには、ruby-lsp-rspec gem を追加します。

こちらも名前から想像できる通り、 rspec 向けの機能拡張を行う add-on になります。

以下のような specファイルを開くと、

# frozen_string_literal: true

require "spec_helper"

RSpec.describe Diffs::StatsComponent, type: :component do
  include RepoHelpers

  subject(:component) do
    described_class.new(diff_files: diff_files)
  end

  let_it_be(:project) { create(:project, :repository) }
  let_it_be(:repository) { project.repository }
  let_it_be(:commit) { project.commit(sample_commit.id) }
  let_it_be(:diffs) { commit.raw_diffs }
  let_it_be(:diff) { diffs.first }
  let_it_be(:diff_refs) { commit.diff_refs }
  let_it_be(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: diff_refs, repository: repository) }
  let_it_be(:diff_files) { [diff_file] }

  describe "rendered component" do
    subject { page }

    let(:element) { page.find(".js-diff-stats-dropdown") }

    before do
      render_inline component
    end
...

VSCodeOUTLINE に以下のように、 examples のテキストが表示されるため、 spec ファイルの流れを追うのも、修正をするのも楽になります。

また、以下のようにspecファイル上に Run | Run In Terminal | Debug リンクが追加されます。

このRunなどをクリックすることで、rspecのテストを実行できます。また、これらのテスト機構が、 VSCode の テスト機能に統合されているため、 以下のような VSCode 標準の、 Test: Run Test at Curosr などの機能が利用できるようになります。

また、テスト結果についてもGUIで表示られるようになります。

テスト結果がエラーになっているのは、DBなどを構築せずテストだけ実行したためで、gitlab のバグではありません。

使いたいんだけど、プロジェクトの Gemfiles に組み込めないんだけど

VSCoderuby-lsp ですが、インストール時の設定では、プロジェクトに bundle install されているものを使う設定になっていると思います。そのため、プロジェクトの他のgemとの依存関係の問題で使いたくても最新の ruby-lsp が使えない、なんて問題に出会う事があると思います。

そのような場合は、 ruby-lsp などの ruby 開発サポート系ツールだけをインストールしたリポジトリを準備し、bundler でインストールした bin ディレクトリへ PATH を通しておいて、 VSCode 上の設定を変更することで、プロジェクトは独立した形で、 ruby-lsp を使うことができます。

手順は以下のようなGemfileを準備し

# frozen_string_literal: true

source 'http://rubygems.org'


gem 'ruby-lsp'
gem 'ruby-lsp-rails'
gem 'ruby-lsp-rspec'

対象ディレクトリで、

bundle config path vendor
bundle install

しておき、VSCodesettings.json にいかの項目を追加します。

"rubyLsp.bundleGemfile": "${インストールディレクトリ}/Gemfile"

私の場合は、asdf を使ってrubyをいれているのもあってrubocop、erblint などをひとまとめにしたチェック系ツールをまとめたリポジトリを作り、homebrewとasdf用の環境セットアップをするラッパースクリプトを通して、bundle exec するシェルスクリプトから各種ツールを起動するリポジトリを作って使っています。

また、PCが変わっても VSCode の設定が変わらないよう上記リポジトリ

/opt/ruby_tool

へcloneしています。

参考のために、 ruby_toolへのリンクも貼っておきます。頻繁にバージョンを上げたり、ツールを入れ替えたりしているので、ご利用される際は、forkしてお使いください。

最後に

最後までお読みくださりありがとうございました。

明日の記事の担当は 森田 さんです。お楽しみに。

また、株式会社エニグモでは、ツールやエディタのカスタマイズを愛する人エンジニアもそうでないエンジニアも広く募集しております。興味のある方は、以下の求人一覧をご覧ください。


株式会社エニグモ すべての求人一覧

hrmos.co