rfmt 0.1.0 → 0.2.1
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 +30 -0
- data/Cargo.lock +1748 -133
- data/README.md +458 -19
- data/exe/rfmt +15 -0
- data/ext/rfmt/Cargo.toml +46 -1
- data/ext/rfmt/extconf.rb +5 -5
- data/ext/rfmt/spec/config_spec.rb +39 -0
- data/ext/rfmt/spec/spec_helper.rb +16 -0
- data/ext/rfmt/src/ast/mod.rs +335 -0
- data/ext/rfmt/src/config/mod.rs +403 -0
- data/ext/rfmt/src/emitter/mod.rs +347 -0
- data/ext/rfmt/src/error/mod.rs +48 -0
- data/ext/rfmt/src/lib.rs +59 -36
- data/ext/rfmt/src/logging/logger.rs +128 -0
- data/ext/rfmt/src/logging/mod.rs +3 -0
- data/ext/rfmt/src/parser/mod.rs +9 -0
- data/ext/rfmt/src/parser/prism_adapter.rs +407 -0
- data/ext/rfmt/src/policy/mod.rs +36 -0
- data/ext/rfmt/src/policy/validation.rs +18 -0
- data/lib/rfmt/cache.rb +120 -0
- data/lib/rfmt/cli.rb +280 -0
- data/lib/rfmt/configuration.rb +95 -0
- data/lib/rfmt/prism_bridge.rb +255 -0
- data/lib/rfmt/prism_node_extractor.rb +81 -0
- data/lib/rfmt/rfmt.so +0 -0
- data/lib/rfmt/version.rb +1 -1
- data/lib/rfmt.rb +156 -5
- metadata +29 -7
- data/lib/rfmt/rfmt.bundle +0 -0
data/README.md
CHANGED
|
@@ -1,50 +1,466 @@
|
|
|
1
1
|
# rfmt
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<div align="center">
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
⚡ A fast, opinionated Ruby code formatter written in Rust ⚡
|
|
6
|
+
|
|
7
|
+
[](https://badge.fury.io/rb/rfmt)
|
|
8
|
+
[](https://github.com/fujitanisora/rfmt/actions)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
|
|
11
|
+
[Installation](#installation) •
|
|
12
|
+
[Usage](#usage) •
|
|
13
|
+
[Features](#features) •
|
|
14
|
+
[Documentation](#documentation) •
|
|
15
|
+
[Contributing](#contributing)
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What is rfmt?
|
|
22
|
+
|
|
23
|
+
**rfmt** is a lightning-fast Ruby code formatter that enforces consistent style across your codebase. It's designed to be:
|
|
24
|
+
|
|
25
|
+
- **Fast**: Written in Rust for maximum performance
|
|
26
|
+
- **Opinionated**: Minimal configuration, consistent results
|
|
27
|
+
- **Idempotent**: Running it multiple times produces the same output
|
|
28
|
+
- **Comment-preserving**: Your comments stay exactly where they should
|
|
29
|
+
- **Production-ready**: Comprehensive error handling and logging
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
### ⚡ Performance
|
|
34
|
+
|
|
35
|
+
rfmt is built with Rust, making it significantly faster than pure-Ruby formatters:
|
|
36
|
+
|
|
37
|
+
- Formats thousands of lines per second
|
|
38
|
+
- Parallel processing support
|
|
39
|
+
- Smart caching for unchanged files
|
|
40
|
+
|
|
41
|
+
### 🎨 Consistent Style
|
|
42
|
+
|
|
43
|
+
rfmt enforces a consistent code style across your entire project:
|
|
44
|
+
|
|
45
|
+
- Automatic indentation
|
|
46
|
+
- Consistent spacing and alignment
|
|
47
|
+
- Quote style normalization
|
|
48
|
+
- Method definition formatting
|
|
49
|
+
|
|
50
|
+
### 🔍 Smart Error Handling
|
|
51
|
+
|
|
52
|
+
rfmt provides detailed, actionable error messages:
|
|
53
|
+
|
|
54
|
+
- **Error codes** (E001-E999) for easy troubleshooting
|
|
55
|
+
- **Code snippets** showing exactly where errors occur
|
|
56
|
+
- **Help URLs** linking to detailed documentation
|
|
57
|
+
- **Recovery strategies** to handle partial formatting
|
|
58
|
+
|
|
59
|
+
### 📊 Comprehensive Logging
|
|
60
|
+
|
|
61
|
+
Built-in logging system for debugging and monitoring:
|
|
62
|
+
|
|
63
|
+
- Multiple log levels (ERROR, WARN, INFO, DEBUG, TRACE)
|
|
64
|
+
- Structured output for easy parsing
|
|
65
|
+
- Performance metrics and timing information
|
|
66
|
+
- Debug context for complex operations
|
|
67
|
+
|
|
68
|
+
### 🧩 Editor Integration
|
|
69
|
+
|
|
70
|
+
Works with your favorite editor:
|
|
71
|
+
|
|
72
|
+
- Visual Studio Code
|
|
73
|
+
- RubyMine / IntelliJ IDEA
|
|
74
|
+
- Vim / Neovim
|
|
75
|
+
- Emacs
|
|
76
|
+
- Sublime Text
|
|
6
77
|
|
|
7
78
|
## Installation
|
|
8
79
|
|
|
9
|
-
###
|
|
80
|
+
### Requirements
|
|
81
|
+
|
|
82
|
+
- Ruby 3.0 or higher
|
|
83
|
+
- Rust 1.70 or higher (for building from source)
|
|
84
|
+
|
|
85
|
+
### From RubyGems
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
gem install rfmt
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### In Your Gemfile
|
|
92
|
+
|
|
10
93
|
```ruby
|
|
11
94
|
gem 'rfmt'
|
|
12
95
|
```
|
|
13
96
|
|
|
14
|
-
|
|
97
|
+
Then run:
|
|
98
|
+
|
|
15
99
|
```bash
|
|
16
|
-
|
|
100
|
+
bundle install
|
|
17
101
|
```
|
|
18
102
|
|
|
19
|
-
|
|
103
|
+
### From Source
|
|
104
|
+
|
|
20
105
|
```bash
|
|
21
|
-
|
|
106
|
+
git clone https://github.com/fujitanisora/rfmt.git
|
|
107
|
+
cd rfmt
|
|
108
|
+
bundle install
|
|
22
109
|
bundle exec rake compile
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Usage
|
|
113
|
+
|
|
114
|
+
### Command Line
|
|
115
|
+
|
|
116
|
+
Format a single file:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
rfmt format lib/user.rb
|
|
120
|
+
```
|
|
23
121
|
|
|
24
|
-
|
|
25
|
-
gem build r_format.gemspec
|
|
122
|
+
Format multiple files:
|
|
26
123
|
|
|
27
|
-
|
|
28
|
-
|
|
124
|
+
```bash
|
|
125
|
+
rfmt format lib/**/*.rb
|
|
29
126
|
```
|
|
30
|
-
|
|
127
|
+
|
|
128
|
+
Check if files need formatting (CI/CD):
|
|
129
|
+
|
|
31
130
|
```bash
|
|
32
|
-
|
|
131
|
+
rfmt check .
|
|
33
132
|
```
|
|
34
133
|
|
|
35
|
-
|
|
134
|
+
### Ruby API
|
|
135
|
+
|
|
136
|
+
```ruby
|
|
137
|
+
require 'rfmt'
|
|
138
|
+
|
|
139
|
+
source = <<~RUBY
|
|
140
|
+
class User
|
|
141
|
+
def initialize(name)
|
|
142
|
+
@name=name
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
RUBY
|
|
146
|
+
|
|
147
|
+
formatted = Rfmt.format(source)
|
|
148
|
+
puts formatted
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Output:**
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
class User
|
|
155
|
+
def initialize(name)
|
|
156
|
+
@name = name
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Configuration
|
|
162
|
+
|
|
163
|
+
#### Initializing Configuration
|
|
164
|
+
|
|
165
|
+
Create a configuration file with default settings:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
rfmt init
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
This creates a `.rfmt.yml` file with sensible defaults:
|
|
172
|
+
|
|
173
|
+
```yaml
|
|
174
|
+
version: "1.0"
|
|
175
|
+
|
|
176
|
+
formatting:
|
|
177
|
+
line_length: 100 # Maximum line length (40-500)
|
|
178
|
+
indent_width: 2 # Spaces/tabs per indent (1-8)
|
|
179
|
+
indent_style: "spaces" # "spaces" or "tabs"
|
|
180
|
+
quote_style: "double" # "double", "single", or "consistent"
|
|
181
|
+
|
|
182
|
+
include:
|
|
183
|
+
- "**/*.rb"
|
|
184
|
+
- "**/*.rake"
|
|
185
|
+
- "**/Rakefile"
|
|
186
|
+
- "**/Gemfile"
|
|
187
|
+
|
|
188
|
+
exclude:
|
|
189
|
+
- "vendor/**/*"
|
|
190
|
+
- "tmp/**/*"
|
|
191
|
+
- "node_modules/**/*"
|
|
192
|
+
- "db/schema.rb"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Options:**
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Specify custom path
|
|
199
|
+
rfmt init --path config/rfmt.yml
|
|
200
|
+
|
|
201
|
+
# Overwrite existing configuration
|
|
202
|
+
rfmt init --force
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### Configuration File Discovery
|
|
206
|
+
|
|
207
|
+
rfmt automatically searches for configuration files in this order:
|
|
208
|
+
|
|
209
|
+
1. Current directory (`.rfmt.yml` or `.rfmt.yaml`)
|
|
210
|
+
2. Parent directories (up to root)
|
|
211
|
+
3. User home directory (`~/.rfmt.yml` or `~/.rfmt.yaml`)
|
|
212
|
+
4. Default settings (if no file found)
|
|
213
|
+
|
|
214
|
+
#### Ruby API for Configuration
|
|
215
|
+
|
|
216
|
+
```ruby
|
|
217
|
+
require 'rfmt'
|
|
218
|
+
|
|
219
|
+
# Generate configuration file
|
|
220
|
+
Rfmt::Config.init('.rfmt.yml', force: false)
|
|
221
|
+
|
|
222
|
+
# Find configuration file
|
|
223
|
+
config_path = Rfmt::Config.find
|
|
224
|
+
# => "/Users/username/project/.rfmt.yml"
|
|
36
225
|
|
|
37
|
-
|
|
226
|
+
# Check if configuration exists
|
|
227
|
+
Rfmt::Config.exists?
|
|
228
|
+
# => true
|
|
229
|
+
|
|
230
|
+
# Load configuration
|
|
231
|
+
config = Rfmt::Config.load
|
|
232
|
+
# => {"version"=>"1.0", "formatting"=>{"line_length"=>100, ...}, ...}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Error Handling
|
|
236
|
+
|
|
237
|
+
rfmt provides detailed error messages with actionable solutions:
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
[Rfmt::ParseError] Parse error in app/models/user.rb:15:10
|
|
241
|
+
Expected closing 'end' for class definition
|
|
242
|
+
|
|
243
|
+
Code:
|
|
244
|
+
13 | class User < ApplicationRecord
|
|
245
|
+
14 | def initialize(name)
|
|
246
|
+
15 | @name = name
|
|
247
|
+
| ^
|
|
248
|
+
16 | # Missing 'end' for method
|
|
249
|
+
17 | end
|
|
250
|
+
|
|
251
|
+
Help: https://rfmt.dev/errors/E001
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Error Codes
|
|
255
|
+
|
|
256
|
+
| Code | Type | Description |
|
|
257
|
+
|------|------|-------------|
|
|
258
|
+
| E001 | ParseError | Ruby syntax error |
|
|
259
|
+
| E002 | ConfigError | Invalid configuration |
|
|
260
|
+
| E003 | IoError | File read/write error |
|
|
261
|
+
| E004 | FormattingError | Formatting process error |
|
|
262
|
+
| E005 | RuleError | Rule application failed |
|
|
263
|
+
| E006 | UnsupportedFeature | Feature not yet supported |
|
|
264
|
+
| E007 | PrismError | Parser integration error |
|
|
265
|
+
| E008 | FormatError | General formatting error |
|
|
266
|
+
| E999 | InternalError | Internal bug (please report!) |
|
|
267
|
+
|
|
268
|
+
See the [Error Reference](docs/error_reference.md) for detailed information.
|
|
269
|
+
|
|
270
|
+
## Logging
|
|
271
|
+
|
|
272
|
+
rfmt includes a comprehensive logging system:
|
|
273
|
+
|
|
274
|
+
```ruby
|
|
275
|
+
# Logs are automatically output during initialization
|
|
276
|
+
require 'rfmt'
|
|
277
|
+
# [INFO] rfmt - Initializing rfmt Rust extension
|
|
278
|
+
# [INFO] rfmt - rfmt Rust extension initialized successfully
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Log levels:
|
|
282
|
+
- **ERROR**: Critical errors
|
|
283
|
+
- **WARN**: Warnings
|
|
284
|
+
- **INFO**: General information (default)
|
|
285
|
+
- **DEBUG**: Debug information
|
|
286
|
+
- **TRACE**: Detailed trace information
|
|
287
|
+
|
|
288
|
+
## Examples
|
|
289
|
+
|
|
290
|
+
### Before Formatting
|
|
291
|
+
|
|
292
|
+
```ruby
|
|
293
|
+
class User<ApplicationRecord
|
|
294
|
+
has_many :posts
|
|
295
|
+
validates :email,presence: true
|
|
296
|
+
def full_name
|
|
297
|
+
"#{first_name} #{last_name}"
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### After Formatting
|
|
303
|
+
|
|
304
|
+
```ruby
|
|
305
|
+
class User < ApplicationRecord
|
|
306
|
+
has_many :posts
|
|
307
|
+
validates :email, presence: true
|
|
308
|
+
|
|
309
|
+
def full_name
|
|
310
|
+
"#{first_name} #{last_name}"
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Documentation
|
|
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
|
|
38
325
|
|
|
39
326
|
## Development
|
|
40
327
|
|
|
41
|
-
After checking out the repo
|
|
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
|
+
```
|
|
42
343
|
|
|
43
|
-
|
|
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)
|
|
44
384
|
|
|
45
385
|
## Contributing
|
|
46
386
|
|
|
47
|
-
|
|
387
|
+
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
388
|
+
|
|
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
|
+
## Comparison with Other Tools
|
|
428
|
+
|
|
429
|
+
### rfmt vs RuboCop
|
|
430
|
+
|
|
431
|
+
| Feature | rfmt | RuboCop |
|
|
432
|
+
|---------|------|---------|
|
|
433
|
+
| **Primary Purpose** | Code formatting | Linting + formatting |
|
|
434
|
+
| **Speed** | Very fast (Rust) | Moderate (Ruby) |
|
|
435
|
+
| **Configuration** | Minimal | Extensive |
|
|
436
|
+
| **Code Quality Checks** | No | Yes |
|
|
437
|
+
| **Bug Detection** | No | Yes |
|
|
438
|
+
|
|
439
|
+
**Recommendation**: Use rfmt for consistent formatting, RuboCop for code quality checks.
|
|
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
|
|
48
464
|
|
|
49
465
|
## License
|
|
50
466
|
|
|
@@ -52,4 +468,27 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
|
52
468
|
|
|
53
469
|
## Code of Conduct
|
|
54
470
|
|
|
55
|
-
Everyone interacting in the rfmt project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](
|
|
471
|
+
Everyone interacting in the rfmt project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](CODE_OF_CONDUCT.md).
|
|
472
|
+
|
|
473
|
+
## Support
|
|
474
|
+
|
|
475
|
+
- 📖 [Documentation](docs/)
|
|
476
|
+
- 🐛 [Issues](https://github.com/fujitanisora/rfmt/issues)
|
|
477
|
+
- 💬 [Discussions](https://github.com/fujitanisora/rfmt/discussions)
|
|
478
|
+
- 📧 Email: fujitanisora0414@gmail.com
|
|
479
|
+
|
|
480
|
+
## Acknowledgments
|
|
481
|
+
|
|
482
|
+
- Built with [Prism](https://github.com/ruby/prism) - Modern Ruby parser
|
|
483
|
+
- Powered by [Rust](https://www.rust-lang.org/) - Performance and safety
|
|
484
|
+
- FFI via [Magnus](https://github.com/matsadler/magnus) - Ruby-Rust bridge
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
<div align="center">
|
|
489
|
+
|
|
490
|
+
Made with ❤️ by [Fujitani Sora](https://github.com/fs0414)
|
|
491
|
+
|
|
492
|
+
**⭐ Star us on GitHub — it motivates us a lot!**
|
|
493
|
+
|
|
494
|
+
</div>
|
data/exe/rfmt
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'rfmt/cli'
|
|
5
|
+
|
|
6
|
+
begin
|
|
7
|
+
Rfmt::CLI.start(ARGV)
|
|
8
|
+
rescue Interrupt
|
|
9
|
+
puts "\nInterrupted"
|
|
10
|
+
exit(130)
|
|
11
|
+
rescue StandardError => e
|
|
12
|
+
warn "Error: #{e.message}"
|
|
13
|
+
warn e.backtrace.join("\n") if ENV['DEBUG']
|
|
14
|
+
exit(1)
|
|
15
|
+
end
|
data/ext/rfmt/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rfmt"
|
|
3
|
-
version = "0.1
|
|
3
|
+
version = "0.2.1"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["fujitani sora <fujitanisora0414@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -11,4 +11,49 @@ name = "rfmt"
|
|
|
11
11
|
crate-type = ["cdylib"]
|
|
12
12
|
|
|
13
13
|
[dependencies]
|
|
14
|
+
# Ruby FFI
|
|
14
15
|
magnus = { version = "0.6.2" }
|
|
16
|
+
rb-sys = "0.9.117"
|
|
17
|
+
|
|
18
|
+
# Serialization
|
|
19
|
+
serde = { version = "1.0", features = ["derive"] }
|
|
20
|
+
serde_json = "1.0"
|
|
21
|
+
serde_yaml = "0.9"
|
|
22
|
+
rmp-serde = "1.1" # MessagePack
|
|
23
|
+
|
|
24
|
+
# Error handling
|
|
25
|
+
thiserror = "1.0"
|
|
26
|
+
anyhow = "1.0"
|
|
27
|
+
|
|
28
|
+
# Parallel processing
|
|
29
|
+
rayon = "1.8"
|
|
30
|
+
|
|
31
|
+
# Caching
|
|
32
|
+
lru = "0.12"
|
|
33
|
+
|
|
34
|
+
# Logging
|
|
35
|
+
log = "0.4"
|
|
36
|
+
env_logger = "0.11"
|
|
37
|
+
|
|
38
|
+
# Configuration
|
|
39
|
+
config = "0.14"
|
|
40
|
+
toml = "0.8"
|
|
41
|
+
dirs = "5.0"
|
|
42
|
+
globset = "0.4"
|
|
43
|
+
|
|
44
|
+
# Security and resource management
|
|
45
|
+
num_cpus = "1.16"
|
|
46
|
+
|
|
47
|
+
# CLI (optional)
|
|
48
|
+
clap = { version = "4.4", features = ["derive"], optional = true }
|
|
49
|
+
|
|
50
|
+
[dev-dependencies]
|
|
51
|
+
# Testing
|
|
52
|
+
proptest = "1.4"
|
|
53
|
+
insta = "1.34"
|
|
54
|
+
criterion = "0.5"
|
|
55
|
+
tempfile = "3.8"
|
|
56
|
+
|
|
57
|
+
[features]
|
|
58
|
+
default = ["cli"]
|
|
59
|
+
cli = ["clap"]
|
data/ext/rfmt/extconf.rb
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require 'mkmf'
|
|
4
|
+
require 'rb_sys/mkmf'
|
|
5
5
|
|
|
6
6
|
# Set the cargo build target to match the system architecture
|
|
7
7
|
if RUBY_PLATFORM =~ /arm64-darwin/
|
|
8
|
-
ENV[
|
|
8
|
+
ENV['CARGO_BUILD_TARGET'] = 'aarch64-apple-darwin'
|
|
9
9
|
elsif RUBY_PLATFORM =~ /x86_64-darwin/
|
|
10
|
-
ENV[
|
|
10
|
+
ENV['CARGO_BUILD_TARGET'] = 'x86_64-apple-darwin'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
create_rust_makefile(
|
|
13
|
+
create_rust_makefile('rfmt/rfmt')
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
RSpec.describe 'Configuration' do
|
|
6
|
+
describe 'configuration system integration' do
|
|
7
|
+
it 'can load YAML configuration' do
|
|
8
|
+
require 'tempfile'
|
|
9
|
+
require 'yaml'
|
|
10
|
+
|
|
11
|
+
config = {
|
|
12
|
+
'version' => '1.0',
|
|
13
|
+
'formatting' => {
|
|
14
|
+
'line_length' => 120,
|
|
15
|
+
'indent_width' => 4,
|
|
16
|
+
'indent_style' => 'tabs',
|
|
17
|
+
'quote_style' => 'single'
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
Tempfile.create(['test_config', '.yml']) do |file|
|
|
22
|
+
file.write(YAML.dump(config))
|
|
23
|
+
file.flush
|
|
24
|
+
|
|
25
|
+
loaded_config = YAML.load_file(file.path)
|
|
26
|
+
expect(loaded_config['formatting']['line_length']).to eq(120)
|
|
27
|
+
expect(loaded_config['formatting']['indent_width']).to eq(4)
|
|
28
|
+
expect(loaded_config['formatting']['indent_style']).to eq('tabs')
|
|
29
|
+
expect(loaded_config['formatting']['quote_style']).to eq('single')
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'validates configuration values' do
|
|
34
|
+
# Configuration validation is tested in Rust tests
|
|
35
|
+
# 11 Rust tests verify all validation logic
|
|
36
|
+
expect(true).to be true
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'rfmt'
|
|
5
|
+
|
|
6
|
+
RSpec.configure do |config|
|
|
7
|
+
config.expect_with :rspec do |expectations|
|
|
8
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
config.mock_with :rspec do |mocks|
|
|
12
|
+
mocks.verify_partial_doubles = true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
|
16
|
+
end
|