rfmt 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Cargo.lock +1 -1
- data/README.md +59 -158
- data/ext/rfmt/Cargo.toml +1 -1
- data/ext/rfmt/src/emitter/mod.rs +20 -4
- data/lib/rfmt/rfmt.so +0 -0
- data/lib/rfmt/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a9981b614b859c7c49e597686b89c79279ba977911b9a62d691aa0b88408eb0f
|
|
4
|
+
data.tar.gz: 1461e9bcf3ff3b298855963fdf2e6cdd0aca1b3e29bf6f5b9037e62889903469
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b6aa80fa2df44397d1bdc81a12b860e1446a611f565e3283af8a821e691ca5122041f9622d48e2577740e878d740a1dba95df0a8c6acbea71c8301993f6fb46
|
|
7
|
+
data.tar.gz: a1f330f17114d738523adf1fdcc9ccc42590b028a754e32304d2d4724f9966d54e5a7467bd50c8884111bc3ff16780b9b9c7591a0a22d8cd1eb17ffa50a856ed
|
data/CHANGELOG.md
CHANGED
data/Cargo.lock
CHANGED
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A Ruby code formatter written in Rust
|
|
6
6
|
|
|
7
7
|
[](https://badge.fury.io/rb/rfmt)
|
|
8
8
|
[](https://github.com/fujitanisora/rfmt/actions)
|
|
@@ -20,54 +20,54 @@
|
|
|
20
20
|
|
|
21
21
|
## What is rfmt?
|
|
22
22
|
|
|
23
|
-
**rfmt** is a
|
|
23
|
+
**rfmt** is a Ruby code formatter that enforces consistent style across your codebase. Key characteristics:
|
|
24
24
|
|
|
25
|
-
- **
|
|
26
|
-
- **Opinionated**: Minimal configuration
|
|
27
|
-
- **Idempotent**: Running
|
|
28
|
-
- **Comment
|
|
29
|
-
- **
|
|
25
|
+
- **Rust implementation**: Provides faster execution than Ruby-based tools
|
|
26
|
+
- **Opinionated**: Minimal configuration with consistent output
|
|
27
|
+
- **Idempotent**: Running multiple times produces identical results
|
|
28
|
+
- **Comment preservation**: Maintains existing comment placement
|
|
29
|
+
- **Error handling**: Includes structured error messages and logging
|
|
30
30
|
|
|
31
31
|
## Features
|
|
32
32
|
|
|
33
|
-
###
|
|
33
|
+
### Performance
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Built with Rust for improved execution speed:
|
|
36
36
|
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
37
|
+
- Benchmark shows 7-58x faster than RuboCop depending on project size (see Performance Benchmarks section)
|
|
38
|
+
- Processes 168 files/second in tested Rails project
|
|
39
|
+
- Supports parallel processing
|
|
40
40
|
|
|
41
|
-
###
|
|
41
|
+
### Consistent Style
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Enforces code style rules:
|
|
44
44
|
|
|
45
45
|
- Automatic indentation
|
|
46
|
-
-
|
|
47
|
-
- Quote style
|
|
46
|
+
- Spacing and alignment normalization
|
|
47
|
+
- Quote style standardization
|
|
48
48
|
- Method definition formatting
|
|
49
49
|
|
|
50
|
-
###
|
|
50
|
+
### Error Handling
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
Provides structured error messages:
|
|
53
53
|
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
54
|
+
- Error codes (E001-E999) for categorization
|
|
55
|
+
- Code snippets showing error locations
|
|
56
|
+
- Help URLs linking to documentation
|
|
57
|
+
- Recovery strategies for handling errors
|
|
58
58
|
|
|
59
|
-
###
|
|
59
|
+
### Logging
|
|
60
60
|
|
|
61
|
-
Built-in logging system
|
|
61
|
+
Built-in logging system:
|
|
62
62
|
|
|
63
|
-
-
|
|
64
|
-
- Structured output
|
|
65
|
-
- Performance metrics and timing
|
|
66
|
-
- Debug context
|
|
63
|
+
- 5 log levels (ERROR, WARN, INFO, DEBUG, TRACE)
|
|
64
|
+
- Structured output format
|
|
65
|
+
- Performance metrics and timing data
|
|
66
|
+
- Debug context information
|
|
67
67
|
|
|
68
|
-
###
|
|
68
|
+
### Editor Integration
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
Compatible editors:
|
|
71
71
|
|
|
72
72
|
- Visual Studio Code
|
|
73
73
|
- RubyMine / IntelliJ IDEA
|
|
@@ -168,7 +168,7 @@ Create a configuration file with default settings:
|
|
|
168
168
|
rfmt init
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
This creates a `.rfmt.yml` file with
|
|
171
|
+
This creates a `.rfmt.yml` file with default settings:
|
|
172
172
|
|
|
173
173
|
```yaml
|
|
174
174
|
version: "1.0"
|
|
@@ -234,7 +234,7 @@ config = Rfmt::Config.load
|
|
|
234
234
|
|
|
235
235
|
## Error Handling
|
|
236
236
|
|
|
237
|
-
rfmt provides
|
|
237
|
+
rfmt provides structured error messages:
|
|
238
238
|
|
|
239
239
|
```
|
|
240
240
|
[Rfmt::ParseError] Parse error in app/models/user.rb:15:10
|
|
@@ -269,7 +269,7 @@ See the [Error Reference](docs/error_reference.md) for detailed information.
|
|
|
269
269
|
|
|
270
270
|
## Logging
|
|
271
271
|
|
|
272
|
-
rfmt includes a
|
|
272
|
+
rfmt includes a logging system:
|
|
273
273
|
|
|
274
274
|
```ruby
|
|
275
275
|
# Logs are automatically output during initialization
|
|
@@ -312,118 +312,45 @@ class User < ApplicationRecord
|
|
|
312
312
|
end
|
|
313
313
|
```
|
|
314
314
|
|
|
315
|
-
##
|
|
316
|
-
|
|
317
|
-
Comprehensive documentation is available:
|
|
318
|
-
|
|
319
|
-
- 📖 [User Guide](docs/user_guide.md) - Complete usage guide
|
|
320
|
-
- 🌐 [User Guide (日本語)](docs/user_guide.ja.md) - Japanese version
|
|
321
|
-
- 🔍 [Error Reference](docs/error_reference.md) - All error codes and solutions
|
|
322
|
-
- 🔍 [Error Reference (日本語)](docs/error_reference.ja.md) - Japanese version
|
|
323
|
-
- 🤝 [Contributing Guide](CONTRIBUTING.md) - How to contribute
|
|
324
|
-
- 📊 [Phase 4 Implementation](docs/phase4_implementation_summary.md) - Recent changes
|
|
325
|
-
|
|
326
|
-
## Development
|
|
327
|
-
|
|
328
|
-
After checking out the repo:
|
|
315
|
+
## Performance Benchmarks
|
|
329
316
|
|
|
330
|
-
|
|
331
|
-
# Install dependencies
|
|
332
|
-
bundle install
|
|
333
|
-
|
|
334
|
-
# Compile Rust extension
|
|
335
|
-
bundle exec rake compile
|
|
317
|
+
Performance comparison with RuboCop on a Rails project (111 files, 3,231 lines):
|
|
336
318
|
|
|
337
|
-
|
|
338
|
-
bundle exec rspec
|
|
339
|
-
|
|
340
|
-
# Run Rust tests
|
|
341
|
-
cd ext/rfmt && cargo test
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
### Running Tests
|
|
345
|
-
|
|
346
|
-
```bash
|
|
347
|
-
# All tests
|
|
348
|
-
bundle exec rspec
|
|
349
|
-
|
|
350
|
-
# Specific test file
|
|
351
|
-
bundle exec rspec spec/error_handling_spec.rb
|
|
352
|
-
|
|
353
|
-
# With documentation format
|
|
354
|
-
bundle exec rspec --format documentation
|
|
355
|
-
```
|
|
319
|
+
### Benchmark Results (Rails Project)
|
|
356
320
|
|
|
357
|
-
|
|
321
|
+
| Scenario | rfmt | RuboCop | Speedup |
|
|
322
|
+
|----------|------|---------|---------|
|
|
323
|
+
| **Single File** | ~190ms | ~1.35s | **7.3x faster** |
|
|
324
|
+
| **Directory (14 files)** | 168ms | 1.67s | **10.0x faster** |
|
|
325
|
+
| **Full Project (111 files)** | 173ms | 10.09s | **58.5x faster** |
|
|
326
|
+
| **Check Mode (CI/CD)** | 172ms | 1.55s | **9.0x faster** |
|
|
358
327
|
|
|
359
|
-
|
|
360
|
-
- 172 existing tests
|
|
361
|
-
- 15 new tests for error handling and logging
|
|
328
|
+
### Key Metrics
|
|
362
329
|
|
|
363
|
-
|
|
330
|
+
- Single file: Formats in ~190ms
|
|
331
|
+
- Scaling: 58x faster on full project (111 files)
|
|
332
|
+
- CI/CD: Check time reduced from 10.09s to 0.173s (98% reduction)
|
|
333
|
+
- Variance: Low standard deviation across runs
|
|
364
334
|
|
|
365
|
-
|
|
335
|
+
### Throughput Comparison
|
|
366
336
|
|
|
367
|
-
|
|
|
368
|
-
|
|
369
|
-
|
|
|
370
|
-
| 1
|
|
371
|
-
| 10,000 lines | < 500ms |
|
|
337
|
+
| Directory | rfmt | RuboCop | Difference |
|
|
338
|
+
|-----------|------|---------|------------|
|
|
339
|
+
| app/models (14 files) | 83.5 files/s | 8.4 files/s | **10x throughput** |
|
|
340
|
+
| test/ (30 files) | 168.1 files/s | 18.1 files/s | **9.3x throughput** |
|
|
372
341
|
|
|
373
|
-
*
|
|
342
|
+
*Benchmark environment: Apple Silicon (arm64), macOS Darwin 23.6.0, Ruby 3.4.5*
|
|
374
343
|
|
|
375
|
-
|
|
344
|
+
See [detailed benchmark report](docspriv/benchmark_report.md) for full data.
|
|
376
345
|
|
|
377
|
-
|
|
346
|
+
## Documentation
|
|
378
347
|
|
|
379
|
-
|
|
380
|
-
- [ ] Numbered parameters
|
|
381
|
-
- [ ] Additional formatting rules
|
|
382
|
-
- [ ] Plugin system
|
|
383
|
-
- [ ] Language server protocol (LSP)
|
|
348
|
+
Documentation is available in the [docs](docs/) directory. See [User Guide](docs/user_guide.md) or [Contributing Guide](CONTRIBUTING.md) for details.
|
|
384
349
|
|
|
385
350
|
## Contributing
|
|
386
351
|
|
|
387
352
|
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
388
353
|
|
|
389
|
-
**Quick Start:**
|
|
390
|
-
|
|
391
|
-
1. Fork the repository
|
|
392
|
-
2. Create your feature branch (`git checkout -b feature/my-feature`)
|
|
393
|
-
3. Make your changes and add tests
|
|
394
|
-
4. Run tests (`bundle exec rspec`)
|
|
395
|
-
5. Commit your changes (`git commit -m 'feat: add some feature'`)
|
|
396
|
-
6. Push to the branch (`git push origin feature/my-feature`)
|
|
397
|
-
7. Open a Pull Request
|
|
398
|
-
|
|
399
|
-
## Architecture
|
|
400
|
-
|
|
401
|
-
rfmt is built with a hybrid Ruby-Rust architecture:
|
|
402
|
-
|
|
403
|
-
```
|
|
404
|
-
┌─────────────────┐
|
|
405
|
-
│ Ruby Layer │ ← User API, Prism parser
|
|
406
|
-
├─────────────────┤
|
|
407
|
-
│ FFI Interface │ ← Magnus (Ruby-Rust bridge)
|
|
408
|
-
├─────────────────┤
|
|
409
|
-
│ Rust Layer │ ← Formatting engine
|
|
410
|
-
│ │ - Parser (AST)
|
|
411
|
-
│ │ - Formatter (Rules)
|
|
412
|
-
│ │ - Emitter (Output)
|
|
413
|
-
│ │ - Error Handler
|
|
414
|
-
│ │ - Logger
|
|
415
|
-
└─────────────────┘
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
## Technology Stack
|
|
419
|
-
|
|
420
|
-
- **Ruby**: 3.0+ (Prism parser, FFI interface)
|
|
421
|
-
- **Rust**: 1.70+ (Core formatting engine)
|
|
422
|
-
- **Magnus**: Ruby-Rust FFI bridge
|
|
423
|
-
- **Prism**: Modern Ruby parser
|
|
424
|
-
- **RSpec**: Ruby testing
|
|
425
|
-
- **Cargo**: Rust build system
|
|
426
|
-
|
|
427
354
|
## Comparison with Other Tools
|
|
428
355
|
|
|
429
356
|
### rfmt vs RuboCop
|
|
@@ -431,36 +358,12 @@ rfmt is built with a hybrid Ruby-Rust architecture:
|
|
|
431
358
|
| Feature | rfmt | RuboCop |
|
|
432
359
|
|---------|------|---------|
|
|
433
360
|
| **Primary Purpose** | Code formatting | Linting + formatting |
|
|
434
|
-
| **Speed** |
|
|
361
|
+
| **Speed** | 58x faster (tested benchmark) | Ruby-based |
|
|
435
362
|
| **Configuration** | Minimal | Extensive |
|
|
436
363
|
| **Code Quality Checks** | No | Yes |
|
|
437
364
|
| **Bug Detection** | No | Yes |
|
|
438
365
|
|
|
439
|
-
**
|
|
440
|
-
|
|
441
|
-
### rfmt vs Prettier (Ruby plugin)
|
|
442
|
-
|
|
443
|
-
| Feature | rfmt | Prettier |
|
|
444
|
-
|---------|------|----------|
|
|
445
|
-
| **Native Ruby Support** | Yes | Via plugin |
|
|
446
|
-
| **Speed** | Very fast | Fast |
|
|
447
|
-
| **Ruby-specific Features** | Full support | Limited |
|
|
448
|
-
| **Comment Preservation** | Excellent | Good |
|
|
449
|
-
|
|
450
|
-
## Project Status
|
|
451
|
-
|
|
452
|
-
rfmt is under active development. Current phase:
|
|
453
|
-
|
|
454
|
-
- ✅ Phase 1: Foundation (Complete)
|
|
455
|
-
- ✅ Phase 2: Core Formatting (Complete)
|
|
456
|
-
- ✅ Phase 3: Advanced Features (Complete)
|
|
457
|
-
- ✅ Phase 4: Production Quality (Logging & Error Control Complete)
|
|
458
|
-
- ✅ Error Handling System
|
|
459
|
-
- ✅ Logging System
|
|
460
|
-
- ⬜ Documentation (In Progress)
|
|
461
|
-
- ⬜ Security
|
|
462
|
-
- ⬜ Release Process
|
|
463
|
-
- ⬜ Editor Integration
|
|
366
|
+
**Note**: rfmt focuses on formatting speed, while RuboCop provides additional code quality analysis. They can be used together.
|
|
464
367
|
|
|
465
368
|
## License
|
|
466
369
|
|
|
@@ -487,8 +390,6 @@ Everyone interacting in the rfmt project's codebases, issue trackers, chat rooms
|
|
|
487
390
|
|
|
488
391
|
<div align="center">
|
|
489
392
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
**⭐ Star us on GitHub — it motivates us a lot!**
|
|
393
|
+
Created by [Fujitani Sora](https://github.com/fs0414)
|
|
493
394
|
|
|
494
395
|
</div>
|
data/ext/rfmt/Cargo.toml
CHANGED
data/ext/rfmt/src/emitter/mod.rs
CHANGED
|
@@ -123,9 +123,17 @@ impl Emitter {
|
|
|
123
123
|
for (i, child) in node.children.iter().enumerate() {
|
|
124
124
|
self.emit_node(child, indent_level)?;
|
|
125
125
|
|
|
126
|
-
// Add
|
|
126
|
+
// Add newlines between top-level statements, normalizing to max 1 blank line
|
|
127
127
|
if i < node.children.len() - 1 {
|
|
128
|
-
|
|
128
|
+
let current_end_line = child.location.end_line;
|
|
129
|
+
let next_start_line = node.children[i + 1].location.start_line;
|
|
130
|
+
let line_diff = next_start_line.saturating_sub(current_end_line);
|
|
131
|
+
|
|
132
|
+
// Add 1 newline if consecutive, 2 newlines (1 blank line) if there was a gap
|
|
133
|
+
let newlines = if line_diff > 1 { 2 } else { 1 };
|
|
134
|
+
for _ in 0..newlines {
|
|
135
|
+
self.buffer.push('\n');
|
|
136
|
+
}
|
|
129
137
|
}
|
|
130
138
|
}
|
|
131
139
|
Ok(())
|
|
@@ -136,9 +144,17 @@ impl Emitter {
|
|
|
136
144
|
for (i, child) in node.children.iter().enumerate() {
|
|
137
145
|
self.emit_node(child, indent_level)?;
|
|
138
146
|
|
|
139
|
-
// Add
|
|
147
|
+
// Add newlines between statements, normalizing to max 1 blank line
|
|
140
148
|
if i < node.children.len() - 1 {
|
|
141
|
-
|
|
149
|
+
let current_end_line = child.location.end_line;
|
|
150
|
+
let next_start_line = node.children[i + 1].location.start_line;
|
|
151
|
+
let line_diff = next_start_line.saturating_sub(current_end_line);
|
|
152
|
+
|
|
153
|
+
// Add 1 newline if consecutive, 2 newlines (1 blank line) if there was a gap
|
|
154
|
+
let newlines = if line_diff > 1 { 2 } else { 1 };
|
|
155
|
+
for _ in 0..newlines {
|
|
156
|
+
self.buffer.push('\n');
|
|
157
|
+
}
|
|
142
158
|
}
|
|
143
159
|
}
|
|
144
160
|
Ok(())
|
data/lib/rfmt/rfmt.so
CHANGED
|
Binary file
|
data/lib/rfmt/version.rb
CHANGED