rfmt 0.2.3 → 0.2.4

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: c712093f002557a29995a2838caede692a26e86d492c7f9f735e8fe9f2a5f5f4
4
- data.tar.gz: a7ce48fbf06a56879d803cb848786310ff5e6dc091de1d8f8a9ff47a0bb00dac
3
+ metadata.gz: d42c0061474a8e7ef36fc5cbce1d7bfdad2bc5a9dbbff9b1a2c2b700b373c6ca
4
+ data.tar.gz: f12d17ab726936fbdf69e4e5aaf3bca55fadf49230aa641adf0cba61c363f5ca
5
5
  SHA512:
6
- metadata.gz: '05954d426b7b6951e330d55d469ea78ebbf75350d755e0107eb0c4de32f5b11afd9373fbeabff3f7c2c902cfada70f4fae276c8b5d0d4d3b00eb3514a467fa0e'
7
- data.tar.gz: cd4b6992cd4d795dfe8bd91f74504212337bcf7c13c736822919a071abda7ff0e1712f24e277786fa8b9a3ba6150b0727d33f415631c1707b6277c5612c94dbe
6
+ metadata.gz: 51948c8616f667de54435f87f7e154209c27777e82a84ada9f73d97c8928f68a063da72c1d7268035ca7d8d6e3eec658e4f6d874770658501edaad68a512ecdf
7
+ data.tar.gz: e9a794b23d30ba314aa2b0f5fcacb6bbaff7408430bab6623169ef7d76fad53f32f58789e2a0a828a3b9e38dc074ca22bb0c4ff93f023e7c1a8c000081ba66e5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.4] - 2025-11-25
4
+
5
+ ### Fixed
6
+ - Fixed if-else expression formatting
7
+
3
8
  ## [0.2.3] - 2025-01-25
4
9
 
5
10
  ### Added
data/Cargo.lock CHANGED
@@ -1219,7 +1219,7 @@ checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
1219
1219
 
1220
1220
  [[package]]
1221
1221
  name = "rfmt"
1222
- version = "0.2.3"
1222
+ version = "0.2.4"
1223
1223
  dependencies = [
1224
1224
  "anyhow",
1225
1225
  "clap",
data/ext/rfmt/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rfmt"
3
- version = "0.2.3"
3
+ version = "0.2.4"
4
4
  edition = "2021"
5
5
  authors = ["fujitani sora <fujitanisora0414@gmail.com>"]
6
6
  license = "MIT"
@@ -40,6 +40,7 @@ pub enum NodeType {
40
40
  // Expressions
41
41
  CallNode,
42
42
  IfNode,
43
+ ElseNode,
43
44
  UnlessNode,
44
45
 
45
46
  // Literals
@@ -83,6 +84,7 @@ impl NodeType {
83
84
  "def_node" => Self::DefNode,
84
85
  "call_node" => Self::CallNode,
85
86
  "if_node" => Self::IfNode,
87
+ "else_node" => Self::ElseNode,
86
88
  "unless_node" => Self::UnlessNode,
87
89
  "string_node" => Self::StringNode,
88
90
  "integer_node" => Self::IntegerNode,
@@ -110,7 +110,7 @@ impl Config {
110
110
  for filename in &config_files {
111
111
  let config_path = current_dir.join(filename);
112
112
  if config_path.exists() {
113
- log::debug!("Found config file: {:?}", config_path);
113
+ log::info!("Found config file: {:?}", config_path);
114
114
  return Self::load_file(&config_path);
115
115
  }
116
116
  }
@@ -133,7 +133,7 @@ impl Config {
133
133
  }
134
134
  }
135
135
 
136
- log::debug!("No config file found, using defaults");
136
+ log::info!("No config file found, using defaults");
137
137
  Ok(Config::default())
138
138
  }
139
139
 
@@ -113,6 +113,8 @@ impl Emitter {
113
113
  NodeType::ClassNode => self.emit_class(node, indent_level)?,
114
114
  NodeType::ModuleNode => self.emit_module(node, indent_level)?,
115
115
  NodeType::DefNode => self.emit_method(node, indent_level)?,
116
+ NodeType::IfNode => self.emit_if_unless(node, indent_level, false, "if")?,
117
+ NodeType::UnlessNode => self.emit_if_unless(node, indent_level, false, "unless")?,
116
118
  _ => self.emit_generic(node, indent_level)?,
117
119
  }
118
120
  Ok(())
@@ -304,6 +306,122 @@ impl Emitter {
304
306
  Ok(())
305
307
  }
306
308
 
309
+ /// Emit if/unless/elsif/else node
310
+ /// is_elsif: true if this is an elsif clause (don't emit 'end')
311
+ /// keyword: "if" or "unless"
312
+ fn emit_if_unless(&mut self, node: &Node, indent_level: usize, is_elsif: bool, keyword: &str) -> Result<()> {
313
+ // Check if this is a postfix if (modifier form)
314
+ // In postfix if, the statements come before the if keyword in source
315
+ let is_postfix = if let (Some(predicate), Some(statements)) =
316
+ (node.children.first(), node.children.get(1)) {
317
+ statements.location.start_offset < predicate.location.start_offset
318
+ } else {
319
+ false
320
+ };
321
+
322
+ // Postfix if/unless: "statement if/unless condition"
323
+ if is_postfix && !is_elsif {
324
+ self.emit_comments_before(node.location.start_line, indent_level)?;
325
+ self.emit_indent(indent_level)?;
326
+
327
+ // Emit statement
328
+ if let Some(statements) = node.children.get(1) {
329
+ if matches!(statements.node_type, NodeType::StatementsNode) {
330
+ // Extract the statement text (without extra indentation)
331
+ if !self.source.is_empty() {
332
+ let start = statements.location.start_offset;
333
+ let end = statements.location.end_offset;
334
+ if let Some(text) = self.source.get(start..end) {
335
+ write!(self.buffer, "{}", text.trim())?;
336
+ }
337
+ }
338
+ }
339
+ }
340
+
341
+ write!(self.buffer, " {} ", keyword)?;
342
+
343
+ // Emit condition
344
+ if let Some(predicate) = node.children.first() {
345
+ if !self.source.is_empty() {
346
+ let start = predicate.location.start_offset;
347
+ let end = predicate.location.end_offset;
348
+ if let Some(text) = self.source.get(start..end) {
349
+ write!(self.buffer, "{}", text)?;
350
+ }
351
+ }
352
+ }
353
+
354
+ return Ok(());
355
+ }
356
+
357
+ // Normal if/unless/elsif
358
+ if !is_elsif {
359
+ self.emit_comments_before(node.location.start_line, indent_level)?;
360
+ }
361
+
362
+ // Emit 'if'/'unless' or 'elsif' keyword
363
+ self.emit_indent(indent_level)?;
364
+ if is_elsif {
365
+ write!(self.buffer, "elsif ")?;
366
+ } else {
367
+ write!(self.buffer, "{} ", keyword)?;
368
+ }
369
+
370
+ // Emit predicate (condition) - first child
371
+ if let Some(predicate) = node.children.first() {
372
+ // Extract predicate from source
373
+ if !self.source.is_empty() {
374
+ let start = predicate.location.start_offset;
375
+ let end = predicate.location.end_offset;
376
+ if let Some(text) = self.source.get(start..end) {
377
+ write!(self.buffer, "{}", text)?;
378
+ }
379
+ }
380
+ }
381
+
382
+ self.buffer.push('\n');
383
+
384
+ // Emit then clause (second child is StatementsNode)
385
+ if let Some(statements) = node.children.get(1) {
386
+ if matches!(statements.node_type, NodeType::StatementsNode) {
387
+ self.emit_statements(statements, indent_level + 1)?;
388
+ self.buffer.push('\n');
389
+ }
390
+ }
391
+
392
+ // Check for elsif/else (third child)
393
+ if let Some(consequent) = node.children.get(2) {
394
+ match &consequent.node_type {
395
+ NodeType::IfNode => {
396
+ // This is an elsif clause (only valid for if, not unless)
397
+ self.emit_if_unless(consequent, indent_level, true, "if")?;
398
+ }
399
+ NodeType::ElseNode => {
400
+ // This is an else clause
401
+ self.emit_indent(indent_level)?;
402
+ write!(self.buffer, "else\n")?;
403
+
404
+ // Emit else body (first child of ElseNode)
405
+ if let Some(else_statements) = consequent.children.first() {
406
+ if matches!(else_statements.node_type, NodeType::StatementsNode) {
407
+ self.emit_statements(else_statements, indent_level + 1)?;
408
+ self.buffer.push('\n');
409
+ }
410
+ }
411
+ }
412
+ _ => {}
413
+ }
414
+ }
415
+
416
+ // Only emit 'end' for the outermost if (not for elsif)
417
+ if !is_elsif {
418
+ self.emit_indent(indent_level)?;
419
+ write!(self.buffer, "end")?;
420
+ }
421
+
422
+ Ok(())
423
+ }
424
+
307
425
  /// Emit generic node by extracting from source
308
426
  fn emit_generic(&mut self, node: &Node, indent_level: usize) -> Result<()> {
309
427
  // Emit any comments before this node
data/ext/rfmt/src/lib.rs CHANGED
@@ -14,6 +14,7 @@ use magnus::{define_module, function, prelude::*, Error, Ruby};
14
14
  use parser::{PrismAdapter, RubyParser};
15
15
 
16
16
  fn format_ruby_code(ruby: &Ruby, source: String, json: String) -> Result<String, Error> {
17
+ log::info!("format_ruby_code called");
17
18
  let policy = SecurityPolicy::default();
18
19
 
19
20
  policy
@@ -26,7 +27,9 @@ fn format_ruby_code(ruby: &Ruby, source: String, json: String) -> Result<String,
26
27
  let ast = parser.parse(&json).map_err(|e| e.to_magnus_error(ruby))?;
27
28
 
28
29
  // Load configuration from file or use defaults
30
+ log::info!("Attempting to discover config file...");
29
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);
30
33
  let mut emitter = Emitter::with_source(config, source);
31
34
 
32
35
  let formatted = emitter.emit(&ast).map_err(|e| e.to_magnus_error(ruby))?;
@@ -22,7 +22,11 @@ impl RfmtLogger {
22
22
  }
23
23
 
24
24
  pub fn init() {
25
- let logger = Self::new(LevelFilter::Info);
25
+ let level = std::env::var("RFMT_LOG")
26
+ .ok()
27
+ .and_then(|s| s.parse().ok())
28
+ .unwrap_or(LevelFilter::Info);
29
+ let logger = Self::new(level);
26
30
  log::set_boxed_logger(Box::new(logger)).expect("Failed to initialize logger");
27
31
  log::set_max_level(LevelFilter::Trace);
28
32
  }
@@ -159,6 +159,8 @@ module Rfmt
159
159
  node.statements,
160
160
  node.consequent
161
161
  ].compact
162
+ when Prism::ElseNode
163
+ [node.statements].compact
162
164
  when Prism::ArrayNode
163
165
  node.elements || []
164
166
  when Prism::HashNode
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.2.3'
4
+ VERSION = '0.2.4'
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.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - fujitani sora