diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 3eeac6be..ddfe7a32 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -69,6 +69,13 @@ jobs: with: terraform_version: "1.5.0" terraform_wrapper: false + - name: Install Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4' + - name: Install Ruby language server + shell: bash + run: gem install solargraph - name: Install uv shell: bash run: curl -LsSf https://astral.sh/uv/install.sh | sh diff --git a/pyproject.toml b/pyproject.toml index 8872384c..d46c678f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -260,6 +260,7 @@ markers = [ "elixir: language server running for Elixir", "terraform: language server running for Terraform", "snapshot: snapshot tests for symbolic editing operations", + "ruby: language server running for Ruby", ] [tool.codespell] diff --git a/test/resources/repos/ruby/test_repo/.solargraph.yml b/test/resources/repos/ruby/test_repo/.solargraph.yml new file mode 100644 index 00000000..b4678eec --- /dev/null +++ b/test/resources/repos/ruby/test_repo/.solargraph.yml @@ -0,0 +1,4 @@ +--- +include: + - "main.rb" + - "lib.rb" diff --git a/test/resources/repos/ruby/test_repo/lib.rb b/test/resources/repos/ruby/test_repo/lib.rb new file mode 100644 index 00000000..5dd8504b --- /dev/null +++ b/test/resources/repos/ruby/test_repo/lib.rb @@ -0,0 +1,9 @@ +class Calculator + def add(a, b) + a + b + end + + def subtract(a, b) + a - b + end +end diff --git a/test/resources/repos/ruby/test_repo/main.rb b/test/resources/repos/ruby/test_repo/main.rb new file mode 100644 index 00000000..dcf1b0f2 --- /dev/null +++ b/test/resources/repos/ruby/test_repo/main.rb @@ -0,0 +1,21 @@ +require './lib.rb' + +class DemoClass + attr_accessor :value + + def initialize(value) + @value = value + end + + def print_value + puts @value + end +end + +def helper_function(number = 42) + demo = DemoClass.new(number) + Calculator.new.add(demo.value, 10) + demo.print_value +end + +helper_function diff --git a/test/solidlsp/ruby/test_ruby_basic.py b/test/solidlsp/ruby/test_ruby_basic.py new file mode 100644 index 00000000..435c0538 --- /dev/null +++ b/test/solidlsp/ruby/test_ruby_basic.py @@ -0,0 +1,42 @@ +import os +from pathlib import Path + +import pytest + +from solidlsp import SolidLanguageServer +from solidlsp.ls_config import Language +from solidlsp.ls_utils import SymbolUtils + + +@pytest.mark.ruby +class TestRubyLanguageServer: + @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + def test_find_symbol(self, language_server: SolidLanguageServer) -> None: + symbols = language_server.request_full_symbol_tree() + assert SymbolUtils.symbol_tree_contains_name(symbols, "DemoClass"), "DemoClass not found in symbol tree" + assert SymbolUtils.symbol_tree_contains_name(symbols, "helper_function"), "helper_function not found in symbol tree" + assert SymbolUtils.symbol_tree_contains_name(symbols, "print_value"), "print_value not found in symbol tree" + + @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + def test_find_referencing_symbols(self, language_server: SolidLanguageServer) -> None: + file_path = os.path.join("main.rb") + symbols = language_server.request_document_symbols(file_path) + helper_symbol = None + for sym in symbols[0]: + if sym.get("name") == "helper_function": + helper_symbol = sym + break + print(helper_symbol) + assert helper_symbol is not None, "Could not find 'helper_function' symbol in main.rb" + + @pytest.mark.parametrize("language_server", [Language.RUBY], indirect=True) + @pytest.mark.parametrize("repo_path", [Language.RUBY], indirect=True) + def test_find_definition_across_files(self, language_server: SolidLanguageServer, repo_path: Path) -> None: + # Test finding Calculator.add method definition from line 17: Calculator.new.add(demo.value, 10) + definition_location_list = language_server.request_definition(str(repo_path / "main.rb"), 16,17) # add method at line 17 (0-indexed 16), position 17 + + assert len(definition_location_list) == 1 + definition_location = definition_location_list[0] + print(f"Found definition: {definition_location}") + assert definition_location["uri"].endswith("lib.rb") + assert definition_location["range"]["start"]["line"] == 1 # add method on line 2 (0-indexed 1)