I run docscribe daily on client Rails apps. I cannot share that code, so every example below is synthetic and verified against docscribe 1.6.2 on Ruby 3.4.5.
Comments lie
This is the shape I keep finding:
# @param [String] count
# @return [String]
def notify(verbose:, count:)
puts "verbose!" if verbose # Boolean
count.times { send_ping } # Integer
count # Integer
end
The comment says two Strings in, one String out. The code takes a flag and a count and returns the count. Anyone who trusts the comment calls it wrong: "false" is truthy, and "3" has no times method.
What docscribe -a actually does
Safe mode adds what is missing and leaves the rest alone. On the file above:
$ docscribe -a notify_demo.rb
# @param [String] count
# @param [Object] verbose Param documentation.
# @return [String]
def notify(verbose:, count:)
puts "verbose!" if verbose
count.times { send_ping }
count
end
It added the missing @param verbose. It did not touch the lying String tags. That is the contract: safe mode never rewrites a type you wrote. -A rebuilds the block from scratch; I always git diff after it.
Where types really get fixed
Type correction lives in update_types, fed by RBS. Given this signature:
class Object
def notify: (bool verbose, Integer count) -> Integer
end
this command:
$ docscribe update_types --rbs --sig-dir sig notify.rb
produces:
# @param [Boolean] verbose
# @param [Integer] count
# @return [Integer]
def notify(verbose:, count:)
puts "verbose!" if verbose
count.times { send_ping }
count
end
No prose placeholders here because the original had no descriptions to keep. When descriptions exist, update_types keeps them.
The reverse direction exists too: docscribe rbs generates .rbs from YARD. Types flow both ways, YARD stays the human-readable cache in the middle.
source: tells the editor which fix to offer
Every change in 1.6.2 carries source: rbs | infer | syntax through JSON, SARIF, and daemon responses. The IDE uses it to pick the right lightbulb: rbs offers "Update types", anything else offers "Fix YARD". That one field is what makes the VS Code and RubyMine plugins feel fast instead of noisy.
Rails specifics I use daily
Types from schema.rb, not from code. t.boolean :is_admin becomes @!attribute [r] is_admin returning Boolean in the model, via the collector plugin in examples/plugins. No hand-written docs for columns.
One daemon per project serves both editor plugins over a Unix socket JSON-RPC (check, fix, check_batch, update_types, ping). When the daemon is off, the plugins fall back to CLI. CI mode runs on exit codes (0 clean, 1 missing docs, 2 errors) plus check_for_comments, with json/sarif output.
- Live demo and install: https://unurgunite.github.io/docscribe
- Source: https://github.com/unurgunite/docscribe
- Gem: https://rubygems.org/gems/docscribe
Next in 1.7.0
docscribe sorbet - same YARD to signature flow as docscribe rbs, but generating .rbi/sig blocks for srb tc. Plus validate_types on by default (opt-out with --no-validate-types). Plus tighter metaprogramming support: better types for define_method and DSL-generated methods, less Object fallback.
Limits
Heuristics, not a prover, so metaprogramming lands in Object today. Each release narrows that gap.
Question I keep asking: do you keep YARD and RBS in sync by hand, or did you give up on one of them?


Top comments (0)