rfmt 0.3.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1344ebd75598608c54dc975f8afecc17be05152039542ac1c1e80007086530fc
4
- data.tar.gz: b5a29adb45e5163fdfdbbea2526d4ac72bdbca410ee86e888ecb224f3b98c922
3
+ metadata.gz: 3077996bae0d4959192fb7885a197916fc85679858ebc10ea00ea8696bf6d320
4
+ data.tar.gz: c3adf00614cc4ed60df41858c482e77b9618f06f7dadc7e9bc016c7b4d419f99
5
5
  SHA512:
6
- metadata.gz: 71db0a1b94b8a2288a5fae7e3a09ec41fac6e834abd9760fd45b4ac7dfef71baac7ada32582a6018b74fa22a6d0711f529b8372c491179dfbe66cc9c56c287aa
7
- data.tar.gz: c7dc265d4ba68a15c653715bd26d8c087be6d361a7bb3170bd59057c0b9a65cfbf2093c02ff8528dcffd8a2b4ca445faef2fdc4fa4c5035016360d64ad297b9e
6
+ metadata.gz: 8c1a042bcbcd8e74ac67918428fee08f8f4cf85e4f5f67a0cd9196bf7305489808176c442e8d388ae50c32c7d3f329706788c02a62ef69708be9126e600556bf
7
+ data.tar.gz: 2f13782fff7bb4eaea95a78bc8e3d55c4f00395074b9e5befb6d93e66b803673f5bfb1f285ae74facb009d65dbdf2ae8322f405232277994c010d88135d62746
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
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
+
3
20
  ## [0.3.0] - 2025-11-25
4
21
 
5
22
  ### Changed
data/Cargo.lock CHANGED
@@ -1219,7 +1219,7 @@ checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
1219
1219
 
1220
1220
  [[package]]
1221
1221
  name = "rfmt"
1222
- version = "0.3.0"
1222
+ version = "0.4.0"
1223
1223
  dependencies = [
1224
1224
  "anyhow",
1225
1225
  "clap",
data/README.md CHANGED
@@ -4,8 +4,7 @@
4
4
 
5
5
  A Ruby code formatter written in Rust
6
6
 
7
- [![Gem Version](https://badge.fury.io/rb/rfmt.svg)](https://badge.fury.io/rb/rfmt)
8
- [![Test Status](https://github.com/fujitanisora/rfmt/workflows/test/badge.svg)](https://github.com/fujitanisora/rfmt/actions)
7
+ [![Gem Version](https://badge.fury.io/rb/rfmt.svg)](https://rubygems.org/gems/rfmt)
9
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
9
 
11
10
  [Installation](#installation) •
@@ -20,6 +19,8 @@ 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
26
  - **Opinionated**: Minimal configuration with consistent output
@@ -44,7 +45,7 @@ Enforces code style rules:
44
45
 
45
46
  ## Performance Benchmarks
46
47
 
47
- Performance comparison with RuboCop on a Rails project (111 files, 3,241 lines):
48
+ Execution time comparison on a Rails project (111 files, 3,241 lines):
48
49
 
49
50
  | Test Type | Files | rfmt | RuboCop | Ratio |
50
51
  |-----------|-------|------|---------|-------|
@@ -52,6 +53,13 @@ Performance comparison with RuboCop on a Rails project (111 files, 3,241 lines):
52
53
  | Directory | 14 | 176ms | 1.68s | 9.6x |
53
54
  | Full Project (check) | 111 | 172ms | 4.36s | 25.4x |
54
55
 
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
62
+
55
63
  **Observations:**
56
64
  - rfmt execution time remains constant (172-191ms) regardless of file count
57
65
  - Low variance across runs (standard deviation: 8-23ms)
@@ -59,7 +67,7 @@ Performance comparison with RuboCop on a Rails project (111 files, 3,241 lines):
59
67
  **Test Environment:**
60
68
  - CPU: Apple Silicon (arm64)
61
69
  - Ruby: 3.4.5
62
- - rfmt: 0.2.4, RuboCop: 1.81.7
70
+ - rfmt: 0.3.0, RuboCop: 1.81.7
63
71
 
64
72
  See [detailed benchmark report](docs/benchmark.md) for complete data.
65
73
 
@@ -146,13 +154,13 @@ rfmt init --force
146
154
  Format a single file:
147
155
 
148
156
  ```bash
149
- rfmt format lib/user.rb
157
+ rfmt exec lib/user.rb
150
158
  ```
151
159
 
152
160
  Format multiple files:
153
161
 
154
162
  ```bash
155
- rfmt format lib/**/*.rb
163
+ rfmt exec lib/**/*.rb
156
164
  ```
157
165
 
158
166
  Check if files need formatting (CI/CD):
@@ -164,7 +172,15 @@ rfmt check .
164
172
  Show diff without modifying files:
165
173
 
166
174
  ```bash
167
- rfmt format lib/user.rb --diff
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
168
184
  ```
169
185
 
170
186
  ### Ruby API
@@ -255,6 +271,48 @@ class User < ApplicationRecord
255
271
  end
256
272
  ```
257
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
+
258
316
  ## Documentation
259
317
 
260
318
  Documentation is available in the [docs](docs/) directory:
data/ext/rfmt/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rfmt"
3
- version = "0.3.0"
3
+ version = "0.4.0"
4
4
  edition = "2021"
5
5
  authors = ["fujitani sora <fujitanisora0414@gmail.com>"]
6
6
  license = "MIT"
@@ -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
@@ -181,6 +181,7 @@ impl Config {
181
181
  }
182
182
 
183
183
  /// Get the indent string based on configuration
184
+ #[cfg(test)]
184
185
  pub fn indent_string(&self) -> String {
185
186
  match self.formatting.indent_style {
186
187
  IndentStyle::Spaces => " ".repeat(self.formatting.indent_width),
@@ -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(&mut self, node: &Node, indent_level: usize, is_elsif: bool, keyword: &str) -> Result<()> {
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
- write!(self.buffer, "else\n")?;
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!("Config loaded successfully, line_length: {}", config.formatting.line_length);
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(LevelFilter::Info);
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 'format [FILES]', 'Format Ruby files'
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 format(*files)
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 :format, files, check: true, write: false
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rfmt
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rfmt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - fujitani sora