### Complete Method Signature Example Source: https://sorbet.org/docs/sigs A full example demonstrating a method signature with type annotations for parameters and return value, including Sorbet runtime requirement. ```ruby # typed: true require 'sorbet-runtime' class Main # Bring the `sig` method into scope extend T::Sig sig { params(x: String).returns(Integer) } def self.main(x) x.length end end ``` -------------------------------- ### Sorbet Configuration File Example Source: https://sorbet.org/docs/cli The `sorbet/config` file specifies arguments for `srb tc`. Each line is treated as a command-line argument. This example shows how to include the current directory and ignore specific paths. ```properties --dir . # Full-line comment --ignore path/to/ignore.rb ``` -------------------------------- ### Initialize Tapioca Project Source: https://sorbet.org/docs/rbi Run this command after installing Tapioca to initialize your project with Sorbet and generate necessary RBI files. ```bash bundle exec tapioca init ``` -------------------------------- ### Basic Setup for Exhaustiveness Checking Example Source: https://sorbet.org/docs/exhaustiveness This snippet sets up two classes, `A` and `B`, and a method `foo` that accepts either type. It serves as a starting point for demonstrating how exhaustiveness checking can prevent bugs when new types are introduced. ```ruby # typed: true extend T::Sig class A; end class B; end sig { params(x: T.any(A, B)).void } def foo(x) # ... end ``` -------------------------------- ### Install Gems with Bundler Source: https://sorbet.org/docs/adopting Execute the bundle install command to install the declared gems. This command should typically install cleanly in most Ruby development environments. ```bash ❯ bundle install ``` -------------------------------- ### Invoke Sorbet as Language Server Source: https://sorbet.org/docs/lsp Examples of how to invoke the Sorbet language server with the `--lsp` flag in different project setups. Ensure your language client is configured to run this command. ```shell srb tc --lsp ``` ```shell bundle exec srb tc --lsp ``` ```shell bazel-bin/main/sorbet --lsp ``` ```shell srb tc --lsp --watchman-path=/path/to/watchman ``` -------------------------------- ### Sorbet Autocompletion Example Source: https://sorbet.org/docs/autocompletion This example demonstrates a simple syntax error that Sorbet can recover from, enabling autocompletion. ```ruby def foo(x) x. end ``` -------------------------------- ### Sorbet Type Checking Example Source: https://sorbet.org/docs/overview This example demonstrates Sorbet's ability to catch type errors both statically and dynamically. It requires `sorbet-runtime` to be installed and configured. ```ruby # typed: true require 'sorbet-runtime' class A extend T::Sig sig { params(x: Integer).returns(String) } def bar(x) x.to_s end end def main A.new.barr(91) # error: Typo! A.new.bar("91") # error: Type mismatch! end ``` -------------------------------- ### Full example with `void` and `returns` Source: https://sorbet.org/docs/sigs This example demonstrates the correct usage of `void` for `greet` (which prints) and `returns(Integer)` for `name_length`. It also shows a type error when a `void` method's result is passed to a method expecting a specific return type. ```ruby # typed: true require 'sorbet-runtime' class Main extend T::Sig # (1) greet has a useless return: sig { params(name: String).void } def self.greet(name) puts "Hello, #{name}!" end # (2) name_length must be given a string: sig { params(name: String).returns(Integer) } def self.name_length(name) name.length end end # (3) It's an error to pass a void result to name_length: Main.name_length(Main.greet('Alice')) # => error! ``` -------------------------------- ### Neovim LSP Client Initialization Example Source: https://sorbet.org/docs/highlight-untyped In Neovim, configure the `highlightUntypedDiagnosticSeverity` setting via the `init_options` argument to `vim.lsp.start_client()`. This passes the setting to the underlying `initialize` request. ```lua vim.lsp.start_client({ name = "sorbet", cmd = { "srb", "lsp" }, init_options = { highlightUntypedDiagnosticSeverity = 2, -- Warning }, }) ``` -------------------------------- ### Basic Class Method and Instance Method Example Source: https://sorbet.org/docs/class-of Demonstrates a class with both instance and class methods, and a signature using T.class_of for type checking. ```ruby class MyClass def some_instance_method; end def self.some_class_method; end end sig { params(x: T.class_of(MyClass)).void } def example1(x) x.new.some_instance_method # ok x.some_class_method # ok end example1(MyClass) # ok ``` -------------------------------- ### Show Sorbet Version Source: https://sorbet.org/docs/cli-ref Use the --version flag to display the current version of Sorbet installed. ```bash --version Show Sorbet's version ``` -------------------------------- ### Example JSON Output for Per-File Untyped Usages Source: https://sorbet.org/docs/metrics This is an example of the JSON structure Sorbet outputs when tracking untyped usages per file. Files with no untyped usages will omit the `untyped_usages` key. ```json { "files": [ { "path": "foo/bar.rb", // ... "untyped_usages": 23 }, // ... ] } ``` -------------------------------- ### Configure Sorbet LSP in Neovim (Basic) Source: https://sorbet.org/docs/lsp Use this configuration to set up Sorbet as a language server within Neovim. Ensure nvim-lspconfig is installed and configured. ```lua local lspconfig = require('lspconfig') lspconfig.sorbet.setup {} ``` -------------------------------- ### Basic Minitest Spec Example Source: https://sorbet.org/docs/minitest A standard example of a Minitest test class using the Spec DSL. This demonstrates the basic structure of describe and it blocks for testing a simple Ruby class. ```ruby require 'minitest/autorun' class MyClass def greet = 'hello' end class MyTest < Minitest::Spec describe 'my class' do it 'works' do assert_equal('hello', MyClass.new.greet) end end end ``` -------------------------------- ### Overloaded Method Example (Discouraged) Source: https://sorbet.org/docs/overloads This example demonstrates an overloaded method that accepts either a string or an array of strings and returns a single `MyModel` or an array of `MyModel`s, respectively. This pattern is generally discouraged in favor of separate methods. ```ruby sig { params(what: String).returns(MyModel) } sig { params(what: T::Array[String]).returns(T::Array[MyModel]) } def find(what); end ``` -------------------------------- ### Example: Using T.proc for Block Arguments Source: https://sorbet.org/docs/procs This example demonstrates declaring a block argument with `T.proc` and how Sorbet infers the type of the block's parameter statically. The `T.proc` annotation itself is not enforced at runtime. ```ruby # typed: true sig { params(blk: T.proc.params(arg0: Integer).void).void } def foo(&blk) x = T.let('not an int', T.untyped) # (2) The `T.proc` annotation is not checked at runtime. # (This won't raise even though x is not an Integer) yield x end # (3) Sorbet incorporates the `T.proc` annotation into what it knows statically foo do |x| T.reveal_type(x) # Revealed type: Integer end ``` -------------------------------- ### Get Help for Sorbet Subcommands Source: https://sorbet.org/docs/cli Use `--help` to learn about available `srb` subcommands and their options. This is useful for discovering the full range of Sorbet's capabilities. ```bash ❯ srb --help ``` ```bash # for options that Sorbet uses when typechecking ❯ srb tc --help ``` -------------------------------- ### Handling `prepend` in Ruby Source: https://sorbet.org/docs/unsupported Demonstrates the `prepend` keyword in Ruby, which Sorbet does not model. This example shows that `WillBePrepended#foo` is called. ```ruby module WillBePrepended def foo puts 'WillBePrepended#foo' end end class Example prepend WillBePrepended def foo puts 'Example#foo' end end Example.new.foo # => WillBePrepended#foo ``` -------------------------------- ### Example of Abstract Singleton Method (Not Recommended) Source: https://sorbet.org/docs/abstract Demonstrates the problematic use of abstract singleton class methods and how `abstract_module?` can be used to mitigate runtime errors. This pattern is generally discouraged. ```ruby # typed: true # --- This is an example of what NOT to do --- extend T::Sig class AbstractFoo extend T::Sig extend T::Helpers abstract! sig { abstract.void } def self.example; end end class Foo < AbstractFoo sig { override.void } def self.example puts 'Foo#example' end end sig { params(mod: T.class_of(AbstractFoo)).void } def calls_example_bad(mod) # even though there are no errors, # the call to mod.example is NOT always safe! # (see comments below) mod.example end sig { params(mod: T.class_of(AbstractFoo)).void } def calls_example_okay(mod) if !T::AbstractUtils.abstract_module?(mod) mod.example end end calls_example_bad(Foo) # no errors calls_example_bad(AbstractFoo) # no static error, BUT raises at runtime! calls_example_okay(Foo) # no errors calls_example_okay(AbstractFoo) # no errors, because of explicit check ``` -------------------------------- ### Runtime Error Example for T.let Source: https://sorbet.org/docs/type-assertions Demonstrates the runtime TypeError that occurs when a T.let assertion fails. ```ruby $ ruby test.rb <...>/lib/types/private/casts.rb:15:in `cast': T.let: Expected type String, got type Integer with value 10 (TypeError) (TypeError) Caller: test.rb:8 from <...>/lib/types/_types.rb:138:in `let' from test.rb:8:in `
' ``` -------------------------------- ### RBI File Syntax Example Source: https://sorbet.org/docs/rbi Demonstrates the syntax for declaring modules, classes, includes, extends, methods, and constants within an RBI file. Use this for defining type information for Sorbet. ```ruby # -- example.rbi -- # typed: strict # Declares a module module MyModule end # Declares a class class Parent # Declares what modules this class mixes in include MyModule extend MyModule # Declares an untyped method def foo end # Declares a method with input and output types sig { params(x: Integer).returns(String) } def bar(x) end end # Declares a class that subclasses another class class Child < Parent # Declares an Integer constant, with an arbitrary value X = T.let(T.unsafe(nil), Integer) end ``` -------------------------------- ### Ruby `initialize` method return value Source: https://sorbet.org/docs/error-reference In Ruby, the return value of `initialize` is typically ignored. This example shows the internal structure of `new`. ```ruby def self.new(...) instance = alloc _discarded = instance.initialize(...) instance end ``` -------------------------------- ### Sorbet T.let and T.untyped Example Source: https://sorbet.org/docs/gradual Demonstrates how T.let asserts types and how T.untyped allows any value to be asserted as any type, leading to potentially inaccurate type claims at runtime. ```ruby # T.let asserts that an expression has a type: x = T.let(0, Integer) # Anything can be T.untyped: y = T.let(x, T.untyped) # and T.untyped can be anything! z = T.let(y, String) T.reveal_type(x) # => Integer T.reveal_type(y) # => T.untyped T.reveal_type(z) # => String # ... z = 0, but its type is String! ``` -------------------------------- ### Standard Library Generics Syntax in Sorbet Source: https://sorbet.org/docs/stdlib-generics This table shows the Sorbet syntax for common standard library generic types and their corresponding example values. ```ruby T::Array[Integer] ``` ```ruby T::Array[String] ``` ```ruby T::Hash[Symbol, Integer] ``` ```ruby T::Hash[String, Float] ``` ```ruby T::Set[Integer] ``` ```ruby T::Range[Integer] ``` ```ruby T::Enumerable[Integer] ``` ```ruby T::Enumerator[Integer] ``` ```ruby T::Enumerator::Lazy[Integer] ``` ```ruby T::Enumerator::Chain[Integer] ``` ```ruby T::Class[Integer] ``` ```ruby T::Module[Integer] ``` -------------------------------- ### Valid Package Name Example Source: https://sorbet.org/docs/error-reference Demonstrates valid package names in Sorbet's custom package mode. Package names can only share a name with a class or module. ```ruby module Some::Namespace MyConstant = ["hello", "world"] end ``` -------------------------------- ### Handling Incorrect Method Parameters in Sorbet Source: https://sorbet.org/docs/error-reference This example demonstrates common parameter errors like too many, too few, non-existent, or mismatched named/positional parameters, and their correct usage. ```ruby def foo(x: nil); end foo(1) # error foo(y: 1) # error foo(x: 1) # ok foo() # ok def bar(x:); end bar() # error bar(1) # error bar(x: 1) # ok ``` -------------------------------- ### Demonstrate Final Syntax for Methods, Classes, and Modules Source: https://sorbet.org/docs/final This snippet shows the syntax for declaring a class final, a method final, and includes the necessary setup for enabling final checks. ```ruby # typed: true require 'sorbet-runtime' # (0) One-time setup for final: T::Configuration.enable_final_checks_on_hooks class A extend T::Sig # (Brings `sig` into scope) extend T::Helpers # (Brings `final!` into scope) final! # (1) Final class (can't be subclassed) sig(:final) {void} # (2) Final method (can't be overridden / redefined) def foo; end end ``` -------------------------------- ### Variance Calculation Example Source: https://sorbet.org/docs/generics This diagram illustrates how to calculate input and output positions by multiplying variance values (-1 for input, +1 for output) through nested function types. ```plaintext -1 +1 A -> B ┌── -1 ──┐ ┌── +1 ──┐ -1 +1 -1 +1 ( C -> D ) -> ( E -> F ) ``` -------------------------------- ### Share Implementation Between Methods Source: https://sorbet.org/docs/overloads Implement one method in terms of another to share common logic. This example shows `find_many` calling `find_one` for each ID. ```ruby sig { params(ids: T::Array[String]).returns(T::Array[MyModel]) } def find_many(ids) ids.map { |id| find_one(id) } end ``` -------------------------------- ### Skip Sorbet Configuration File Source: https://sorbet.org/docs/cli Use the `--no-config` flag to prevent Sorbet from loading arguments from the `sorbet/config` file. This is useful for creating minimal reproduction examples. ```bash srb tc --no-config ... ``` -------------------------------- ### Standard Library `[]` Method Usage Source: https://sorbet.org/docs/stdlib-generics These examples demonstrate how standard library classes like Array, Set, and Hash can be used with the `[]` method, which Sorbet mirrors in the `T::` namespace to avoid conflicts. ```ruby Array[1, 2, 3] # => evaluates to the array `[1, 2, 3]` ``` ```ruby Set[1, 2, 3] # => evaluates to the set containing 1, 2, and 3 ``` ```ruby Hash[:key1, 1, :key2, 2] # => evaluates to the hash `{key1: 1, key2: 2}` ``` -------------------------------- ### Initialize Sorbet with Tapioca Source: https://sorbet.org/docs/adopting Run `bundle exec tapioca init` to set up Sorbet in your project. This command generates a `sorbet/` directory containing configuration and RBI files. ```bash ❯ bundle exec tapioca init ``` -------------------------------- ### Rakefile DSL definition example Source: https://sorbet.org/docs/faq This snippet from Rake's `dsl_definition.rb` illustrates how Rake monkey patches the global `main` object to extend its DSL, which Sorbet cannot statically analyze. ```ruby # -- from lib/rake/dsl_definition.rb -- ... # Extend the main object with the DSL commands. This allows top-level ``` -------------------------------- ### Show Help Section Source: https://sorbet.org/docs/cli-ref Use the -h or --help flag to display help information. Optionally, specify a SECTION to show help for only that part. ```bash -h, --help [=SECTION(=all)] Show help. Can pass an optional SECTION to show help for only one section instead of the default of all sections ``` -------------------------------- ### Sorbet Project Structure after Initialization Source: https://sorbet.org/docs/adopting After running `tapioca init`, your project should contain a `sorbet/` directory with a `config` file and an `rbi/` subdirectory for interface definitions. ```text sorbet/ ├── config └── rbi/ └── ··· ``` -------------------------------- ### Recursive Type Alias Example (TypeScript) Source: https://sorbet.org/docs/type-aliases Illustrates the concept of recursive type aliases, showing how TypeScript allows a type to reference itself, as demonstrated in this example for a JSON type. ```typescript type JSON = null | number | string | JSON[] | {[arg: string]: JSON}; ``` -------------------------------- ### Verify Sorbet Installation Source: https://sorbet.org/docs/adopting Run `srb` to view help output, `srb typecheck -e` for a quick type check, and `ruby -e 'require "sorbet-runtime"'` to confirm the runtime is loadable. ```bash ❯ bundle exec srb [help output] ❯ bundle exec srb typecheck -e 'puts "Hello, world!"' No errors! Great job. ❯ bundle exec ruby -e 'puts(require "sorbet-runtime")' true ``` -------------------------------- ### Sorbet Metrics JSON Output Example Source: https://sorbet.org/docs/metrics An example of the JSON structure generated by Sorbet when collecting metrics. The 'metrics' array contains individual metric names and their values. ```json { "repo": "my_project", "sha": "0.5.5278", "status": "Success", "branch": "master", "timestamp": "1581018717", "uuid": "0x180096dcfb381440-0x18c753ca-0x4074-0x8a2f-0xd1f9c82443c24b10x41a7", "metrics": [ { "name": "my_project.run.utilization.user_time.us", "value": 37863 }, // ... ] } ``` -------------------------------- ### Initialize Sorbet LSP with supportsSorbetURIs Source: https://sorbet.org/docs/sorbet-uris Pass `supportsSorbetURIs: true` in the `initializationOptions` of the `initialize` request to enable Sorbet to use `sorbet:` URIs for synthetic or missing files. ```json "initializationOptions": { // ... "supportsSorbetURIs": true, // ... } ``` -------------------------------- ### Invariant Type Member Example Source: https://sorbet.org/docs/generics By default, `type_member` is invariant. This means two instances of a generic class are only subtypes if their type parameters are equivalent. This example shows an error when attempting to widen the type. ```ruby class Box extend T::Generic # no variance annotation, so invariant by default Elem = type_member end int_box = Box[Integer].new # Integer <: Numeric, because Integer inherits from Numeric, however: T.let(int_box, Box[Numeric]) # ^ error: Argument does not have asserted type # Elem is invariant, so the claim # Box[Integer] <: Box[Numeric] # is not true ``` -------------------------------- ### Configure Sorbet LSP in Neovim (Custom Initialization Options) Source: https://sorbet.org/docs/lsp Configure Sorbet's language server with custom initialization options in Neovim. This allows fine-tuning of features like 'highlightUntyped'. ```lua local lspconfig = require('lspconfig') lspconfig.sorbet.setup { cmd = { "bundle", "exec", "srb", "tc", "--lsp" }, init_options = { highlightUntyped = true, }, } ``` -------------------------------- ### View Sorbet Extension Output Logs Source: https://sorbet.org/docs/vscode To troubleshoot Sorbet startup issues, view the extension logs by clicking on 'Sorbet: ...' in the status bar and selecting 'View Output', or by using the `>Sorbet: Show Output` command. This output often contains error messages indicating why Sorbet crashed. ```text [Error - 9:36:32 AM] Connection to server got closed. Server will not be restarted. Running Sorbet LSP with: bundle exec srb typecheck --lsp Could not locate Gemfile or .bundle/ directory ``` -------------------------------- ### Basic T.all Syntax Source: https://sorbet.org/docs/intersection-types Demonstrates the basic syntax for `T.all`, which requires at least two type arguments. ```ruby T.all(Type1, Type2, ...) ``` -------------------------------- ### Define Generic Function Type in Sorbet Source: https://sorbet.org/docs/generics This snippet defines a generic interface `Fn` representing a function with `Input` and `Output` type members. It includes an example of a function `example` that takes a generic `Fn` object and an `Integer`, returning a `String`. ```ruby module Fn extend T::Sig extend T::Generic interface! Input = type_member(:in) Output = type_member(:out) sig { abstract.params(input: Input).returns(Output) } def call(input); end end sig do params( fn: Fn[Integer, String], x: Integer, ) .returns(String) end def example(fn, x) res = fn.call(x) res end ``` -------------------------------- ### Configure Sorbet LSP in Neovim (Custom Command) Source: https://sorbet.org/docs/lsp Customize the command used to start the Sorbet language server in Neovim. This is useful if Sorbet is not in your PATH or requires specific execution context, like using 'bundle exec'. ```lua local lspconfig = require('lspconfig') lspconfig.sorbet.setup { cmd = { "bundle", "exec", "srb", "tc", "--lsp" }, } ``` -------------------------------- ### Avoid Self-Referential Constants Source: https://sorbet.org/docs/error-reference A constant cannot store a reference to itself. This example shows an invalid self-referential constant definition. ```ruby X = X ``` -------------------------------- ### Method Signature with No Parameters Source: https://sorbet.org/docs/sigs Example of a method signature for a method that takes no parameters, omitting the `params` section. ```ruby sig { returns(Integer) } def self.main 42 end ``` -------------------------------- ### Add Tapioca to Gemfile Source: https://sorbet.org/docs/rbi Add Tapioca to your Gemfile to manage RBI generation. Ensure you run `bundle install` after adding it. ```ruby gem "tapioca", require: false, :group => [:development, :test] ``` -------------------------------- ### Inheriting from a Final Class Source: https://sorbet.org/docs/error-reference Shows an example where a class attempts to inherit from a class marked as final, which is not allowed. Final classes cannot be subclassed. ```ruby class Final extend T::Helpers final! end class Bad < Final; end # error ``` -------------------------------- ### Sorbet Input Options Source: https://sorbet.org/docs/cli-ref Configure how Sorbet receives input files and directories. Use these options to specify which files Sorbet should process and how to interpret them. ```bash -e Treat as if it were the contents of a Ruby file passed on the command line (default: "") --e-rbi Like `-e`, but treat as an RBI file (default: "") --file Run over the contents of (Equivalent to passing as a positional argument) --dir Run over all Ruby and RBI files in , recursively (Equivalent to passing as a positional argument) --allowed-extension [,...] Use these extensions to determine which file types Sorbet should discover inside directories. (default: .rb,.rbi) --ignore Ignores input files that contain in their paths (relative to the input path passed to Sorbet). When starts with `/` it matches against the prefix of these relative paths; others match anywhere. Matches must be against whole path segments, so `foo` matches `foo/bar.rb` and `bar/foo/baz.rb` but not `foo.rb` or `foo2/bar.rb`. --no-config Do not load the content of the `sorbet/config` file. Otherwise, Sorbet reads the `sorbet/config` file and treats each line as if it were passed on the command line, unless the line starts with `#`. To load a as if it were a config file, pass `@` as a positional arg --typed {false,true,strict,strong,[auto]} Force all code to specified strictness level, disregarding all `# typed:` sigils. For `auto`, uses the `# typed:` sigil in the file or `false` for files without a sigil. (default: auto) --typed-override Read to override the strictness of individual files. Contents must be a map of `: ['path1.rb', ...]` pairs. Can be used to enable type checking for certain files temporarily without having to add a comment to every file. (default: "") ``` -------------------------------- ### Basic RBS Comment Signature Source: https://sorbet.org/docs/rbs-support Example of a basic function signature using RBS comment syntax. Enable with `--enable-experimental-rbs-comments`. ```ruby #: (Integer) -> String def foo(x) T.reveal_type(x) # Revealed type: `Integer` x.to_s end str = foo(42) T.reveal_type(str) # Revealed type: `String` ``` -------------------------------- ### Sorbet Method Signature and Implementation Source: https://sorbet.org/docs/gradual Demonstrates a Sorbet method signature with a return type annotation and its corresponding Ruby implementation. This example highlights how Sorbet checks return types at runtime. ```ruby sig { params(person: Person).returns(String) } def name_length(person) person.name.length end person = Person.new person.name = 'Jenny Rosen' name_length(person) ``` -------------------------------- ### Avoid Cyclic Type Aliases Source: https://sorbet.org/docs/error-reference Sorbet does not support recursive type aliases. This example shows an invalid cyclic type alias definition. ```ruby X = T.type_alias {X} # error: Unable to resolve right hand side of type alias ``` -------------------------------- ### Using Interfaces for Abstract Methods (Recommended) Source: https://sorbet.org/docs/abstract Illustrates a better approach using an interface with abstract instance methods, which are then extended into concrete classes. This avoids the need for runtime checks and abstract singleton methods. ```ruby # typed: true extend T::Sig module IFoo extend T::Sig extend T::Helpers abstract! sig { abstract.void } def example; end end class Foo extend T::Sig extend IFoo sig { override.void } def self.example puts 'Foo#example' end end sig { params(mod: IFoo).void } def calls_example_good(mod) # call to mod.example is always safe mod.example end calls_example_good(Foo) # no errors calls_example_good(IFoo) # doesn't type check ``` -------------------------------- ### Mixin Example with T.self_type Source: https://sorbet.org/docs/self-type Demonstrates using T.self_type within a mixin module. The type of the receiver is correctly inferred when the mixin is used in a class. ```ruby module Mixin extend T::Sig sig { returns(T.self_type) } def bar self end end class UsesMixin extend Mixin end T.reveal_type(UsesMixin.bar) # => T.class_of(UsesMixin) ``` -------------------------------- ### Example Ruby File for Sorbet Testing Source: https://sorbet.org/docs/quickref A minimal Ruby file with Sorbet type annotations, suitable for testing static and runtime checks. It includes the necessary sigil and a simple method. ```ruby # -- foo.rb -- # typed: true require 'sorbet-runtime' class Main extend T::Sig sig { void } def self.main puts 'Hello, world!' end end Main.main ``` -------------------------------- ### Initialize Tapioca Source: https://sorbet.org/docs/adopting Initialize Tapioca, a tool for generating RBI files, which are essential for Sorbet to understand gem interfaces. The generated files, including bin/tapioca, should be committed to source control. ```bash tapioca init ``` -------------------------------- ### Sorbet Operation Status Type Definition Source: https://sorbet.org/docs/lsp Defines the possible statuses for a Sorbet operation: 'start' or 'end'. This is used within the `sorbet/showOperation` notification. ```typescript export type SorbetOperationStatus = 'start' | 'end'; ``` -------------------------------- ### Run Sorbet Static Check on a Whole Project Source: https://sorbet.org/docs/quickref To typecheck an entire project, run the `srb` command from the project's root directory. This command uses the `sorbet/config` file to determine which files to check. ```bash ❯ srb ``` -------------------------------- ### Inferring Local Variable Types in Sorbet Source: https://sorbet.org/docs/type-annotations Sorbet infers the type of local variables from their initialization. This example shows Sorbet inferring `x` as an `Integer`. ```ruby x = 2 + 3 ``` -------------------------------- ### Create `.watchmanconfig` for Sorbet projects Source: https://sorbet.org/docs/lsp Provides a solution for using Sorbet with watchman in projects that do not use version control systems like Git. Creating an empty `.watchmanconfig` file in the project root helps watchman identify the project directory. ```plaintext .watchmanconfig ``` -------------------------------- ### Sorbet Configuration for Input Directory Source: https://sorbet.org/docs/lsp Configure Sorbet to use a single input directory with ignore flags for LSP mode. This workaround is necessary because LSP mode has limitations on multiple input directories. ```shell --dir=. --ignore=/bin ``` -------------------------------- ### Inverted Failure Handler Logic Source: https://sorbet.org/docs/runtime This configuration inverts the previous example, defaulting to logging errors and requiring `.on_failure(:raise)` to opt into raising `TypeError`. ```ruby T::Configuration.call_validation_error_handler = lambda do |signature, opts| # ┌────┐ if signature&.on_failure && signature&.on_failure[0] == :raise raise TypeError.new(opts[:pretty_message]) else puts opts[:pretty_message] end end # ... # ┌─────────────────┐ sig { params(argv: T::Array[String]).void.on_failure(:raise) } ``` -------------------------------- ### Sorbet CLI Usage Source: https://sorbet.org/docs/cli-ref Basic usage of the Sorbet command-line interface. Use this to understand the fundamental structure of Sorbet commands. ```bash Sorbet: A fast, powerful typechecker designed for Ruby Usage: sorbet [options] [[--] ...] ``` -------------------------------- ### Intersection with Union Types Source: https://sorbet.org/docs/intersection-types Sorbet distributes intersection types over union types. In this example, `T.all(FooParent, T.any(FooChild, Bar))` simplifies to `FooChild`. ```ruby class FooParent; end class FooChild < FooParent; end class Bar; end sig { params(x: T.all(FooParent, T.any(FooChild, Bar))).void } def example3(x) T.reveal_type(x) # => FooChild end ``` -------------------------------- ### Apply All Quick Fixes in File Source: https://sorbet.org/docs/code-actions This code action applies all quickfix code actions within the current file. It's useful for bulk corrections, such as when upgrading type checking levels or silencing multiple `possibly-nil` errors. ```ruby # typed: true def foo x = nil T.must(x) end ``` -------------------------------- ### Declare a Final Method in Sorbet Source: https://sorbet.org/docs/final This example demonstrates how to declare a method as final using `sig(:final)`. Ensure `T::Configuration.enable_final_checks_on_hooks` is called once per project. ```ruby require 'sorbet-runtime' # (1) Call this once per project, ideally right after `require 'sorbet-runtime'` T::Configuration.enable_final_checks_on_hooks module HasFinalMethod extend T::Sig # (2) The special `sig(:final)` syntax declares this method final: sig(:final) {void} def foo; end end ``` -------------------------------- ### Sorbet Documentation Comment Placement - Is Documentation Source: https://sorbet.org/docs/doc-comments This example shows a valid documentation comment. Sorbet recognizes this comment as documentation because there is no blank line between it and the definition. ```ruby # This comment IS a documentation comment, because there is no blank line. def bar; end ``` -------------------------------- ### Basic Sorbet Metrics Collection Source: https://sorbet.org/docs/metrics Instructs Sorbet to typecheck the current project and write metrics to a JSON file. Ensure the `--metrics-file` flag is used to enable metrics recording. ```bash ❯ srb tc --metrics-file=metrics.json ``` -------------------------------- ### Execute Sorbet LSP on a remote host via SSH Source: https://sorbet.org/docs/lsp Shows how to run the Sorbet language server on a remote machine and connect to it from a local client using SSH. This allows the client (e.g., VS Code) to run on one host while the server executes on another. ```bash ssh some.remote.host -- 'cd project; bundle exec srb tc --lsp' ``` -------------------------------- ### Handling `sorbet/showOperation` Notifications Source: https://sorbet.org/docs/server-status Sorbet sends `sorbet/showOperation` notifications to inform clients about the start and end of operations. Clients need to register a handler for this notification. ```APIDOC ## Handling `sorbet/showOperation` Notifications ### Description Once `supportsOperationNotifications` is enabled, Sorbet will send `sorbet/showOperation` notifications. These are unprompted server-to-client messages, similar to `textDocument/publishDiagnostics`, indicating the status of ongoing operations. Clients must register a handler to process these notifications. ### Method Notification (Server-to-Client) ### Endpoint `sorbet/showOperation` ### Parameters - **params**: `SorbetShowOperationParams` (as defined in Sorbet-specific LSP extensions) - This parameter object contains details about the operation being reported. ### Request Example (This is a server-to-client notification, not a request from the client.) ### Response Notifications do not expect a response from the client. ``` -------------------------------- ### Define Type Alias with Enum Values Source: https://sorbet.org/docs/tenum Individual enum values can be used in type aliases, for example, to create a union type of specific enum members. ```ruby RedSuit = T.type_alias { T.any(Suit::Hearts, Suit::Diamonds) } ``` -------------------------------- ### Running Sorbet with Custom Packager Layers Source: https://sorbet.org/docs/error-reference Specifies the valid layers for package layering checks via a command-line flag. ```bash srb tc --packager-layers util,lib,app ``` -------------------------------- ### Contravariance Example: Function Subtyping Source: https://sorbet.org/docs/generics Demonstrates how contravariance applies to function types. A function accepting a supertype can be used where a function accepting a subtype is expected, but not vice-versa. ```ruby sig do params( f: T.proc.params(x: Child).void ) .void end def takes_func(f) f.call(Child.new) f.call(GrandChild.new) end wants_at_least_parent = T.let( ->(parent) {parent.on_parent}, T.proc.params(parent: Parent).void ) takes_func(wants_at_least_parent) # OK wants_at_least_child = T.let( ->(child) {child.on_child}, T.proc.params(child: Child).void ) takes_func(wants_at_least_child) # OK wants_at_least_grandchild = T.let( ->(grandchild) {grandchild.on_grandchild}, T.proc.params(grandchild: GrandChild).void ) takes_func(wants_at_least_grandchild) # error! ``` -------------------------------- ### Sorbet Generics Type Checking Example Source: https://sorbet.org/docs/stdlib-generics Demonstrates a case where Sorbet attempts to detect and report a static error for incorrect generic type usage with `T.any`. ```ruby sig { params(xs: T.any(T::Array[Integer], T::Array[String])).void } def example(xs) if xs.is_a?(T::Array[Integer]) # error! # ... elsif xs.is_a?(T::Array[String]) # error! # ... end end ``` -------------------------------- ### Sorbet error for missing Kernel ancestor Source: https://sorbet.org/docs/requires-ancestor This example shows a `MyBaseClass` that includes `MyHelper` but does not include `Kernel`. Sorbet correctly identifies this violation of the `requires_ancestor` constraint. ```ruby class MyBaseClass < BasicObject # error: `MyBaseClass` must include `Kernel` (required by `MyHelper`) include MyHelper end ``` -------------------------------- ### Show Sorbet License Source: https://sorbet.org/docs/cli-ref Use the --license flag to view Sorbet's license and those of its dependencies. ```bash --license Show Sorbet's license, and licenses of its dependencies ``` -------------------------------- ### Interface definition and usage with T.anything comparison Source: https://sorbet.org/docs/anything Illustrates how T.anything differs from BasicObject by defining an interface and showing that comparing instances of this interface is not allowed by default, unlike BasicObject's `==`. ```ruby module IFoo extend T::Helpers abstract! sig { abstract.void } def foo; end end sig { params(x: IFoo, y: IFoo).void } def example(x, y) x.foo # obviously okay x == y # should this be okay? (spoiler: it's not) end ```