Tapioca / Sorbet Integration
Operandi provides a Tapioca DSL compiler that generates RBI signatures for methods automatically created by the arg and output DSL macros. This enables full Sorbet type checking for your services.
Features
When you use the arg or output keywords, Operandi dynamically generates methods at runtime:
class CreateUser < ApplicationService
arg :name, type: String
arg :email, type: String, optional: true
arg :role, type: [Symbol, String]
output :user, type: User
endThe Tapioca compiler generates RBI signatures for these methods:
# sorbet/rbi/dsl/create_user.rbi
# typed: true
class CreateUser
sig { returns(String) }
def name; end
sig { returns(T::Boolean) }
def name?; end
sig { returns(T.nilable(String)) }
def email; end
sig { returns(T::Boolean) }
def email?; end
sig { returns(T.any(Symbol, String)) }
def role; end
sig { returns(T::Boolean) }
def role?; end
sig { returns(User) }
def user; end
sig { returns(T::Boolean) }
def user?; end
private
sig { params(value: String).returns(String) }
def name=(value); end
sig { params(value: T.nilable(String)).returns(T.nilable(String)) }
def email=(value); end
sig { params(value: T.any(Symbol, String)).returns(T.any(Symbol, String)) }
def role=(value); end
sig { params(value: User).returns(User) }
def user=(value); end
endSetup
1. Install Tapioca
Add Tapioca to your Gemfile:
Then run:
2. Generate RBI Files
The Operandi compiler is automatically discovered by Tapioca. Generate RBI files with:
This will create RBI files in sorbet/rbi/dsl/ for all your services.
3. Re-generate After Changes
After adding or modifying arg/output declarations, regenerate the RBI files:
Type Mappings
Ruby Types
Standard Ruby types are mapped directly:
String
::String
Integer
::Integer
Float
::Float
Hash
::Hash
Array
::Array
Symbol
::Symbol
User (custom)
::User
Boolean Types
Boolean types are mapped to T::Boolean:
Union Types
Multiple types create union types:
Optional Types
Optional arguments/outputs are wrapped in T.nilable:
Sorbet Runtime Types
Sorbet runtime types are automatically resolved:
T::Boolean
T::Boolean
T.nilable(String)
T.nilable(::String)
T::Array[String]
T::Array[::String]
T::Hash[Symbol, String]
T::Hash[::Symbol, ::String]
T.any(String, Integer)
T.any(::String, ::Integer)
Generated Methods
For each arg or output, three methods are generated:
name
The declared type
public
name?
T::Boolean
public
name=
The declared type
private
Inheritance
The compiler handles inherited arguments and outputs. If a child service inherits from a parent, the RBI will include methods for both parent and child fields.
Troubleshooting
RBI files not generated
Ensure Operandi is properly loaded in your application. The compiler only runs if Operandi::Base is defined.
Types showing as T.untyped
T.untypedThis happens when:
No
type:option is specified for the argument/outputThe type cannot be resolved (e.g., undefined constant)
See Also
Ruby LSP Integration - Editor integration without Sorbet
Arguments - Full
argDSL documentationOutputs - Full
outputDSL documentation
Last updated