rfmt 0.2.1 → 0.2.3
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 +18 -0
- data/Cargo.lock +1 -1
- data/README.md +67 -177
- data/ext/rfmt/Cargo.toml +1 -1
- data/ext/rfmt/src/config/mod.rs +38 -3
- data/ext/rfmt/src/emitter/mod.rs +20 -4
- data/ext/rfmt/src/error/mod.rs +0 -2
- data/ext/rfmt/src/lib.rs +2 -1
- data/lib/rfmt/configuration.rb +1 -1
- data/lib/rfmt/rfmt.so +0 -0
- data/lib/rfmt/version.rb +1 -1
- data/lib/rfmt.rb +4 -4
- 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: c712093f002557a29995a2838caede692a26e86d492c7f9f735e8fe9f2a5f5f4
|
|
4
|
+
data.tar.gz: a7ce48fbf06a56879d803cb848786310ff5e6dc091de1d8f8a9ff47a0bb00dac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '05954d426b7b6951e330d55d469ea78ebbf75350d755e0107eb0c4de32f5b11afd9373fbeabff3f7c2c902cfada70f4fae276c8b5d0d4d3b00eb3514a467fa0e'
|
|
7
|
+
data.tar.gz: cd4b6992cd4d795dfe8bd91f74504212337bcf7c13c736822919a071abda7ff0e1712f24e277786fa8b9a3ba6150b0727d33f415631c1707b6277c5612c94dbe
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.2.3] - 2025-01-25
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Configuration file (rfmt.yml) is now automatically loaded and applied during formatting
|
|
7
|
+
- Automatic config file discovery in current directory, parent directories, and home directory
|
|
8
|
+
- Support for custom indent_width and other formatting options via rfmt.yml
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Default config file name changed from .rfmt.yml to rfmt.yml (hidden file to regular file)
|
|
12
|
+
- Backward compatibility maintained: .rfmt.yml is still supported with lower priority
|
|
13
|
+
- Config file search order: rfmt.yml > rfmt.yaml > .rfmt.yml > .rfmt.yaml
|
|
14
|
+
- README updated to remove exaggerated expressions and focus on factual, data-driven descriptions
|
|
15
|
+
|
|
16
|
+
## [0.2.2] - 2025-01-25
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- Fixed blank line formatting to output single blank line instead of double blank lines
|
|
20
|
+
|
|
3
21
|
## [0.2.1] - 2025-01-25
|
|
4
22
|
|
|
5
23
|
### Fixed
|
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,60 +20,81 @@
|
|
|
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
|
+
## Performance Benchmarks
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
Performance comparison with RuboCop on a Rails project (111 files, 3,231 lines):
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
### Benchmark Results (Rails Project)
|
|
73
|
+
|
|
74
|
+
| Scenario | rfmt | RuboCop | Speedup |
|
|
75
|
+
|----------|------|---------|---------|
|
|
76
|
+
| **Single File** | ~190ms | ~1.35s | **7.3x faster** |
|
|
77
|
+
| **Directory (14 files)** | 168ms | 1.67s | **10.0x faster** |
|
|
78
|
+
| **Full Project (111 files)** | 173ms | 10.09s | **58.5x faster** |
|
|
79
|
+
| **Check Mode (CI/CD)** | 172ms | 1.55s | **9.0x faster** |
|
|
80
|
+
|
|
81
|
+
### Key Metrics
|
|
82
|
+
|
|
83
|
+
- Single file: Formats in ~190ms
|
|
84
|
+
- Scaling: 58x faster on full project (111 files)
|
|
85
|
+
- CI/CD: Check time reduced from 10.09s to 0.173s (98% reduction)
|
|
86
|
+
- Variance: Low standard deviation across runs
|
|
87
|
+
|
|
88
|
+
### Throughput Comparison
|
|
89
|
+
|
|
90
|
+
| Directory | rfmt | RuboCop | Difference |
|
|
91
|
+
|-----------|------|---------|------------|
|
|
92
|
+
| app/models (14 files) | 83.5 files/s | 8.4 files/s | **10x throughput** |
|
|
93
|
+
| test/ (30 files) | 168.1 files/s | 18.1 files/s | **9.3x throughput** |
|
|
94
|
+
|
|
95
|
+
*Benchmark environment: Apple Silicon (arm64), macOS Darwin 23.6.0, Ruby 3.4.5*
|
|
96
|
+
|
|
97
|
+
See [detailed benchmark report](docspriv/benchmark_report.md) for full data.
|
|
77
98
|
|
|
78
99
|
## Installation
|
|
79
100
|
|
|
@@ -168,7 +189,7 @@ Create a configuration file with default settings:
|
|
|
168
189
|
rfmt init
|
|
169
190
|
```
|
|
170
191
|
|
|
171
|
-
This creates a
|
|
192
|
+
This creates a `rfmt.yml` file with default settings:
|
|
172
193
|
|
|
173
194
|
```yaml
|
|
174
195
|
version: "1.0"
|
|
@@ -206,9 +227,9 @@ rfmt init --force
|
|
|
206
227
|
|
|
207
228
|
rfmt automatically searches for configuration files in this order:
|
|
208
229
|
|
|
209
|
-
1. Current directory (
|
|
230
|
+
1. Current directory (`rfmt.yml`, `rfmt.yaml`, `.rfmt.yml`, or `.rfmt.yaml`)
|
|
210
231
|
2. Parent directories (up to root)
|
|
211
|
-
3. User home directory (
|
|
232
|
+
3. User home directory (`rfmt.yml`, `rfmt.yaml`, `.rfmt.yml`, or `.rfmt.yaml`)
|
|
212
233
|
4. Default settings (if no file found)
|
|
213
234
|
|
|
214
235
|
#### Ruby API for Configuration
|
|
@@ -217,11 +238,11 @@ rfmt automatically searches for configuration files in this order:
|
|
|
217
238
|
require 'rfmt'
|
|
218
239
|
|
|
219
240
|
# Generate configuration file
|
|
220
|
-
Rfmt::Config.init('
|
|
241
|
+
Rfmt::Config.init('rfmt.yml', force: false)
|
|
221
242
|
|
|
222
243
|
# Find configuration file
|
|
223
244
|
config_path = Rfmt::Config.find
|
|
224
|
-
# => "/Users/username/project
|
|
245
|
+
# => "/Users/username/project/rfmt.yml"
|
|
225
246
|
|
|
226
247
|
# Check if configuration exists
|
|
227
248
|
Rfmt::Config.exists?
|
|
@@ -234,7 +255,7 @@ config = Rfmt::Config.load
|
|
|
234
255
|
|
|
235
256
|
## Error Handling
|
|
236
257
|
|
|
237
|
-
rfmt provides
|
|
258
|
+
rfmt provides structured error messages:
|
|
238
259
|
|
|
239
260
|
```
|
|
240
261
|
[Rfmt::ParseError] Parse error in app/models/user.rb:15:10
|
|
@@ -269,7 +290,7 @@ See the [Error Reference](docs/error_reference.md) for detailed information.
|
|
|
269
290
|
|
|
270
291
|
## Logging
|
|
271
292
|
|
|
272
|
-
rfmt includes a
|
|
293
|
+
rfmt includes a logging system:
|
|
273
294
|
|
|
274
295
|
```ruby
|
|
275
296
|
# Logs are automatically output during initialization
|
|
@@ -314,116 +335,12 @@ end
|
|
|
314
335
|
|
|
315
336
|
## Documentation
|
|
316
337
|
|
|
317
|
-
|
|
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:
|
|
329
|
-
|
|
330
|
-
```bash
|
|
331
|
-
# Install dependencies
|
|
332
|
-
bundle install
|
|
333
|
-
|
|
334
|
-
# Compile Rust extension
|
|
335
|
-
bundle exec rake compile
|
|
336
|
-
|
|
337
|
-
# Run tests
|
|
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
|
-
```
|
|
356
|
-
|
|
357
|
-
### Test Results
|
|
358
|
-
|
|
359
|
-
All 187 tests passing:
|
|
360
|
-
- 172 existing tests
|
|
361
|
-
- 15 new tests for error handling and logging
|
|
362
|
-
|
|
363
|
-
## Performance
|
|
364
|
-
|
|
365
|
-
rfmt is designed for speed:
|
|
366
|
-
|
|
367
|
-
| File Size | Format Time |
|
|
368
|
-
|-----------|-------------|
|
|
369
|
-
| 100 lines | < 10ms |
|
|
370
|
-
| 1,000 lines | < 50ms |
|
|
371
|
-
| 10,000 lines | < 500ms |
|
|
372
|
-
|
|
373
|
-
*Benchmarks run on M1 MacBook Pro*
|
|
374
|
-
|
|
375
|
-
## Roadmap
|
|
376
|
-
|
|
377
|
-
See [ROADMAP.md](ROADMAP.md) for planned features:
|
|
378
|
-
|
|
379
|
-
- [ ] Pattern matching support
|
|
380
|
-
- [ ] Numbered parameters
|
|
381
|
-
- [ ] Additional formatting rules
|
|
382
|
-
- [ ] Plugin system
|
|
383
|
-
- [ ] Language server protocol (LSP)
|
|
338
|
+
Documentation is available in the [docs](docs/) directory. See [User Guide](docs/user_guide.md) or [Contributing Guide](CONTRIBUTING.md) for details.
|
|
384
339
|
|
|
385
340
|
## Contributing
|
|
386
341
|
|
|
387
342
|
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
388
343
|
|
|
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
344
|
## Comparison with Other Tools
|
|
428
345
|
|
|
429
346
|
### rfmt vs RuboCop
|
|
@@ -431,36 +348,12 @@ rfmt is built with a hybrid Ruby-Rust architecture:
|
|
|
431
348
|
| Feature | rfmt | RuboCop |
|
|
432
349
|
|---------|------|---------|
|
|
433
350
|
| **Primary Purpose** | Code formatting | Linting + formatting |
|
|
434
|
-
| **Speed** |
|
|
351
|
+
| **Speed** | 58x faster (tested benchmark) | Baseline |
|
|
435
352
|
| **Configuration** | Minimal | Extensive |
|
|
436
353
|
| **Code Quality Checks** | No | Yes |
|
|
437
354
|
| **Bug Detection** | No | Yes |
|
|
438
355
|
|
|
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
|
|
356
|
+
**Note**: rfmt focuses on formatting speed, while RuboCop provides additional code quality analysis. They can be used together.
|
|
464
357
|
|
|
465
358
|
## License
|
|
466
359
|
|
|
@@ -474,7 +367,6 @@ Everyone interacting in the rfmt project's codebases, issue trackers, chat rooms
|
|
|
474
367
|
|
|
475
368
|
- 📖 [Documentation](docs/)
|
|
476
369
|
- 🐛 [Issues](https://github.com/fujitanisora/rfmt/issues)
|
|
477
|
-
- 💬 [Discussions](https://github.com/fujitanisora/rfmt/discussions)
|
|
478
370
|
- 📧 Email: fujitanisora0414@gmail.com
|
|
479
371
|
|
|
480
372
|
## Acknowledgments
|
|
@@ -487,8 +379,6 @@ Everyone interacting in the rfmt project's codebases, issue trackers, chat rooms
|
|
|
487
379
|
|
|
488
380
|
<div align="center">
|
|
489
381
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
**⭐ Star us on GitHub — it motivates us a lot!**
|
|
382
|
+
Created by [Fujitani Sora](https://github.com/fs0414)
|
|
493
383
|
|
|
494
384
|
</div>
|
data/ext/rfmt/Cargo.toml
CHANGED
data/ext/rfmt/src/config/mod.rs
CHANGED
|
@@ -99,8 +99,45 @@ pub enum TrailingComma {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
impl Config {
|
|
102
|
+
/// Discover configuration file in current directory or parent directories
|
|
103
|
+
/// Searches in order: rfmt.yml, rfmt.yaml, .rfmt.yml, .rfmt.yaml
|
|
104
|
+
pub fn discover() -> crate::error::Result<Self> {
|
|
105
|
+
let config_files = ["rfmt.yml", "rfmt.yaml", ".rfmt.yml", ".rfmt.yaml"];
|
|
106
|
+
|
|
107
|
+
// Try current directory and parent directories
|
|
108
|
+
if let Ok(mut current_dir) = std::env::current_dir() {
|
|
109
|
+
loop {
|
|
110
|
+
for filename in &config_files {
|
|
111
|
+
let config_path = current_dir.join(filename);
|
|
112
|
+
if config_path.exists() {
|
|
113
|
+
log::debug!("Found config file: {:?}", config_path);
|
|
114
|
+
return Self::load_file(&config_path);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Move to parent directory
|
|
119
|
+
if !current_dir.pop() {
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Try home directory
|
|
126
|
+
if let Some(home_dir) = dirs::home_dir() {
|
|
127
|
+
for filename in &config_files {
|
|
128
|
+
let config_path = home_dir.join(filename);
|
|
129
|
+
if config_path.exists() {
|
|
130
|
+
log::debug!("Found config file in home: {:?}", config_path);
|
|
131
|
+
return Self::load_file(&config_path);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
log::debug!("No config file found, using defaults");
|
|
137
|
+
Ok(Config::default())
|
|
138
|
+
}
|
|
139
|
+
|
|
102
140
|
/// Load configuration from a YAML file
|
|
103
|
-
#[cfg(test)]
|
|
104
141
|
pub fn load_file(path: &std::path::Path) -> crate::error::Result<Self> {
|
|
105
142
|
use crate::error::RfmtError;
|
|
106
143
|
|
|
@@ -119,7 +156,6 @@ impl Config {
|
|
|
119
156
|
}
|
|
120
157
|
|
|
121
158
|
/// Validate configuration values
|
|
122
|
-
#[cfg(test)]
|
|
123
159
|
fn validate(&self) -> crate::error::Result<()> {
|
|
124
160
|
use crate::error::RfmtError;
|
|
125
161
|
|
|
@@ -145,7 +181,6 @@ impl Config {
|
|
|
145
181
|
}
|
|
146
182
|
|
|
147
183
|
/// Get the indent string based on configuration
|
|
148
|
-
#[cfg(test)]
|
|
149
184
|
pub fn indent_string(&self) -> String {
|
|
150
185
|
match self.formatting.indent_style {
|
|
151
186
|
IndentStyle::Spaces => " ".repeat(self.formatting.indent_width),
|
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/ext/rfmt/src/error/mod.rs
CHANGED
|
@@ -18,7 +18,6 @@ pub enum RfmtError {
|
|
|
18
18
|
},
|
|
19
19
|
|
|
20
20
|
#[error("Configuration error: {message}")]
|
|
21
|
-
#[cfg(test)]
|
|
22
21
|
ConfigError { message: String },
|
|
23
22
|
}
|
|
24
23
|
|
|
@@ -36,7 +35,6 @@ impl RfmtError {
|
|
|
36
35
|
RfmtError::PrismError(_) => "PrismError",
|
|
37
36
|
RfmtError::FormatError(_) => "FormatError",
|
|
38
37
|
RfmtError::UnsupportedFeature { .. } => "UnsupportedFeature",
|
|
39
|
-
#[cfg(test)]
|
|
40
38
|
RfmtError::ConfigError { .. } => "ConfigError",
|
|
41
39
|
};
|
|
42
40
|
|
data/ext/rfmt/src/lib.rs
CHANGED
|
@@ -25,7 +25,8 @@ fn format_ruby_code(ruby: &Ruby, source: String, json: String) -> Result<String,
|
|
|
25
25
|
let parser = PrismAdapter::new();
|
|
26
26
|
let ast = parser.parse(&json).map_err(|e| e.to_magnus_error(ruby))?;
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
// Load configuration from file or use defaults
|
|
29
|
+
let config = Config::discover().map_err(|e| e.to_magnus_error(ruby))?;
|
|
29
30
|
let mut emitter = Emitter::with_source(config, source);
|
|
30
31
|
|
|
31
32
|
let formatted = emitter.emit(&ast).map_err(|e| e.to_magnus_error(ruby))?;
|
data/lib/rfmt/configuration.rb
CHANGED
|
@@ -18,7 +18,7 @@ module Rfmt
|
|
|
18
18
|
'exclude' => ['vendor/**/*', 'tmp/**/*', 'node_modules/**/*']
|
|
19
19
|
}.freeze
|
|
20
20
|
|
|
21
|
-
CONFIG_FILES = ['
|
|
21
|
+
CONFIG_FILES = ['rfmt.yml', 'rfmt.yaml', '.rfmt.yml', '.rfmt.yaml'].freeze
|
|
22
22
|
|
|
23
23
|
attr_reader :config
|
|
24
24
|
|
data/lib/rfmt/rfmt.so
CHANGED
|
Binary file
|
data/lib/rfmt/version.rb
CHANGED
data/lib/rfmt.rb
CHANGED
|
@@ -95,10 +95,10 @@ module Rfmt
|
|
|
95
95
|
YAML
|
|
96
96
|
|
|
97
97
|
# Generate a default configuration file
|
|
98
|
-
# @param path [String] Path where to create the config file (default:
|
|
98
|
+
# @param path [String] Path where to create the config file (default: rfmt.yml)
|
|
99
99
|
# @param force [Boolean] Overwrite existing file if true
|
|
100
100
|
# @return [Boolean] true if file was created, false if already exists
|
|
101
|
-
def self.init(path = '
|
|
101
|
+
def self.init(path = 'rfmt.yml', force: false)
|
|
102
102
|
if File.exist?(path) && !force
|
|
103
103
|
warn "Configuration file already exists: #{path}"
|
|
104
104
|
warn 'Use force: true to overwrite'
|
|
@@ -116,7 +116,7 @@ module Rfmt
|
|
|
116
116
|
current_dir = Dir.pwd
|
|
117
117
|
|
|
118
118
|
loop do
|
|
119
|
-
['.rfmt.yml', '.rfmt.yaml'].each do |filename|
|
|
119
|
+
['rfmt.yml', 'rfmt.yaml', '.rfmt.yml', '.rfmt.yaml'].each do |filename|
|
|
120
120
|
config_path = File.join(current_dir, filename)
|
|
121
121
|
return config_path if File.exist?(config_path)
|
|
122
122
|
end
|
|
@@ -134,7 +134,7 @@ module Rfmt
|
|
|
134
134
|
nil
|
|
135
135
|
end
|
|
136
136
|
if home_dir
|
|
137
|
-
['.rfmt.yml', '.rfmt.yaml'].each do |filename|
|
|
137
|
+
['rfmt.yml', 'rfmt.yaml', '.rfmt.yml', '.rfmt.yaml'].each do |filename|
|
|
138
138
|
config_path = File.join(home_dir, filename)
|
|
139
139
|
return config_path if File.exist?(config_path)
|
|
140
140
|
end
|