rfmt 0.2.4 → 0.4.0
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 +37 -0
- data/Cargo.lock +1 -1
- data/README.md +142 -159
- data/ext/rfmt/Cargo.toml +1 -1
- data/ext/rfmt/src/ast/mod.rs +2 -0
- data/ext/rfmt/src/config/mod.rs +1 -0
- data/ext/rfmt/src/emitter/mod.rs +10 -3
- data/ext/rfmt/src/lib.rs +4 -1
- data/ext/rfmt/src/logging/logger.rs +11 -2
- data/lib/rfmt/cli.rb +7 -3
- data/lib/rfmt/rfmt.so +0 -0
- data/lib/rfmt/version.rb +1 -1
- data/lib/rfmt.rb +4 -4
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3077996bae0d4959192fb7885a197916fc85679858ebc10ea00ea8696bf6d320
|
|
4
|
+
data.tar.gz: c3adf00614cc4ed60df41858c482e77b9618f06f7dadc7e9bc016c7b4d419f99
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8c1a042bcbcd8e74ac67918428fee08f8f4cf85e4f5f67a0cd9196bf7305489808176c442e8d388ae50c32c7d3f329706788c02a62ef69708be9126e600556bf
|
|
7
|
+
data.tar.gz: 2f13782fff7bb4eaea95a78bc8e3d55c4f00395074b9e5befb6d93e66b803673f5bfb1f285ae74facb009d65dbdf2ae8322f405232277994c010d88135d62746
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.4.0] - 2025-11-26
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Verbose mode option (`--verbose` flag) for detailed output during formatting
|
|
7
|
+
- Git commit hook configuration with Lefthook integration for automatic formatting
|
|
8
|
+
- RubyGems badge and installation instructions in README
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Improved documentation structure and readability in user guides (English and Japanese)
|
|
12
|
+
- Enhanced logging system with verbose output support
|
|
13
|
+
- Updated benchmark documentation in README
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- Command formatting to execution conversion issues
|
|
17
|
+
- Documentation version command display
|
|
18
|
+
- Various code quality improvements based on Clippy suggestions
|
|
19
|
+
|
|
20
|
+
## [0.3.0] - 2025-11-25
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **BREAKING**: Default configuration file name changed from `rfmt.yml` to `.rfmt.yml`
|
|
24
|
+
- `rfmt init` now creates `.rfmt.yml` instead of `rfmt.yml`
|
|
25
|
+
- Configuration file search order updated: `.rfmt.yml` > `.rfmt.yaml` > `rfmt.yml` > `rfmt.yaml`
|
|
26
|
+
- This follows Ruby community conventions for hidden configuration files
|
|
27
|
+
- Backward compatibility maintained: `rfmt.yml` is still supported
|
|
28
|
+
- Updated README.md to use `.rfmt.yml` in all examples and documentation
|
|
29
|
+
- Updated benchmark data with latest accurate measurements (3,241 lines, more realistic performance ratios)
|
|
30
|
+
- Removed exaggerated performance claims from README and documentation
|
|
31
|
+
- Simplified feature descriptions in README (removed Error Handling and Logging from Features section)
|
|
32
|
+
|
|
33
|
+
### Documentation
|
|
34
|
+
- Updated user guides (English and Japanese) to reflect `.rfmt.yml` as default
|
|
35
|
+
- Updated version information in documentation to 0.2.4 → 0.3.0
|
|
36
|
+
- Updated benchmark documentation with accurate data from latest measurements
|
|
37
|
+
- Added configuration verification examples in examples/ directory
|
|
38
|
+
- Improved Ruby API examples with clearer input/output distinction
|
|
39
|
+
|
|
3
40
|
## [0.2.4] - 2025-11-25
|
|
4
41
|
|
|
5
42
|
### Fixed
|
data/Cargo.lock
CHANGED
data/README.md
CHANGED
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
A Ruby code formatter written in Rust
|
|
6
6
|
|
|
7
|
-
[](https://
|
|
8
|
-
[](https://github.com/fujitanisora/rfmt/actions)
|
|
7
|
+
[](https://rubygems.org/gems/rfmt)
|
|
9
8
|
[](https://opensource.org/licenses/MIT)
|
|
10
9
|
|
|
11
10
|
[Installation](#installation) •
|
|
@@ -20,23 +19,20 @@ A Ruby code formatter written in Rust
|
|
|
20
19
|
|
|
21
20
|
## What is rfmt?
|
|
22
21
|
|
|
22
|
+
[RubyGems reference](https://rubygems.org/gems/rfmt)
|
|
23
|
+
|
|
23
24
|
**rfmt** is a Ruby code formatter that enforces consistent style across your codebase. Key characteristics:
|
|
24
25
|
|
|
25
|
-
- **Rust implementation**: Provides faster execution than Ruby-based tools
|
|
26
26
|
- **Opinionated**: Minimal configuration with consistent output
|
|
27
27
|
- **Idempotent**: Running multiple times produces identical results
|
|
28
28
|
- **Comment preservation**: Maintains existing comment placement
|
|
29
|
-
- **
|
|
29
|
+
- **Rust implementation**: Core formatter implemented in Rust
|
|
30
30
|
|
|
31
31
|
## Features
|
|
32
32
|
|
|
33
33
|
### Performance
|
|
34
34
|
|
|
35
|
-
Built with Rust for improved execution speed
|
|
36
|
-
|
|
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
|
|
35
|
+
Built with Rust for improved execution speed. See Performance Benchmarks section for details.
|
|
40
36
|
|
|
41
37
|
### Consistent Style
|
|
42
38
|
|
|
@@ -47,54 +43,33 @@ Enforces code style rules:
|
|
|
47
43
|
- Quote style standardization
|
|
48
44
|
- Method definition formatting
|
|
49
45
|
|
|
50
|
-
### Error Handling
|
|
51
|
-
|
|
52
|
-
Provides structured error messages:
|
|
53
|
-
|
|
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
|
-
|
|
59
|
-
### Logging
|
|
60
|
-
|
|
61
|
-
Built-in logging system:
|
|
62
|
-
|
|
63
|
-
- 5 log levels (ERROR, WARN, INFO, DEBUG, TRACE)
|
|
64
|
-
- Structured output format
|
|
65
|
-
- Performance metrics and timing data
|
|
66
|
-
- Debug context information
|
|
67
|
-
|
|
68
46
|
## Performance Benchmarks
|
|
69
47
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
### Benchmark Results (Rails Project)
|
|
48
|
+
Execution time comparison on a Rails project (111 files, 3,241 lines):
|
|
73
49
|
|
|
74
|
-
|
|
|
75
|
-
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
| **Check Mode (CI/CD)** | 172ms | 1.55s | **9.0x faster** |
|
|
50
|
+
| Test Type | Files | rfmt | RuboCop | Ratio |
|
|
51
|
+
|-----------|-------|------|---------|-------|
|
|
52
|
+
| Single File | 1 | 191ms | 1.38s | 7.2x |
|
|
53
|
+
| Directory | 14 | 176ms | 1.68s | 9.6x |
|
|
54
|
+
| Full Project (check) | 111 | 172ms | 4.36s | 25.4x |
|
|
80
55
|
|
|
81
|
-
|
|
56
|
+
**About this comparison:**
|
|
57
|
+
- RuboCop times include startup overhead and loading all cops (linting rules)
|
|
58
|
+
- RuboCop was run with default configuration (all cops enabled)
|
|
59
|
+
- rfmt is a formatting-only tool with minimal overhead
|
|
60
|
+
- Both tools were measured in check mode (no file modifications)
|
|
61
|
+
- Results are averages from 10 runs per test
|
|
82
62
|
|
|
83
|
-
|
|
84
|
-
-
|
|
85
|
-
-
|
|
86
|
-
- Variance: Low standard deviation across runs
|
|
63
|
+
**Observations:**
|
|
64
|
+
- rfmt execution time remains constant (172-191ms) regardless of file count
|
|
65
|
+
- Low variance across runs (standard deviation: 8-23ms)
|
|
87
66
|
|
|
88
|
-
|
|
67
|
+
**Test Environment:**
|
|
68
|
+
- CPU: Apple Silicon (arm64)
|
|
69
|
+
- Ruby: 3.4.5
|
|
70
|
+
- rfmt: 0.3.0, RuboCop: 1.81.7
|
|
89
71
|
|
|
90
|
-
|
|
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.
|
|
72
|
+
See [detailed benchmark report](docs/benchmark.md) for complete data.
|
|
98
73
|
|
|
99
74
|
## Installation
|
|
100
75
|
|
|
@@ -132,18 +107,60 @@ bundle exec rake compile
|
|
|
132
107
|
|
|
133
108
|
## Usage
|
|
134
109
|
|
|
110
|
+
### Initialize Configuration
|
|
111
|
+
|
|
112
|
+
First, create a configuration file with default settings:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
rfmt init
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This creates a `.rfmt.yml` file with default settings:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
version: "1.0"
|
|
122
|
+
|
|
123
|
+
formatting:
|
|
124
|
+
line_length: 100 # Maximum line length (40-500)
|
|
125
|
+
indent_width: 2 # Spaces/tabs per indent (1-8)
|
|
126
|
+
indent_style: "spaces" # "spaces" or "tabs"
|
|
127
|
+
quote_style: "double" # "double", "single", or "consistent"
|
|
128
|
+
|
|
129
|
+
include:
|
|
130
|
+
- "**/*.rb"
|
|
131
|
+
- "**/*.rake"
|
|
132
|
+
- "**/Rakefile"
|
|
133
|
+
- "**/Gemfile"
|
|
134
|
+
|
|
135
|
+
exclude:
|
|
136
|
+
- "vendor/**/*"
|
|
137
|
+
- "tmp/**/*"
|
|
138
|
+
- "node_modules/**/*"
|
|
139
|
+
- "db/schema.rb"
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Options:**
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Specify custom path
|
|
146
|
+
rfmt init --path config/.rfmt.yml
|
|
147
|
+
|
|
148
|
+
# Overwrite existing configuration
|
|
149
|
+
rfmt init --force
|
|
150
|
+
```
|
|
151
|
+
|
|
135
152
|
### Command Line
|
|
136
153
|
|
|
137
154
|
Format a single file:
|
|
138
155
|
|
|
139
156
|
```bash
|
|
140
|
-
rfmt
|
|
157
|
+
rfmt exec lib/user.rb
|
|
141
158
|
```
|
|
142
159
|
|
|
143
160
|
Format multiple files:
|
|
144
161
|
|
|
145
162
|
```bash
|
|
146
|
-
rfmt
|
|
163
|
+
rfmt exec lib/**/*.rb
|
|
147
164
|
```
|
|
148
165
|
|
|
149
166
|
Check if files need formatting (CI/CD):
|
|
@@ -152,16 +169,32 @@ Check if files need formatting (CI/CD):
|
|
|
152
169
|
rfmt check .
|
|
153
170
|
```
|
|
154
171
|
|
|
172
|
+
Show diff without modifying files:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
rfmt exec lib/user.rb --diff
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Enable verbose output for debugging:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
rfmt exec lib/user.rb --verbose
|
|
182
|
+
# or use environment variable
|
|
183
|
+
DEBUG=1 rfmt exec lib/user.rb
|
|
184
|
+
```
|
|
185
|
+
|
|
155
186
|
### Ruby API
|
|
156
187
|
|
|
188
|
+
**Input (unformatted code):**
|
|
189
|
+
|
|
157
190
|
```ruby
|
|
158
191
|
require 'rfmt'
|
|
159
192
|
|
|
160
193
|
source = <<~RUBY
|
|
161
194
|
class User
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
195
|
+
def initialize(name)
|
|
196
|
+
@name=name
|
|
197
|
+
end
|
|
165
198
|
end
|
|
166
199
|
RUBY
|
|
167
200
|
|
|
@@ -169,67 +202,25 @@ formatted = Rfmt.format(source)
|
|
|
169
202
|
puts formatted
|
|
170
203
|
```
|
|
171
204
|
|
|
172
|
-
**Output:**
|
|
205
|
+
**Output (formatted code):**
|
|
173
206
|
|
|
174
207
|
```ruby
|
|
175
208
|
class User
|
|
176
209
|
def initialize(name)
|
|
177
|
-
@name
|
|
210
|
+
@name=name
|
|
178
211
|
end
|
|
179
212
|
end
|
|
180
213
|
```
|
|
181
214
|
|
|
182
215
|
### Configuration
|
|
183
216
|
|
|
184
|
-
#### Initializing Configuration
|
|
185
|
-
|
|
186
|
-
Create a configuration file with default settings:
|
|
187
|
-
|
|
188
|
-
```bash
|
|
189
|
-
rfmt init
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
This creates a `rfmt.yml` file with default settings:
|
|
193
|
-
|
|
194
|
-
```yaml
|
|
195
|
-
version: "1.0"
|
|
196
|
-
|
|
197
|
-
formatting:
|
|
198
|
-
line_length: 100 # Maximum line length (40-500)
|
|
199
|
-
indent_width: 2 # Spaces/tabs per indent (1-8)
|
|
200
|
-
indent_style: "spaces" # "spaces" or "tabs"
|
|
201
|
-
quote_style: "double" # "double", "single", or "consistent"
|
|
202
|
-
|
|
203
|
-
include:
|
|
204
|
-
- "**/*.rb"
|
|
205
|
-
- "**/*.rake"
|
|
206
|
-
- "**/Rakefile"
|
|
207
|
-
- "**/Gemfile"
|
|
208
|
-
|
|
209
|
-
exclude:
|
|
210
|
-
- "vendor/**/*"
|
|
211
|
-
- "tmp/**/*"
|
|
212
|
-
- "node_modules/**/*"
|
|
213
|
-
- "db/schema.rb"
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
**Options:**
|
|
217
|
-
|
|
218
|
-
```bash
|
|
219
|
-
# Specify custom path
|
|
220
|
-
rfmt init --path config/rfmt.yml
|
|
221
|
-
|
|
222
|
-
# Overwrite existing configuration
|
|
223
|
-
rfmt init --force
|
|
224
|
-
```
|
|
225
|
-
|
|
226
217
|
#### Configuration File Discovery
|
|
227
218
|
|
|
228
219
|
rfmt automatically searches for configuration files in this order:
|
|
229
220
|
|
|
230
|
-
1. Current directory (
|
|
221
|
+
1. Current directory (`.rfmt.yml`, `.rfmt.yaml`, `rfmt.yml`, or `rfmt.yaml`)
|
|
231
222
|
2. Parent directories (up to root)
|
|
232
|
-
3. User home directory (
|
|
223
|
+
3. User home directory (`.rfmt.yml`, `.rfmt.yaml`, `rfmt.yml`, or `rfmt.yaml`)
|
|
233
224
|
4. Default settings (if no file found)
|
|
234
225
|
|
|
235
226
|
#### Ruby API for Configuration
|
|
@@ -238,11 +229,11 @@ rfmt automatically searches for configuration files in this order:
|
|
|
238
229
|
require 'rfmt'
|
|
239
230
|
|
|
240
231
|
# Generate configuration file
|
|
241
|
-
Rfmt::Config.init('rfmt.yml', force: false)
|
|
232
|
+
Rfmt::Config.init('.rfmt.yml', force: false)
|
|
242
233
|
|
|
243
234
|
# Find configuration file
|
|
244
235
|
config_path = Rfmt::Config.find
|
|
245
|
-
# => "/Users/username/project
|
|
236
|
+
# => "/Users/username/project/.rfmt.yml"
|
|
246
237
|
|
|
247
238
|
# Check if configuration exists
|
|
248
239
|
Rfmt::Config.exists?
|
|
@@ -253,59 +244,6 @@ config = Rfmt::Config.load
|
|
|
253
244
|
# => {"version"=>"1.0", "formatting"=>{"line_length"=>100, ...}, ...}
|
|
254
245
|
```
|
|
255
246
|
|
|
256
|
-
## Error Handling
|
|
257
|
-
|
|
258
|
-
rfmt provides structured error messages:
|
|
259
|
-
|
|
260
|
-
```
|
|
261
|
-
[Rfmt::ParseError] Parse error in app/models/user.rb:15:10
|
|
262
|
-
Expected closing 'end' for class definition
|
|
263
|
-
|
|
264
|
-
Code:
|
|
265
|
-
13 | class User < ApplicationRecord
|
|
266
|
-
14 | def initialize(name)
|
|
267
|
-
15 | @name = name
|
|
268
|
-
| ^
|
|
269
|
-
16 | # Missing 'end' for method
|
|
270
|
-
17 | end
|
|
271
|
-
|
|
272
|
-
Help: https://rfmt.dev/errors/E001
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### Error Codes
|
|
276
|
-
|
|
277
|
-
| Code | Type | Description |
|
|
278
|
-
|------|------|-------------|
|
|
279
|
-
| E001 | ParseError | Ruby syntax error |
|
|
280
|
-
| E002 | ConfigError | Invalid configuration |
|
|
281
|
-
| E003 | IoError | File read/write error |
|
|
282
|
-
| E004 | FormattingError | Formatting process error |
|
|
283
|
-
| E005 | RuleError | Rule application failed |
|
|
284
|
-
| E006 | UnsupportedFeature | Feature not yet supported |
|
|
285
|
-
| E007 | PrismError | Parser integration error |
|
|
286
|
-
| E008 | FormatError | General formatting error |
|
|
287
|
-
| E999 | InternalError | Internal bug (please report!) |
|
|
288
|
-
|
|
289
|
-
See the [Error Reference](docs/error_reference.md) for detailed information.
|
|
290
|
-
|
|
291
|
-
## Logging
|
|
292
|
-
|
|
293
|
-
rfmt includes a logging system:
|
|
294
|
-
|
|
295
|
-
```ruby
|
|
296
|
-
# Logs are automatically output during initialization
|
|
297
|
-
require 'rfmt'
|
|
298
|
-
# [INFO] rfmt - Initializing rfmt Rust extension
|
|
299
|
-
# [INFO] rfmt - rfmt Rust extension initialized successfully
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
Log levels:
|
|
303
|
-
- **ERROR**: Critical errors
|
|
304
|
-
- **WARN**: Warnings
|
|
305
|
-
- **INFO**: General information (default)
|
|
306
|
-
- **DEBUG**: Debug information
|
|
307
|
-
- **TRACE**: Detailed trace information
|
|
308
|
-
|
|
309
247
|
## Examples
|
|
310
248
|
|
|
311
249
|
### Before Formatting
|
|
@@ -333,9 +271,55 @@ class User < ApplicationRecord
|
|
|
333
271
|
end
|
|
334
272
|
```
|
|
335
273
|
|
|
274
|
+
## Development
|
|
275
|
+
|
|
276
|
+
### Setup
|
|
277
|
+
|
|
278
|
+
After cloning the repository:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
bundle install
|
|
282
|
+
bundle exec lefthook install
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Git Hooks
|
|
286
|
+
|
|
287
|
+
This project uses [lefthook](https://github.com/evilmartians/lefthook) for automated validation before push:
|
|
288
|
+
|
|
289
|
+
**Pre-push checks:**
|
|
290
|
+
- RuboCop (Ruby linting)
|
|
291
|
+
- cargo fmt --check (Rust formatting)
|
|
292
|
+
- cargo clippy (Rust linting)
|
|
293
|
+
|
|
294
|
+
**Skip hooks temporarily:**
|
|
295
|
+
```bash
|
|
296
|
+
# Skip all hooks for this push
|
|
297
|
+
LEFTHOOK=0 git push
|
|
298
|
+
|
|
299
|
+
# Skip specific hook
|
|
300
|
+
LEFTHOOK_EXCLUDE=rubocop git push
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Running Tests
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
# Ruby tests
|
|
307
|
+
bundle exec rspec
|
|
308
|
+
|
|
309
|
+
# Rust tests
|
|
310
|
+
cargo test --manifest-path ext/rfmt/Cargo.toml
|
|
311
|
+
|
|
312
|
+
# All tests
|
|
313
|
+
bundle exec rake dev:test_all
|
|
314
|
+
```
|
|
315
|
+
|
|
336
316
|
## Documentation
|
|
337
317
|
|
|
338
|
-
Documentation is available in the [docs](docs/) directory
|
|
318
|
+
Documentation is available in the [docs](docs/) directory:
|
|
319
|
+
|
|
320
|
+
- [User Guide](docs/user_guide.md) - Comprehensive usage guide
|
|
321
|
+
- [Error Reference](docs/error_reference.md) - Error codes and troubleshooting
|
|
322
|
+
- [Contributing Guide](CONTRIBUTING.md) - How to contribute
|
|
339
323
|
|
|
340
324
|
## Contributing
|
|
341
325
|
|
|
@@ -348,12 +332,11 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
|
|
|
348
332
|
| Feature | rfmt | RuboCop |
|
|
349
333
|
|---------|------|---------|
|
|
350
334
|
| **Primary Purpose** | Code formatting | Linting + formatting |
|
|
351
|
-
| **Speed** | 58x faster (tested benchmark) | Baseline |
|
|
352
335
|
| **Configuration** | Minimal | Extensive |
|
|
353
336
|
| **Code Quality Checks** | No | Yes |
|
|
354
337
|
| **Bug Detection** | No | Yes |
|
|
355
338
|
|
|
356
|
-
**Note**: rfmt focuses on formatting
|
|
339
|
+
**Note**: rfmt focuses on code formatting, while RuboCop provides additional code quality analysis. They can be used together.
|
|
357
340
|
|
|
358
341
|
## License
|
|
359
342
|
|
data/ext/rfmt/Cargo.toml
CHANGED
data/ext/rfmt/src/ast/mod.rs
CHANGED
|
@@ -174,6 +174,7 @@ impl Node {
|
|
|
174
174
|
|
|
175
175
|
/// Add metadata to the node
|
|
176
176
|
#[cfg(test)]
|
|
177
|
+
#[allow(dead_code)]
|
|
177
178
|
pub fn with_metadata(mut self, metadata: HashMap<String, String>) -> Self {
|
|
178
179
|
self.metadata = metadata;
|
|
179
180
|
self
|
|
@@ -181,6 +182,7 @@ impl Node {
|
|
|
181
182
|
|
|
182
183
|
/// Add comments to the node
|
|
183
184
|
#[cfg(test)]
|
|
185
|
+
#[allow(dead_code)]
|
|
184
186
|
pub fn with_comments(mut self, comments: Vec<Comment>) -> Self {
|
|
185
187
|
self.comments = comments;
|
|
186
188
|
self
|
data/ext/rfmt/src/config/mod.rs
CHANGED
data/ext/rfmt/src/emitter/mod.rs
CHANGED
|
@@ -309,11 +309,18 @@ impl Emitter {
|
|
|
309
309
|
/// Emit if/unless/elsif/else node
|
|
310
310
|
/// is_elsif: true if this is an elsif clause (don't emit 'end')
|
|
311
311
|
/// keyword: "if" or "unless"
|
|
312
|
-
fn emit_if_unless(
|
|
312
|
+
fn emit_if_unless(
|
|
313
|
+
&mut self,
|
|
314
|
+
node: &Node,
|
|
315
|
+
indent_level: usize,
|
|
316
|
+
is_elsif: bool,
|
|
317
|
+
keyword: &str,
|
|
318
|
+
) -> Result<()> {
|
|
313
319
|
// Check if this is a postfix if (modifier form)
|
|
314
320
|
// In postfix if, the statements come before the if keyword in source
|
|
315
321
|
let is_postfix = if let (Some(predicate), Some(statements)) =
|
|
316
|
-
(node.children.first(), node.children.get(1))
|
|
322
|
+
(node.children.first(), node.children.get(1))
|
|
323
|
+
{
|
|
317
324
|
statements.location.start_offset < predicate.location.start_offset
|
|
318
325
|
} else {
|
|
319
326
|
false
|
|
@@ -399,7 +406,7 @@ impl Emitter {
|
|
|
399
406
|
NodeType::ElseNode => {
|
|
400
407
|
// This is an else clause
|
|
401
408
|
self.emit_indent(indent_level)?;
|
|
402
|
-
|
|
409
|
+
writeln!(self.buffer, "else")?;
|
|
403
410
|
|
|
404
411
|
// Emit else body (first child of ElseNode)
|
|
405
412
|
if let Some(else_statements) = consequent.children.first() {
|
data/ext/rfmt/src/lib.rs
CHANGED
|
@@ -29,7 +29,10 @@ fn format_ruby_code(ruby: &Ruby, source: String, json: String) -> Result<String,
|
|
|
29
29
|
// Load configuration from file or use defaults
|
|
30
30
|
log::info!("Attempting to discover config file...");
|
|
31
31
|
let config = Config::discover().map_err(|e| e.to_magnus_error(ruby))?;
|
|
32
|
-
log::info!(
|
|
32
|
+
log::info!(
|
|
33
|
+
"Config loaded successfully, line_length: {}",
|
|
34
|
+
config.formatting.line_length
|
|
35
|
+
);
|
|
33
36
|
let mut emitter = Emitter::with_source(config, source);
|
|
34
37
|
|
|
35
38
|
let formatted = emitter.emit(&ast).map_err(|e| e.to_magnus_error(ruby))?;
|
|
@@ -22,10 +22,20 @@ impl RfmtLogger {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
pub fn init() {
|
|
25
|
+
// Check for debug mode via environment variables
|
|
26
|
+
let debug_mode = std::env::var("DEBUG").is_ok()
|
|
27
|
+
|| std::env::var("RFMT_DEBUG").is_ok()
|
|
28
|
+
|| std::env::var("RUST_LOG").is_ok();
|
|
29
|
+
|
|
25
30
|
let level = std::env::var("RFMT_LOG")
|
|
26
31
|
.ok()
|
|
27
32
|
.and_then(|s| s.parse().ok())
|
|
28
|
-
.unwrap_or(
|
|
33
|
+
.unwrap_or(if debug_mode {
|
|
34
|
+
LevelFilter::Info
|
|
35
|
+
} else {
|
|
36
|
+
// In normal mode, only show warnings and errors
|
|
37
|
+
LevelFilter::Warn
|
|
38
|
+
});
|
|
29
39
|
let logger = Self::new(level);
|
|
30
40
|
log::set_boxed_logger(Box::new(logger)).expect("Failed to initialize logger");
|
|
31
41
|
log::set_max_level(LevelFilter::Trace);
|
|
@@ -63,7 +73,6 @@ impl Log for RfmtLogger {
|
|
|
63
73
|
#[cfg(test)]
|
|
64
74
|
mod tests {
|
|
65
75
|
use super::*;
|
|
66
|
-
use log::{debug, error, info, trace, warn};
|
|
67
76
|
use std::sync::{Arc, Mutex};
|
|
68
77
|
|
|
69
78
|
struct TestWriter {
|
data/lib/rfmt/cli.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'thor'
|
|
4
|
+
|
|
5
|
+
# Check for verbose flag before loading rfmt to set debug mode early
|
|
6
|
+
ENV['RFMT_DEBUG'] = '1' if ARGV.include?('-v') || ARGV.include?('--verbose')
|
|
7
|
+
|
|
4
8
|
require 'rfmt'
|
|
5
9
|
require 'rfmt/configuration'
|
|
6
10
|
require 'rfmt/cache'
|
|
@@ -43,7 +47,7 @@ module Rfmt
|
|
|
43
47
|
class_option :config, type: :string, desc: 'Path to configuration file'
|
|
44
48
|
class_option :verbose, type: :boolean, aliases: '-v', desc: 'Verbose output'
|
|
45
49
|
|
|
46
|
-
desc '
|
|
50
|
+
desc 'exec [FILES]', 'Format Ruby files'
|
|
47
51
|
option :write, type: :boolean, default: true, desc: 'Write formatted output'
|
|
48
52
|
option :check, type: :boolean, desc: "Check if files are formatted (don't write)"
|
|
49
53
|
option :diff, type: :boolean, desc: 'Show diff of changes'
|
|
@@ -52,7 +56,7 @@ module Rfmt
|
|
|
52
56
|
option :jobs, type: :numeric, desc: 'Number of parallel jobs (default: CPU count)'
|
|
53
57
|
option :cache, type: :boolean, default: true, desc: 'Use cache to skip unchanged files'
|
|
54
58
|
option :cache_dir, type: :string, desc: 'Cache directory (default: ~/.cache/rfmt)'
|
|
55
|
-
def
|
|
59
|
+
def exec(*files)
|
|
56
60
|
config = load_config
|
|
57
61
|
files = files.empty? ? config.files_to_format : files.flatten
|
|
58
62
|
|
|
@@ -92,7 +96,7 @@ module Rfmt
|
|
|
92
96
|
|
|
93
97
|
desc 'check [FILES]', 'Check if files need formatting'
|
|
94
98
|
def check(*files)
|
|
95
|
-
invoke :
|
|
99
|
+
invoke :exec, files, check: true, write: false
|
|
96
100
|
end
|
|
97
101
|
|
|
98
102
|
desc 'version', 'Show version'
|
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: rfmt.yml)
|
|
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 = 'rfmt.yml', force: false)
|
|
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', '
|
|
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', '
|
|
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
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rfmt
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- fujitani sora
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-11-
|
|
11
|
+
date: 2025-11-25 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rb_sys
|