> For the complete documentation index, see [llms.txt](https://light-services.kodkod.me/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://light-services.kodkod.me/deep-dive/ruby-lsp.md).

# Ruby LSP Integration

Operandi provides a Ruby LSP add-on that enhances your editor experience by informing the language server about methods generated by the `arg` and `output` DSL keywords.

## Features

When you use the `arg` or `output` keywords, Operandi dynamically generates methods at runtime:

```ruby
class MyService < ApplicationService
  arg :user, type: User
  output :result, type: Hash
end
```

This generates the following methods:

* `user` - getter method (returns `User`)
* `user?` - predicate method (returns boolean)
* `user=` - setter method (private, accepts `User`)
* `result` - getter method (returns `Hash`)
* `result?` - predicate method (returns boolean)
* `result=` - setter method (private, accepts `Hash`)

The Ruby LSP add-on teaches the language server about these generated methods, enabling:

* **Go to Definition** - Navigate to the `arg`/`output` declaration
* **Completion** - Autocomplete generated method names
* **Hover** - See information about generated methods, including return types
* **Signature Help** - Get parameter hints for setter methods
* **Workspace Symbol** - Find generated methods in symbol search

## Setup

The add-on is automatically discovered by Ruby LSP when Operandi is in your project's dependencies. No additional configuration is required.

### Requirements

* Ruby LSP `~> 0.26` or later
* Operandi gem installed in your project

### Verification

To verify the add-on is loaded, check the Ruby LSP output in your editor. You should see "Ruby LSP Operandi" listed among the active add-ons.

## How It Works

The add-on uses Ruby LSP's **indexing enhancement** system to register generated methods during code indexing. When the indexer encounters an `arg` or `output` call with a symbol argument, it automatically registers the three generated methods (getter, predicate, setter) in the index.

This is a static analysis approach - the add-on analyzes your source code without executing it. This means:

* Methods are recognized immediately as you type
* No running application is required
* Works with any editor that supports Ruby LSP

## Type Inference

The add-on extracts type information from the `type:` option and includes it as YARD-style documentation comments. This enables hover information to display return types for generated methods.

### Simple Ruby Types

```ruby
arg :user, type: User      # → User
arg :items, type: Array    # → Array
arg :name, type: String    # → String
```

### Namespaced Types

```ruby
arg :payment, type: Stripe::Charge      # → Stripe::Charge
arg :config, type: MyApp::Configuration # → MyApp::Configuration
```

### Sorbet Runtime Types

Sorbet runtime types are resolved to their underlying Ruby types:

| Sorbet Type               | Ruby Type                 |
| ------------------------- | ------------------------- |
| `T::Boolean`              | `TrueClass \| FalseClass` |
| `T.nilable(String)`       | `String \| NilClass`      |
| `T::Array[String]`        | `Array`                   |
| `T::Hash[Symbol, String]` | `Hash`                    |
| `T.any(String, Integer)`  | `String \| Integer`       |

### Custom Type Mappings

You can add custom type mappings through the Operandi configuration:

```ruby
# config/initializers/operandi.rb
Operandi.configure do |config|
  config.ruby_lsp_type_mappings = {
    "Types::UUID" => "String",
    "Types::Money" => "BigDecimal",
    "Types::JSON" => "Hash",
    "CustomTypes::Email" => "String",
    "MyApp::Types::PhoneNumber" => "String",
  }
end
```

Custom mappings allow you to:

* Add mappings for your own custom types
* Override default mappings if needed
* Support domain-specific type modules

## Limitations

* Only `arg` and `output` declarations with a symbol as the first argument are recognized
* The add-on cannot detect dynamically computed argument names (e.g., `arg some_variable`)
* Inherited arguments/outputs from parent classes are not automatically discovered
* Parameterized types like `T::Array[String]` resolve to the container type (`Array`), not the full generic type

## What's Next?

Learn more about other integrations:

* [RuboCop Integration](/deep-dive/rubocop.md) - Static analysis cops for services
* [Testing](/deep-dive/testing.md) - Testing your services with RSpec matchers


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://light-services.kodkod.me/deep-dive/ruby-lsp.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
