What is a Scenario File?
masterscenario/ directory of the repository.repository·master·Indexed 21 days ago
https://github.com/ruby/typeprofAn experimental type-level Ruby interpreter for testing and understanding Ruby code through abstract interpretation. TypeProf tracks abstract values instead of concrete objects to observe method types and generate RBS definitions. It features a CLI for batch analysis, a Language Server Protocol (LSP) implementation for editor integration (including VSCode), and a scenario-based testing framework for verifying type inference correctness. Requires Ruby 3.3 or later.
scenario/ directory of the repository.To avoid confusion with standard Ruby values, TypeProf uses the term abstract values to describe the entities it handles during type-level execution.
TypeProf supports the following abstract values:
Foo.new returns the abstract value Foo). Note that literals like 42 are treated as instances of Integer.Integer). TypeProf does not abstract these to the Class type to ensure constant references and class methods are handled correctly.:foo). Unlike other objects, symbols are often handled by their concrete value to support use cases like keyword arguments or JSON keys.untyped: An abstract value used when TypeProf cannot trace a value due to analysis limits. Operations on untyped result in untyped.Integer | String).Array, Hash, and Enumerator.-> {... }) or block parameters (&blk). These are treated as concrete pieces of code and represented in RBS using anonymous proc types.To avoid losing precision, TypeProf uses "abstract values" instead of actual Ruby objects. Most values are abstracted to their class.
Supported abstract values include:
42 is an Integer instance). In RBS output, these are represented by the class name (e.g., Foo).Integer). These are not abstracted to Class to preserve constant references and class methods.:foo) are kept concrete. However, symbols generated via String#to_sym or interpolated symbols (e.g., :"foo_#{x}") are treated as the Symbol class.untyped: Used when TypeProf cannot track a value due to analysis limits. Operations on untyped result in untyped.Integer | String).Array, Hash, and Enumerator.TypeProf is an interpreter that executes Ruby programs at a type level. Instead of tracking actual object values, it tracks "abstract values" (primarily the classes the objects belong to).
Key behaviors:
p) under a # Revealed types section.Integer | String).def foo(n)
p n #=> Integer
n.to_s
end
p foo(42) #=> StringAnalysis Output Example:
# Revealed types
# test.rb:2 #=> Integer
# test.rb:6 #=> String
# Classes
class Object
def foo : (Integer) -> String
endTypeProf is a Ruby interpreter that performs abstract interpretation. Instead of executing code with concrete values (like the number 42), it executes the program at the type level using abstract values.
test.rb:2 #=> Integer).If a class Foo has an accessor a, and one instance sets a to an Integer while another sets it to a String, TypeProf reveals the type as a union:
class Foo
def initialize
@a = 42
end
attr_accessor :a
end
Foo.new.a = "str"
p Foo.new.a #=> Integer | StringOutput:
# Revealed types
# test.rb:11 #=> Integer | String
# Classes
class Foo
attr_accessor a : Integer | String
def initialize : -> Integer
endScenario files use specific section headers to define input, expectations, and diagnostic requirements.
A minimal file requires two sections:
## update: Contains the input Ruby code.## assert: Contains the expected type signatures written in RBS syntax.You can chain multiple ## update and ## assert pairs within a single file to test how TypeProf handles sequential code changes or different implementation variations.
To verify that TypeProf correctly identifies type errors, use the ## diagnostics section. This section should contain the expected error messages and their locations in the format (line,column)-(line,column): error_message.
## update
def foo(n)
n.to_s
end
foo(42)
## assert
class Object
def foo: (Integer) -> String
end
## diagnostics
(5,0)-(5,3): wrong number of arguments (2 for 1)To run the entire suite of scenario tests, use the Rake task.
$ bundle exec rake testWhen reporting a bug, follow these steps to ensure the maintainers can reproduce and fix the issue:
ruby tool/scenario_runner.rb your_scenario.rb to confirm it fails as expected.typeprof --version).To use TypeProf within VSCode for type-level Ruby interpretation:
code --install-extension mame.ruby-typeproftypeprof --init in your project root. This creates a typeprof.conf.jsonc configuration file.$ typeprof --initInstall the TypeProf gem using the standard RubyGems command.
$ gem install typeprofRun typeprof --init in your project root to generate a typeprof.conf.jsonc file. This file is used to configure TypeProf's behavior. For detailed configuration options, refer to the typeprof.conf.jsonc file template.
$ typeprof --init