Ruby sorbet: Difference between revisions

From wikinotes
No edit summary
 
(6 intermediate revisions by the same user not shown)
Line 16: Line 16:
</blockquote><!-- documentation -->
</blockquote><!-- documentation -->


= Locations =
= Notes =
<blockquote>
<blockquote>
{| class="wikitable"
{| class="wikitable"
|-
|-
| <code>sorbet/config</code> || config
| [[sorbet install]]
|-
|-
| <code>sorbet/rbi/shims/*.rbi</code> || add your own custom stubs
| [[sorbet usage]]
|-
|-
|}
| [[sorbet confguration]]
</blockquote><!-- Locations -->
 
= Usage =
<blockquote>
<source lang="bash">
bundle exec srb tc --help 2>&1 | less -Ri          # show help in less
bundle exec srb tc 2>&1 | grep -C5 ClassICareAbout  # check for errors in specific class
</source>
 
You can also use sorbet as an LSP.
<source lang="bash">
srb tc --lsp
</source>
 
Include <code>sig</code> by requiring <code>sorbet-runtime</code>
</blockquote><!-- Usage -->
 
= Configuration =
<blockquote>
== Disable sorbet-runtime ==
<blockquote>
You may want to temporarily disable sorbet-runtime for an executable, environment etc.
 
<syntaxhighlight lang="ruby">
require "sorbet-runtime"
T::Configuration.call_validation_error_handler = nil
</syntaxhighlight>
</blockquote><!-- Disable sorbet-runtime -->
</blockquote><!-- Configuration -->
 
= Basics =
<blockquote>
<source lang="ruby">
# person.rb
 
class Person
  def create(name:, age:, object:); end
  def speak; "foo"; end
end
</source>
 
<source lang="ruby">
# person.rbi
 
class Person
  extend T::Sig      # adds 'sig' method
  extend T::Helpers  # adds 'requires_ancestor, abstract!, interface!, sealed!, ...' methods
 
  sig { params(name: ::String, age: ::Integer, object: T.untyped).void }
  def create(name:, age:, object:); end
 
  sig { returns(String) }
  def speak; "foo"; end
end
</source>
</blockquote><!-- basics -->
 
= Common Cases =
<blockquote>
== attr_reader/writer/accessor ==
<blockquote>
<source lang="ruby">
sig { returns(String) }
attr_reader :name
</source>
</blockquote><!-- attr_reader/writer/accessor -->
 
== include module ==
<blockquote>
{| class="wikitable"
|-
|-
| require_ancestors || https://sorbet.org/docs/requires-ancestor
| [[sorbet syntax]]
|-
| mix_in_class_methods || https://sorbet.org/docs/abstract
|-
|-
|}
|}
 
</blockquote><!-- Notes -->
instance methods should just work
<source lang="ruby">
module AnimalMethods
  sig { returns(T.void) }
  def walk(); end
end
 
class Cat
  include AnimalMethods
end
</source>
 
class methods
<source lang="ruby">
module AnimalMethods
  extend T::Sig
  extend T::Helpers
 
  # modify to set classmethods on include
  def self.included(base = nil)
    base&.extend(ClassMethods)
  end
 
  # define classmethods
  module ClassMethods
    sig { returns(String) }
    def speak(); end
  end
 
  # inform sorbet of classmethods
  mixes_in_class_methods ClassMethods
end
 
class Cat
  include AnimalMethods
end
</source>
 
rails concerns && included do
<source lang="ruby">
 
</source>
</blockquote><!-- include module -->
 
== procs/lambdas ==
<blockquote>
<source lang="ruby">
sig { params(block: T.proc.params(arg0: Integer).void).void }
def foo(&block)
</source>
 
If your proc is designed to be executed in a different context<br>
(for example, proc is set as a class method, but designed to run on a class instance)<br>
you can use <code>T.bind(self, YourClass)</code>.
</blockquote><!-- procs/lambdas -->
</blockquote><!-- Common Cases -->
 
= Types =
<blockquote>
<source lang="ruby">
# stdlib types
String
Symbol
Integer
Float
NilClass
 
# generic types
T::Array[Integer]
T::Set[Integer]
T::Hash[Symbol, String]
T::Enumerable[Integer]
T::Enumerator[Integer]
T::Range[Integer]
 
# sorbet types
T::Boolean              # true/false
T.untyped              # anything
T.nilable(String)      # Unions: string or nil
T.any(String, Integer)  # Unions: either string or integer
T.noreturn              # if method never returns (exception, exit process, loop forever, ...)
 
sig { params(...).void }  # ignore return value, not meant to be used
</source>
</blockquote><!-- Types -->
 
= Generics =
<blockquote>
<source lang="ruby">
# a generic method, that takes param of arbitrary type 'T' and returns type 'T'
sig do
  type_parameters(:T)
    .params(var: T.type_parameter(:T))
    .returns(T.type_parameter(:T))
end
def foo(var)
  var
end
</source>
</blockquote><!-- Generics -->
 
= Tools =
<blockquote>
<source lang="ruby">
T.type_alias
T.bind(self, YourClass)              # use within proc, to indicate the instance it should be executed in (defaults to current)
T.cast(var, YourClass)
mixes_in_class_methods ClassMethods  # when class included, ClassMethods become static methods on target class
requires_ancestor Kernel            # any class that includes this module, must also include Kernel
</source>
</blockquote><!-- Tools -->
 
= Tricks =
<blockquote>
== Type Aliases ==
<blockquote>
You can define re-usable type-sigs with type aliases.
<source lang="ruby">
class University
  extend T::Sig
 
  StudentMap = T.type_alias { T::Hash[Symbol, String] }
 
  sig { params(student_map: StudentMap).returns(Integer) }
  def count_students(student_map)
    student_map.count
  end
 
  sig { params(student_map: StudentMap).returns(List[String]) }
  def name_students(student_map)
    student_map.keys()
  end
end
</source>
</blockquote><!-- Type Aliases -->
 
== Dynamically setting a Type Signature ==
<blockquote>
<source lang="ruby">
class Foo
  sig { params(a: Integer).void }
  def bar(a) = nil
end
 
T::Private::Methods.declare_sig(Foo, nil, :final) { params(a: String).void }
declaration = T::Private::DeclState.current.active_declaration
T::Private::Methods.run_sig(Foo, :bar, Foo.instance_method(:bar), declaration)
 
# voila! signature installed
T::Utils.signature_for_instance_method(Foo, :bar)
</source>
</blockquote><!-- copying a type signature -->
</blockquote><!-- Tricks -->

Latest revision as of 19:32, 4 November 2023

Implements static typing for ruby.
You may also be interested in ruby tapioca to automatically generate rbi files.

Documentation

homepage https://sorbet.org/
github https://github.com/sorbet/sorbet
gem src (no apidocs) https://github.com/sorbet/sorbet/tree/master/gems
sig documentation https://sorbet.org/docs/sigs

Notes

sorbet install
sorbet usage
sorbet confguration
sorbet syntax