A Ruby code formatter written in Rust
Installation • Usage • Features • Editor Integration • Documentation • Contributing
What is rfmt?
RubyGems reference DeepWiki rfmt
rfmt is a Ruby code formatter that enforces consistent style across your codebase. Key characteristics:
- Opinionated: Minimal configuration with consistent output
- Idempotent: Running multiple times produces identical results
- Comment preservation: Maintains existing comment placement
- Rust implementation: Core formatter implemented in Rust
Features
Performance
Built with Rust for improved execution speed. See Performance Benchmarks section for details.
Consistent Style
Enforces code style rules:
- Automatic indentation
- Spacing and alignment normalization
- Quote style standardization
- Method definition formatting
Performance
rfmt delivers consistent, fast formatting across projects of any size:
| Project Size | Files | Execution Time | Throughput |
|---|---|---|---|
| Small | 9 files | ~105ms | 85 files/sec |
| Medium | 35 files | ~110ms | 315 files/sec |
| Large | 151 files | ~100ms | 1,560 files/sec |
Key Performance Characteristics:
- Constant Time: Execution time stays around 100ms regardless of project size
- Parallel Processing: Automatic scaling with available CPU cores
- High Throughput: Up to 1,500+ files per second on large projects
- Low Overhead: Minimal startup time and memory usage
Test Environment:
- CPU: Apple Silicon (arm64)
- Ruby: 3.4.8
- Average of 5 runs per test
Built with Rust for optimal performance and memory efficiency.
For detailed performance comparisons and benchmarks, see Performance Benchmarks.
Installation
Requirements
- Ruby 3.0 or higher
- Rust 1.70 or higher (for building from source)
From RubyGems
In Your Gemfile
Then run:
From Source
git clone https://github.com/fs0414/rfmt.git cd rfmt bundle install bundle exec rake compile
Usage
Initialize Configuration
First, create a configuration file with default settings:
This creates a .rfmt.yml file with default settings:
version: "1.0" formatting: line_length: 100 # Maximum line length (40-500) indent_width: 2 # Spaces/tabs per indent (1-8) indent_style: "spaces" # "spaces" or "tabs" quote_style: "double" # "double", "single", or "consistent" include: - "**/*.rb" - "**/*.rake" - "**/Rakefile" - "**/Gemfile" exclude: - "vendor/**/*" - "tmp/**/*" - "node_modules/**/*" - "db/schema.rb"
Options:
# Specify custom path rfmt init --path config/.rfmt.yml # Overwrite existing configuration rfmt init --force
Command Line
Format a single file:
Format multiple files:
Format all files in your project:
Check if files need formatting (CI/CD):
Show diff without modifying files:
Quiet mode (minimal output):
Enable verbose output for debugging:
rfmt --verbose lib/user.rb
Common Options
| Option | Description |
|---|---|
--check |
Check formatting without writing files |
--diff |
Show diff of changes |
--quiet |
Minimal output |
--verbose |
Detailed output with timing |
Output Modes
Normal mode (default):
$ rfmt app/ Processing 25 file(s)... ✓ Formatted app/controllers/users_controller.rb ✓ Formatted app/models/user.rb ✓ Processed 25 files (3 formatted, 22 unchanged)
Quiet mode (--quiet or -q):
$ rfmt --quiet app/ ✓ 3 files formatted
Verbose mode (--verbose or -v):
$ rfmt --verbose app/
Processing 25 file(s)...
Using sequential processing for 25 files
✓ Formatted app/controllers/users_controller.rb
✓ app/models/application_record.rb already formatted
...
✓ Processed 25 files
(3 formatted, 22 unchanged)
Details:
Total files: 25
Total time: 0.45s
Files/sec: 55.6Parallel Processing
rfmt automatically chooses the optimal processing mode:
- < 20 files: Sequential processing (fastest for small batches)
- 20-49 files: Automatic based on average file size
- ≥ 50 files: Parallel processing (utilizes multiple cores)
You can override this behavior:
# Force parallel processing rfmt --parallel app/ # Force sequential processing rfmt --no-parallel app/
Cache Management
rfmt uses caching to improve performance on large codebases:
# Clear cache if needed rfmt cache clear # View cache statistics rfmt cache stats
Ruby API
Input (unformatted code):
require 'rfmt' source = <<~RUBY class User def initialize(name) @name=name end end RUBY formatted = Rfmt.format(source) puts formatted
Output (formatted code):
class User def initialize(name) @name=name end end
Configuration
Configuration File Discovery
rfmt automatically searches for configuration files in this order:
- Current directory (
.rfmt.yml,.rfmt.yaml,rfmt.yml, orrfmt.yaml) - Parent directories (up to root)
- User home directory (
.rfmt.yml,.rfmt.yaml,rfmt.yml, orrfmt.yaml) - Default settings (if no file found)
Ruby API for Configuration
require 'rfmt' # Generate configuration file Rfmt::Config.init('.rfmt.yml', force: false) # Find configuration file config_path = Rfmt::Config.find # => "/Users/username/project/.rfmt.yml" # Check if configuration exists Rfmt::Config.exists? # => true # Load configuration config = Rfmt::Config.load # => {"version"=>"1.0", "formatting"=>{"line_length"=>100, ...}, ...}
Examples
Before Formatting
class User<ApplicationRecord has_many :posts validates :email,presence: true def full_name "#{first_name} #{last_name}" end end
After Formatting
class User < ApplicationRecord has_many :posts validates :email, presence: true def full_name "#{first_name} #{last_name}" end end
Editor Integration
rfmt integrates with editors through Ruby LSP. For detailed setup instructions, see Editor Integration Guide.
VSCode (Quick Start)
- Install Ruby LSP extension
- Add to your
settings.json:
{
"rubyLsp.formatter": "rfmt",
"editor.formatOnSave": true,
"[ruby]": {
"editor.defaultFormatter": "Shopify.ruby-lsp"
}
}Neovim
require("lspconfig").ruby_lsp.setup({ init_options = { formatter = "rfmt" } })
See Editor Integration Guide for Helix, Emacs, Sublime Text, and more.
Development
Setup
After cloning the repository:
bundle install
bundle exec lefthook installGit Hooks
This project uses lefthook for automated validation before push:
Pre-push checks:
- RuboCop (Ruby linting)
- cargo fmt --check (Rust formatting)
- cargo clippy (Rust linting)
Skip hooks temporarily:
# Skip all hooks for this push LEFTHOOK=0 git push # Skip specific hook LEFTHOOK_EXCLUDE=rubocop git push
Running Tests
# Ruby tests bundle exec rspec # Rust tests cargo test --manifest-path ext/rfmt/Cargo.toml # All tests bundle exec rake dev:test_all
Documentation
Documentation is available in the docs directory:
- User Guide - Comprehensive usage guide
- Error Reference - Error codes and troubleshooting
- Contributing Guide - How to contribute
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Comparison with Other Tools
rfmt vs RuboCop
| Feature | rfmt | RuboCop |
|---|---|---|
| Primary Purpose | Code formatting | Linting + formatting |
| Configuration | Minimal | Extensive |
| Code Quality Checks | No | Yes |
| Bug Detection | No | Yes |
Note: rfmt focuses on code formatting, while RuboCop provides additional code quality analysis. They can be used together.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the rfmt project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
Support
- 📖 Documentation
- 🐛 Issues
- 📧 Email: fujitanisora0414@gmail.com
Acknowledgments
- Built with Prism - Modern Ruby parser
- Powered by Rust - Performance and safety
- FFI via Magnus - Ruby-Rust bridge