rfmt 1.3.2 → 1.3.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 +12 -0
- data/Cargo.lock +1 -1
- data/ext/rfmt/Cargo.toml +1 -1
- data/ext/rfmt/src/emitter/mod.rs +37 -60
- data/ext/rfmt/src/lib.rs +0 -11
- data/lib/rfmt/native_extension_loader.rb +138 -0
- data/lib/rfmt/version.rb +1 -1
- data/lib/rfmt.rb +4 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7d2092d9d53fa47024fcb8a13fb635a6da7eba5d4c51d3a8df854d551380037b
|
|
4
|
+
data.tar.gz: 59bb09f50cb7ee5a033328300a581e973879aaad56067d267b041c2070cac8bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7043e22d625b0b6a689f01950a6ed0fae7ab3fa1cfa2dcd51af544d72aadf8b0c3aa65a3465c9f9baabf2f1a000c37bddb2f2f57e2defd11344f6194ad3b68b
|
|
7
|
+
data.tar.gz: 407b70b3614da3ed19c74bd43d9491ee9bff1ce6cb1ef7f1e1d2d0b71068afb937bd5409668ae0c7454a6f2d12cb4764fa6df0273bef149980be30e0f9f1d7b6
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.3.3] - 2026-01-17
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Add native extension loader for Ruby 3.3+ compatibility (#65)
|
|
7
|
+
- Resolves LoadError on Ruby 3.3+ arm64-darwin systems
|
|
8
|
+
- Implements dynamic path resolution for version-specific directories
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- Remove unnecessary String clones in comment emission (performance optimization)
|
|
12
|
+
- Remove debug logs and obvious comments from codebase
|
|
13
|
+
- Update .gitignore with development artifacts
|
|
14
|
+
|
|
3
15
|
## [1.3.2] - 2026-01-09
|
|
4
16
|
|
|
5
17
|
### Added
|
data/Cargo.lock
CHANGED
data/ext/rfmt/Cargo.toml
CHANGED
data/ext/rfmt/src/emitter/mod.rs
CHANGED
|
@@ -62,13 +62,9 @@ impl Emitter {
|
|
|
62
62
|
|
|
63
63
|
self.emit_node(ast, 0)?;
|
|
64
64
|
|
|
65
|
-
// Find the last emitted code line for proper blank line handling
|
|
66
65
|
let last_code_line = Self::find_last_code_line(ast);
|
|
67
|
-
|
|
68
|
-
// Emit any remaining comments that weren't emitted
|
|
69
66
|
self.emit_remaining_comments(last_code_line)?;
|
|
70
67
|
|
|
71
|
-
// Ensure file ends with a newline
|
|
72
68
|
if !self.buffer.ends_with('\n') {
|
|
73
69
|
self.buffer.push('\n');
|
|
74
70
|
}
|
|
@@ -186,35 +182,26 @@ impl Emitter {
|
|
|
186
182
|
/// Emit comments that appear before a given line
|
|
187
183
|
/// Uses BTreeMap index for O(log n) lookup instead of O(n) iteration
|
|
188
184
|
fn emit_comments_before(&mut self, line: usize, indent_level: usize) -> Result<()> {
|
|
189
|
-
|
|
185
|
+
self.ensure_indent_cache(indent_level);
|
|
190
186
|
|
|
191
|
-
// Use indexed lookup instead of iterating all comments
|
|
192
187
|
let indices = self.get_comment_indices_before(line);
|
|
193
188
|
|
|
194
|
-
// Build list of comments to emit with their data
|
|
195
189
|
let mut comments_to_emit: Vec<_> = indices
|
|
196
190
|
.into_iter()
|
|
197
191
|
.map(|idx| {
|
|
198
192
|
let comment = &self.all_comments[idx];
|
|
199
|
-
(
|
|
200
|
-
idx,
|
|
201
|
-
comment.text.clone(),
|
|
202
|
-
comment.location.start_line,
|
|
203
|
-
comment.location.end_line,
|
|
204
|
-
)
|
|
193
|
+
(idx, comment.location.start_line, comment.location.end_line)
|
|
205
194
|
})
|
|
206
195
|
.collect();
|
|
207
196
|
|
|
208
|
-
|
|
209
|
-
comments_to_emit.sort_by_key(|(_, _, start, _)| *start);
|
|
197
|
+
comments_to_emit.sort_by_key(|(_, start, _)| *start);
|
|
210
198
|
|
|
211
199
|
let comments_count = comments_to_emit.len();
|
|
212
200
|
let mut last_comment_end_line: Option<usize> = None;
|
|
213
201
|
|
|
214
|
-
for (i, (idx,
|
|
202
|
+
for (i, (idx, comment_start_line, comment_end_line)) in
|
|
215
203
|
comments_to_emit.into_iter().enumerate()
|
|
216
204
|
{
|
|
217
|
-
// Preserve blank lines between comments
|
|
218
205
|
if let Some(prev_end) = last_comment_end_line {
|
|
219
206
|
let gap = comment_start_line.saturating_sub(prev_end);
|
|
220
207
|
for _ in 1..gap {
|
|
@@ -222,11 +209,14 @@ impl Emitter {
|
|
|
222
209
|
}
|
|
223
210
|
}
|
|
224
211
|
|
|
225
|
-
writeln!(
|
|
212
|
+
writeln!(
|
|
213
|
+
self.buffer,
|
|
214
|
+
"{}{}",
|
|
215
|
+
&self.indent_cache[indent_level], &self.all_comments[idx].text
|
|
216
|
+
)?;
|
|
226
217
|
self.emitted_comment_indices.insert(idx);
|
|
227
218
|
last_comment_end_line = Some(comment_end_line);
|
|
228
219
|
|
|
229
|
-
// Add blank line after the LAST comment if there was a gap to the code
|
|
230
220
|
if i == comments_count - 1 && line > comment_end_line + 1 {
|
|
231
221
|
self.buffer.push('\n');
|
|
232
222
|
}
|
|
@@ -255,33 +245,24 @@ impl Emitter {
|
|
|
255
245
|
end_line: usize,
|
|
256
246
|
indent_level: usize,
|
|
257
247
|
) -> Result<()> {
|
|
258
|
-
|
|
248
|
+
self.ensure_indent_cache(indent_level);
|
|
259
249
|
|
|
260
|
-
// Use indexed lookup instead of iterating all comments
|
|
261
250
|
let indices = self.get_comment_indices_in_range(start_line, end_line);
|
|
262
251
|
|
|
263
|
-
// Build list of comments to emit, filtering by end_line
|
|
264
252
|
let mut comments_to_emit: Vec<_> = indices
|
|
265
253
|
.into_iter()
|
|
266
254
|
.filter(|&idx| self.all_comments[idx].location.end_line < end_line)
|
|
267
255
|
.map(|idx| {
|
|
268
256
|
let comment = &self.all_comments[idx];
|
|
269
|
-
(
|
|
270
|
-
idx,
|
|
271
|
-
comment.text.clone(),
|
|
272
|
-
comment.location.start_line,
|
|
273
|
-
comment.location.end_line,
|
|
274
|
-
)
|
|
257
|
+
(idx, comment.location.start_line, comment.location.end_line)
|
|
275
258
|
})
|
|
276
259
|
.collect();
|
|
277
260
|
|
|
278
|
-
|
|
279
|
-
comments_to_emit.sort_by_key(|(_, _, start, _)| *start);
|
|
261
|
+
comments_to_emit.sort_by_key(|(_, start, _)| *start);
|
|
280
262
|
|
|
281
263
|
let mut last_comment_end_line: Option<usize> = None;
|
|
282
264
|
|
|
283
|
-
for (idx,
|
|
284
|
-
// Preserve blank lines between comments
|
|
265
|
+
for (idx, comment_start_line, comment_end_line) in comments_to_emit {
|
|
285
266
|
if let Some(prev_end) = last_comment_end_line {
|
|
286
267
|
let gap = comment_start_line.saturating_sub(prev_end);
|
|
287
268
|
for _ in 1..gap {
|
|
@@ -289,7 +270,11 @@ impl Emitter {
|
|
|
289
270
|
}
|
|
290
271
|
}
|
|
291
272
|
|
|
292
|
-
writeln!(
|
|
273
|
+
writeln!(
|
|
274
|
+
self.buffer,
|
|
275
|
+
"{}{}",
|
|
276
|
+
&self.indent_cache[indent_level], &self.all_comments[idx].text
|
|
277
|
+
)?;
|
|
293
278
|
self.emitted_comment_indices.insert(idx);
|
|
294
279
|
last_comment_end_line = Some(comment_end_line);
|
|
295
280
|
}
|
|
@@ -306,39 +291,35 @@ impl Emitter {
|
|
|
306
291
|
indent_level: usize,
|
|
307
292
|
prev_line: usize,
|
|
308
293
|
) -> Result<()> {
|
|
309
|
-
|
|
294
|
+
self.ensure_indent_cache(indent_level);
|
|
310
295
|
|
|
311
|
-
// Use indexed lookup instead of iterating all comments
|
|
312
296
|
let indices = self.get_comment_indices_in_range(start_line, end_line);
|
|
313
297
|
|
|
314
|
-
// Build list of comments to emit, filtering by end_line
|
|
315
298
|
let mut comments_to_emit: Vec<_> = indices
|
|
316
299
|
.into_iter()
|
|
317
300
|
.filter(|&idx| self.all_comments[idx].location.end_line < end_line)
|
|
318
301
|
.map(|idx| {
|
|
319
302
|
let comment = &self.all_comments[idx];
|
|
320
|
-
(
|
|
321
|
-
idx,
|
|
322
|
-
comment.text.clone(),
|
|
323
|
-
comment.location.start_line,
|
|
324
|
-
comment.location.end_line,
|
|
325
|
-
)
|
|
303
|
+
(idx, comment.location.start_line, comment.location.end_line)
|
|
326
304
|
})
|
|
327
305
|
.collect();
|
|
328
306
|
|
|
329
|
-
|
|
330
|
-
comments_to_emit.sort_by_key(|(_, _, start, _)| *start);
|
|
307
|
+
comments_to_emit.sort_by_key(|(_, start, _)| *start);
|
|
331
308
|
|
|
332
309
|
let mut last_end_line: usize = prev_line;
|
|
333
310
|
|
|
334
|
-
for (idx,
|
|
311
|
+
for (idx, comment_start_line, comment_end_line) in comments_to_emit {
|
|
335
312
|
// Preserve blank lines between previous content and this comment
|
|
336
313
|
let gap = comment_start_line.saturating_sub(last_end_line);
|
|
337
314
|
for _ in 1..gap {
|
|
338
315
|
self.buffer.push('\n');
|
|
339
316
|
}
|
|
340
317
|
|
|
341
|
-
writeln!(
|
|
318
|
+
writeln!(
|
|
319
|
+
self.buffer,
|
|
320
|
+
"{}{}",
|
|
321
|
+
&self.indent_cache[indent_level], &self.all_comments[idx].text
|
|
322
|
+
)?;
|
|
342
323
|
self.emitted_comment_indices.insert(idx);
|
|
343
324
|
last_end_line = comment_end_line;
|
|
344
325
|
}
|
|
@@ -352,15 +333,12 @@ impl Emitter {
|
|
|
352
333
|
// Use indexed lookup for O(log n) access
|
|
353
334
|
let indices = self.get_comment_indices_on_line(line);
|
|
354
335
|
|
|
355
|
-
//
|
|
356
|
-
let indices_to_emit: Vec<
|
|
357
|
-
.into_iter()
|
|
358
|
-
.map(|idx| (idx, self.all_comments[idx].text.clone()))
|
|
359
|
-
.collect();
|
|
336
|
+
// Collect indices only (no text clone needed)
|
|
337
|
+
let indices_to_emit: Vec<usize> = indices;
|
|
360
338
|
|
|
361
|
-
// Now emit the collected comments
|
|
362
|
-
for
|
|
363
|
-
write!(self.buffer, " {}", text)?;
|
|
339
|
+
// Now emit the collected comments by accessing text at write time
|
|
340
|
+
for idx in indices_to_emit {
|
|
341
|
+
write!(self.buffer, " {}", &self.all_comments[idx].text)?;
|
|
364
342
|
self.emitted_comment_indices.insert(idx);
|
|
365
343
|
}
|
|
366
344
|
|
|
@@ -1311,9 +1289,9 @@ impl Emitter {
|
|
|
1311
1289
|
Ok(())
|
|
1312
1290
|
}
|
|
1313
1291
|
|
|
1314
|
-
///
|
|
1315
|
-
|
|
1316
|
-
|
|
1292
|
+
/// Ensure indent cache has entries up to and including the given level
|
|
1293
|
+
/// This allows pre-building the cache before borrowing self.indent_cache
|
|
1294
|
+
fn ensure_indent_cache(&mut self, level: usize) {
|
|
1317
1295
|
while self.indent_cache.len() <= level {
|
|
1318
1296
|
let len = self.indent_cache.len();
|
|
1319
1297
|
let indent = match self.config.formatting.indent_style {
|
|
@@ -1322,13 +1300,12 @@ impl Emitter {
|
|
|
1322
1300
|
};
|
|
1323
1301
|
self.indent_cache.push(indent);
|
|
1324
1302
|
}
|
|
1325
|
-
&self.indent_cache[level]
|
|
1326
1303
|
}
|
|
1327
1304
|
|
|
1328
1305
|
/// Emit indentation
|
|
1329
1306
|
fn emit_indent(&mut self, level: usize) -> Result<()> {
|
|
1330
|
-
|
|
1331
|
-
write!(self.buffer, "{}",
|
|
1307
|
+
self.ensure_indent_cache(level);
|
|
1308
|
+
write!(self.buffer, "{}", &self.indent_cache[level])?;
|
|
1332
1309
|
Ok(())
|
|
1333
1310
|
}
|
|
1334
1311
|
|
data/ext/rfmt/src/lib.rs
CHANGED
|
@@ -14,25 +14,16 @@ 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");
|
|
18
17
|
let policy = SecurityPolicy::default();
|
|
19
18
|
|
|
20
19
|
policy
|
|
21
20
|
.validate_source_size(&source)
|
|
22
21
|
.map_err(|e| e.to_magnus_error(ruby))?;
|
|
23
22
|
|
|
24
|
-
log::debug!("Source code validated, size: {} bytes", source.len());
|
|
25
|
-
|
|
26
23
|
let parser = PrismAdapter::new();
|
|
27
24
|
let ast = parser.parse(&json).map_err(|e| e.to_magnus_error(ruby))?;
|
|
28
25
|
|
|
29
|
-
// Load configuration from file or use defaults
|
|
30
|
-
log::info!("Attempting to discover config file...");
|
|
31
26
|
let config = Config::discover().map_err(|e| e.to_magnus_error(ruby))?;
|
|
32
|
-
log::info!(
|
|
33
|
-
"Config loaded successfully, line_length: {}",
|
|
34
|
-
config.formatting.line_length
|
|
35
|
-
);
|
|
36
27
|
let mut emitter = Emitter::with_source(config, source);
|
|
37
28
|
|
|
38
29
|
let formatted = emitter.emit(&ast).map_err(|e| e.to_magnus_error(ruby))?;
|
|
@@ -56,7 +47,6 @@ fn rust_version() -> String {
|
|
|
56
47
|
#[magnus::init]
|
|
57
48
|
fn init(_ruby: &Ruby) -> Result<(), Error> {
|
|
58
49
|
logging::RfmtLogger::init();
|
|
59
|
-
log::info!("Initializing rfmt Rust extension");
|
|
60
50
|
|
|
61
51
|
let module = define_module("Rfmt")?;
|
|
62
52
|
|
|
@@ -64,6 +54,5 @@ fn init(_ruby: &Ruby) -> Result<(), Error> {
|
|
|
64
54
|
module.define_singleton_method("parse_to_json", function!(parse_to_json, 1))?;
|
|
65
55
|
module.define_singleton_method("rust_version", function!(rust_version, 0))?;
|
|
66
56
|
|
|
67
|
-
log::info!("rfmt Rust extension initialized successfully");
|
|
68
57
|
Ok(())
|
|
69
58
|
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rfmt
|
|
4
|
+
# Handles loading of native extension across different Ruby versions
|
|
5
|
+
# Ruby 3.3+ places native extensions in version-specific subdirectories
|
|
6
|
+
module NativeExtensionLoader
|
|
7
|
+
class << self
|
|
8
|
+
# Load the native extension, trying multiple possible paths
|
|
9
|
+
# @return [Boolean] true if successfully loaded
|
|
10
|
+
# @raise [LoadError] if the extension cannot be found
|
|
11
|
+
def load_extension
|
|
12
|
+
debug_log "Loading native extension for Ruby #{RUBY_VERSION}"
|
|
13
|
+
|
|
14
|
+
possible_paths = build_possible_paths
|
|
15
|
+
debug_log "Trying paths: #{possible_paths.inspect}"
|
|
16
|
+
|
|
17
|
+
load_from_paths(possible_paths) || raise(LoadError, build_error_message(possible_paths))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# Try loading from multiple paths
|
|
23
|
+
# @param paths [Array<String>] paths to try
|
|
24
|
+
# @return [Boolean, nil] true if loaded, nil otherwise
|
|
25
|
+
def load_from_paths(paths)
|
|
26
|
+
paths.each do |path|
|
|
27
|
+
if try_load_extension(path)
|
|
28
|
+
debug_log "Successfully loaded from: #{path}"
|
|
29
|
+
return true
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Build list of possible paths for the native extension
|
|
36
|
+
# @return [Array<String>] paths to try, in order of preference
|
|
37
|
+
def build_possible_paths
|
|
38
|
+
paths = []
|
|
39
|
+
|
|
40
|
+
# Ruby 3.3+ style: version-specific subdirectory
|
|
41
|
+
paths << version_specific_path if ruby_version >= '3.3'
|
|
42
|
+
|
|
43
|
+
# Ruby 3.0-3.2 style: might use version directory
|
|
44
|
+
paths << version_specific_path if ruby_version >= '3.0' && ruby_version < '3.3'
|
|
45
|
+
|
|
46
|
+
# Legacy/fallback: direct placement
|
|
47
|
+
paths << File.join(__dir__, 'rfmt')
|
|
48
|
+
|
|
49
|
+
# Additional fallback: check for .bundle extension explicitly
|
|
50
|
+
paths << File.join(__dir__, 'rfmt.bundle')
|
|
51
|
+
|
|
52
|
+
paths.uniq
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Get version-specific path
|
|
56
|
+
# @return [String] path with version directory
|
|
57
|
+
def version_specific_path
|
|
58
|
+
File.join(__dir__, ruby_version_dir, 'rfmt')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Try to load extension from a specific path
|
|
62
|
+
# @param path [String] path to try
|
|
63
|
+
# @return [Boolean] true if successful, false otherwise
|
|
64
|
+
def try_load_extension(path)
|
|
65
|
+
require path
|
|
66
|
+
true
|
|
67
|
+
rescue LoadError => e
|
|
68
|
+
debug_log "Failed to load from #{path}: #{e.message}"
|
|
69
|
+
false
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Get Ruby version for comparison
|
|
73
|
+
# @return [String] Ruby version string
|
|
74
|
+
def ruby_version
|
|
75
|
+
RUBY_VERSION
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Get Ruby version directory name (e.g., "3.3" for Ruby 3.3.0)
|
|
79
|
+
# @return [String] version directory name
|
|
80
|
+
def ruby_version_dir
|
|
81
|
+
RUBY_VERSION.split('.')[0..1].join('.')
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Build detailed error message when extension cannot be loaded
|
|
85
|
+
# @param tried_paths [Array<String>] paths that were tried
|
|
86
|
+
# @return [String] error message
|
|
87
|
+
def build_error_message(tried_paths)
|
|
88
|
+
[
|
|
89
|
+
error_header,
|
|
90
|
+
format_tried_paths(tried_paths),
|
|
91
|
+
error_explanation,
|
|
92
|
+
workaround_instructions
|
|
93
|
+
].join("\n")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Error message header
|
|
97
|
+
# @return [String] header text
|
|
98
|
+
def error_header
|
|
99
|
+
"Unable to load rfmt native extension for Ruby #{RUBY_VERSION}.\n"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Format list of tried paths
|
|
103
|
+
# @param paths [Array<String>] paths that were tried
|
|
104
|
+
# @return [String] formatted path list
|
|
105
|
+
def format_tried_paths(paths)
|
|
106
|
+
"Tried the following paths:\n#{paths.map { |p| " - #{p}" }.join("\n")}\n"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Error explanation text
|
|
110
|
+
# @return [String] explanation
|
|
111
|
+
def error_explanation
|
|
112
|
+
"This might be a packaging issue with the gem for your Ruby version.\n"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Workaround instructions
|
|
116
|
+
# @return [String] instructions
|
|
117
|
+
def workaround_instructions
|
|
118
|
+
<<~MSG.chomp
|
|
119
|
+
Workaround:
|
|
120
|
+
1. Check if rfmt.bundle exists in: #{__dir__}/
|
|
121
|
+
2. If it's in a subdirectory, create a symlink:
|
|
122
|
+
cd #{__dir__}
|
|
123
|
+
ln -sf <subdirectory>/rfmt.bundle rfmt.bundle
|
|
124
|
+
|
|
125
|
+
Please report this issue at: https://github.com/fs0414/rfmt/issues
|
|
126
|
+
MSG
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Log debug information if RFMT_DEBUG is set
|
|
130
|
+
# @param message [String] message to log
|
|
131
|
+
def debug_log(message)
|
|
132
|
+
return unless ENV['RFMT_DEBUG']
|
|
133
|
+
|
|
134
|
+
warn "[RFMT::NativeExtensionLoader] #{message}"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
data/lib/rfmt/version.rb
CHANGED
data/lib/rfmt.rb
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'rfmt/version'
|
|
4
|
-
require_relative 'rfmt/
|
|
4
|
+
require_relative 'rfmt/native_extension_loader'
|
|
5
5
|
require_relative 'rfmt/prism_bridge'
|
|
6
6
|
|
|
7
|
+
# Load native extension with version-aware loader
|
|
8
|
+
Rfmt::NativeExtensionLoader.load_extension
|
|
9
|
+
|
|
7
10
|
module Rfmt
|
|
8
11
|
class Error < StandardError; end
|
|
9
12
|
# Errors from Rust side
|
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: 1.3.
|
|
4
|
+
version: 1.3.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- fujitani sora
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-01-
|
|
11
|
+
date: 2026-01-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rb_sys
|
|
@@ -56,6 +56,7 @@ files:
|
|
|
56
56
|
- lib/rfmt/cache.rb
|
|
57
57
|
- lib/rfmt/cli.rb
|
|
58
58
|
- lib/rfmt/configuration.rb
|
|
59
|
+
- lib/rfmt/native_extension_loader.rb
|
|
59
60
|
- lib/rfmt/prism_bridge.rb
|
|
60
61
|
- lib/rfmt/prism_node_extractor.rb
|
|
61
62
|
- lib/rfmt/version.rb
|