Yarbs
This is retied. Use Inline RBS
Generate RBS type signatures from your existing YARD documentation.
Most Ruby projects that adopt RBS end up writing types twice: once as
@param/@return comments for humans, and again as .rbs files for the
type checker. yarbs closes that gap. It uses rbs prototype rb to work out
the real structure of your code (arity, visibility, attr_*, mixins,
inheritance — all parsed straight from your source, not guessed), then
reads the YARD docs you've already written to fill in the types, and
writes the result to sig/.
class Greeter
# @param name [String] the person's name
# @param count [Integer, nil] how many times to greet
# @return [Boolean] whether it worked
def greet(name, count: nil)
true
end
end$ yarbs "lib/**/*.rb"
wrote sig/greeter.rbsclass Greeter
def greet: (String name, ?count: Integer | nil) -> bool
endNo YARD tag for a given parameter or return value? It's just left untyped
— nothing breaks, and everything else in the signature still gets its real
type.
Installation
Install the gem and add it to the application's Gemfile by executing:
bundle add yarbsIf bundler is not being used to manage dependencies, install the gem by executing:
gem install yarbsGetting started
In your project, run:
bundle exec yarbs init create .yarbs.yml
create Steepfile
create rbs_collection.yaml
update .gitignore (added /.gem_rbs_collection/)
run rbs collection install
wrote 23 files to sig/
This sets up everything needed to type-check against the generated signatures:
-
.yarbs.yml— which files yarbs reads and where it writes (see Configuration) -
Steepfile— a Steep target that checks your sources againstsig/, with lenient diagnostics to start with, since most code staysuntypeduntil it's documented -
rbs_collection.yaml— so Steep gets signatures for the gems you depend on;initthen runsrbs collection installto fetch them (skip that with--no-install) -
.gitignore— ignores the downloaded.gem_rbs_collection/, and, for a gem (a project with a*.gemspec),rbs_collection.lock.yamltoo; an app should commit that lock file, just likeGemfile.lock
Then it generates your signatures for the first time.
It's safe to re-run: init never overwrites a file that already exists (it
reports it as skipped), and only adds the .gitignore entries that are
missing. Use --dry-run to see what it would do first. By default it sets
yarbs up for lib/**/*.rb; pass your own globs to change that
(yarbs init "lib/**/*.rb" "src/**/*.rb").
If Steep isn't in your bundle yet, init finishes by telling you to add it:
bundle add steep --group development
bundle exec steep checkUsage
Run yarbs to regenerate your signatures. It writes one .rbs file per
source file into sig/, mirroring the source layout with a leading
lib//app/ stripped. Without arguments it uses the paths in
.yarbs.yml; give it glob patterns to override them:
yarbs
yarbs "lib/**/*.rb" "app/**/*.rb"Other flags:
-
-o,--output DIR— write intoDIRinstead ofsig/ -
-w,--watch— regenerate automatically whenever a matched file changes (built on listen); handy to run alongside your editor while developing -
-s,--strict— raise instead of silently falling back tountypedwhen a YARD type can't be converted or a file has invalid syntax (not combinable with--watch, since a strict watcher would crash on every keystroke mid-edit)
It's also available as a plain Ruby API:
require "yarbs"
Yarbs.generate(["lib/**/*.rb"], output_dir: "sig", strict: true)Configuration
.yarbs.yml (written by yarbs init) holds the defaults for a plain
yarbs run. Anything passed on the command line overrides it:
# Glob patterns for the Ruby files to generate signatures for.
paths:
- "lib/**/*.rb"
# Directory the generated .rbs files are written into.
output: sig
# Raise instead of falling back to `untyped` when a YARD type can't
# be converted. Ignored by `yarbs --watch`.
strict: falseWithout a .yarbs.yml, yarbs uses these same defaults.
Docs
For the full picture of what yarbs understands and how to document it — worked examples generated by actually running the tool, not hand-written — see:
-
docs/param.md —
@param, including*args,**kwargs, and@option(typed as an RBS record) -
docs/return.md —
@return, includingvoidand the#initializespecial case -
docs/blocks.md —
yield/&block(@yieldparam/@yieldreturn), and typing aProc/lambda parameter -
docs/classes.md — classes, modules, nesting,
inheritance, mixins,
attr_*, constants, and visibility -
docs/deprecated.md —
@deprecated, turned into%a{deprecated}so Steep warns wherever deprecated code is used
Development
After checking out the repo, run bundle install, then
bundle exec rbs collection install to fetch the RBS signatures Steep needs
for yarbs' own dependencies. From there:
-
bundle exec rakeruns the full check: tests (rake test), lint (rake standard), and type checking (rake steep) -
bundle exec exe/yarbs "lib/**/*.rb" -o sigregenerates yarbs' ownsig/from its own docs (it's self-hosting)
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/tobidelius/yarbs.
License
The gem is available as open source under the terms of the MIT License.