smarter_csv 1.17.3 → 1.17.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 +4 -4
- data/CHANGELOG.md +9 -1
- data/CONTRIBUTORS.md +2 -1
- data/README.md +2 -2
- data/docs/upgrade_wizard.html +14 -10
- data/lib/smarter_csv/reader.rb +18 -6
- data/lib/smarter_csv/version.rb +1 -1
- 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: 140f9359c26f8903b9075faeb59e9c1fc4b5c4b9dd5fcef664e12bb53fe13073
|
|
4
|
+
data.tar.gz: 0e7be3195610bcddb77870744a24f0eee9431643c4c28fcbea12d4b8663bb2db
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 176daa024372ade1d6431e5e4fd5355175cd1ebf03e7a216d70b8ff4554eb259a023969783b53118eba6c3fbf747a08e286ed7daad455ebc5cf8d7b61475d3d1
|
|
7
|
+
data.tar.gz: 8b1ca7263e5a54fc642c8f76bfd56577f6056784910acdcdcd0f18c6222c8793280016e749f2e08a61485bf8255cf341250ac1250a8d3ff424f8b07b1edbd51b
|
data/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
# SmarterCSV 1.x Change Log
|
|
3
3
|
|
|
4
4
|
> [!TIP]
|
|
5
|
-
> **Upgrading?** The [SmarterCSV Upgrade Wizard](https://tilo.github.io/smarter_csv/upgrade_wizard.html) walks you through what (if anything) you need to change for your specific version. Most
|
|
5
|
+
> **Upgrading?** The [SmarterCSV Upgrade Wizard](https://tilo.github.io/smarter_csv/upgrade_wizard.html) walks you through what (if anything) you need to change for your specific version. Most steps do not require any changes.
|
|
6
|
+
|
|
7
|
+
## 1.17.4 (2026-06-03)
|
|
8
|
+
|
|
9
|
+
### Bug Fix
|
|
10
|
+
|
|
11
|
+
- fixed [Issue #337](https://github.com/tilo/smarter_csv/issues/337): `Pathname` input no longer worked (regression since 1.17.0); passing a `Pathname` raised `NoMethodError: private method 'gets' called`. `SmarterCSV` now opens any path-like input (`String` or `Pathname`) and reads directly from any already-open IO. Thanks to [Alex Shenia](https://github.com/alexshenia)
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
|
|
7
15
|
## 1.17.3 (2026-05-26)
|
|
8
16
|
|
data/CONTRIBUTORS.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# A Big Thank You to all
|
|
1
|
+
# A Big Thank You to all 65 Contributors!!
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
A Big Thank you to everyone who filed issues, sent comments, and who contributed with pull requests:
|
|
@@ -67,3 +67,4 @@ A Big Thank you to everyone who filed issues, sent comments, and who contributed
|
|
|
67
67
|
* [Paho Lurie-Gregg](https://github.com/paholg)
|
|
68
68
|
* [Jonas Staškevičius](https://github.com/pirminis)
|
|
69
69
|
* [conorg](https://github.com/conorg)
|
|
70
|
+
* [Alex Shenia](https://github.com/alexshenia)
|
data/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
 [](https://codecov.io/gh/tilo/smarter_csv) [](https://rubygems.org/gems/smarter_csv) [](https://rubygems.org/gems/smarter_csv) [](https://www.ruby-toolbox.com/projects/smarter_csv) [](https://tilo.github.io/smarter_csv/upgrade_wizard.html)
|
|
5
5
|
|
|
6
6
|
> [!TIP]
|
|
7
|
-
> **Upgrading from an older version?** Use the [SmarterCSV Upgrade Wizard](https://tilo.github.io/smarter_csv/upgrade_wizard.html) to walk through what (if anything) you need to change for your specific version. Most
|
|
7
|
+
> **Upgrading from an older version?** Use the [SmarterCSV Upgrade Wizard](https://tilo.github.io/smarter_csv/upgrade_wizard.html) to walk through what (if anything) you need to change for your specific version. Most steps do not require any changes.
|
|
8
8
|
|
|
9
9
|
SmarterCSV is a high-performance CSV ingestion and generation for Ruby, focused on fast end-to-end CSV ingestion of real-world data — no silent failures, no surprises, not just tokenization.
|
|
10
10
|
|
|
@@ -336,7 +336,7 @@ For reporting issues, please:
|
|
|
336
336
|
* open a pull-request adding a test that demonstrates the issue
|
|
337
337
|
* mention your version of SmarterCSV, Ruby, Rails
|
|
338
338
|
|
|
339
|
-
# [A Special Thanks to all
|
|
339
|
+
# [A Special Thanks to all 65 Contributors!](CONTRIBUTORS.md) 🎉🎉🎉
|
|
340
340
|
|
|
341
341
|
|
|
342
342
|
## Contributing
|
data/docs/upgrade_wizard.html
CHANGED
|
@@ -153,7 +153,7 @@ button.primary:disabled:hover { background: #e6e6e6; }
|
|
|
153
153
|
<body>
|
|
154
154
|
|
|
155
155
|
<h1>SmarterCSV Upgrade Wizard</h1>
|
|
156
|
-
<p class="muted">This wizard walks you from your current version to the latest, one
|
|
156
|
+
<p class="muted">This wizard walks you from your current version to the latest, one step at a time.<br><br>Only the questions where you answer "Yes" will show migration steps.<br>Question answered with "No" represent risk-free upgrades.</p><br><br>
|
|
157
157
|
|
|
158
158
|
<div id="app"></div>
|
|
159
159
|
|
|
@@ -228,7 +228,7 @@ function renderHop(series, originalVersion) {
|
|
|
228
228
|
let body;
|
|
229
229
|
if (hop.actions.length === 0) {
|
|
230
230
|
body = `<div class="hop dropin">
|
|
231
|
-
|
|
231
|
+
You can upgrade directly to version ${targetRelease}. No changes needed.
|
|
232
232
|
</div>`;
|
|
233
233
|
} else {
|
|
234
234
|
body = `<div class="hop">
|
|
@@ -246,7 +246,7 @@ function renderHop(series, originalVersion) {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
const nextLabel = hop.to === LATEST ? `Finish at ${targetRelease} →` : `Continue to ${targetRelease} →`;
|
|
249
|
-
const reminder = hop.actions.length === 0 ? `<p class="reminder">You can upgrade directly to
|
|
249
|
+
const reminder = hop.actions.length === 0 ? `<p class="reminder">You can upgrade directly to version ${targetRelease}. No changes needed.</p>` :
|
|
250
250
|
`<p class="reminder">If there are actions listed above, please ensure they are fixed before clicking "Continue".</p>`;
|
|
251
251
|
app.innerHTML = `
|
|
252
252
|
<p class="progress">Upgrading from ${series}.x → ${targetRelease}</p>
|
|
@@ -288,7 +288,7 @@ function renderHop(series, originalVersion) {
|
|
|
288
288
|
} else if (yesAnswers.length === 0) {
|
|
289
289
|
// All answered, all "No" — nothing applies, upgrade is direct.
|
|
290
290
|
reminderEl.style.display = "";
|
|
291
|
-
reminderEl.textContent =
|
|
291
|
+
reminderEl.textContent = `You can upgrade directly to version ${targetRelease}. No changes needed.`;
|
|
292
292
|
} else {
|
|
293
293
|
// All answered, at least one "Yes" — actions must be applied first.
|
|
294
294
|
reminderEl.style.display = "";
|
|
@@ -342,17 +342,21 @@ function renderDone(originalVersion) {
|
|
|
342
342
|
const fullVersion = LATEST_RELEASE || LATEST;
|
|
343
343
|
const seriesOnly = LATEST;
|
|
344
344
|
const summaryHTML = renderSummary();
|
|
345
|
+
const introHTML = decisions.length === 0
|
|
346
|
+
? `<p><strong>You can upgrade directly to version ${fullVersion}. No changes needed.</strong></p>
|
|
347
|
+
<p>You're already in the ${seriesOnly}.x series, so the upgrade is just a Gemfile bump.</p>`
|
|
348
|
+
: `<p>You've completed all the upgrade steps from ${escapeHTML(originalVersion || "your current version")} to ${fullVersion} (the latest version in the ${seriesOnly}.x series).</p>`;
|
|
345
349
|
|
|
346
350
|
app.innerHTML = `
|
|
347
351
|
<div class="done">
|
|
348
352
|
<h2>You're done</h2>
|
|
349
|
-
|
|
353
|
+
${introHTML}
|
|
350
354
|
${summaryHTML}
|
|
351
355
|
<p>Update your <code>Gemfile</code> to:</p>
|
|
352
356
|
<pre><code>gem 'smarter_csv', '~> ${seriesOnly}.0'</code></pre>
|
|
353
357
|
<p>Then run:</p>
|
|
354
358
|
<pre><code>bundle update smarter_csv</code></pre>
|
|
355
|
-
<p>After that, run your test suite. If anything behaves unexpectedly, click "Start over" and walk back through the
|
|
359
|
+
<p>After that, run your test suite. If anything behaves unexpectedly, click "Start over" and walk back through the steps to find the migration item you might have missed.</p>
|
|
356
360
|
<p class="muted">Questions? Open an issue at <a href="https://github.com/tilo/smarter_csv/issues">github.com/tilo/smarter_csv/issues</a>.</p>
|
|
357
361
|
<p><button id="restart">Start over</button></p>
|
|
358
362
|
</div>
|
|
@@ -366,17 +370,17 @@ function renderSummary() {
|
|
|
366
370
|
const matchedCount = decisions.reduce((n, d) => n + d.matched.length, 0);
|
|
367
371
|
const dropInCount = decisions.filter(d => d.dropIn).length;
|
|
368
372
|
const intro = matchedCount === 0
|
|
369
|
-
? `<p>Good news
|
|
370
|
-
: `<p>
|
|
373
|
+
? `<p>Good news — <strong>none of the conditions applied to your code</strong>. The upgrade is just a Gemfile bump.</p>`
|
|
374
|
+
: `<p>Apply the following <strong>${matchedCount} change${matchedCount === 1 ? "" : "s"}</strong> to your code, then run <code>bundle update</code>:</p>`;
|
|
371
375
|
|
|
372
376
|
const list = decisions.map(d => {
|
|
373
377
|
const targetRelease = latestReleaseFor(d.to);
|
|
374
378
|
const heading = `<p class="summary-hop-heading"><strong>${d.from}.x → ${targetRelease}</strong></p>`;
|
|
375
379
|
if (d.dropIn) {
|
|
376
|
-
return `<div class="summary-hop">${heading}<p class="muted">
|
|
380
|
+
return `<div class="summary-hop">${heading}<p class="muted">No code changes needed for this step.</p></div>`;
|
|
377
381
|
}
|
|
378
382
|
if (d.matched.length === 0) {
|
|
379
|
-
return `<div class="summary-hop">${heading}<p class="muted">None of the conditions
|
|
383
|
+
return `<div class="summary-hop">${heading}<p class="muted">None of the conditions in this step applied to your code.</p></div>`;
|
|
380
384
|
}
|
|
381
385
|
const items = d.matched.map(a => `<li><strong>If</strong> ${a["if"]}<br>→ ${a.then}</li>`).join("");
|
|
382
386
|
return `<div class="summary-hop">${heading}<ul>${items}</ul></div>`;
|
data/lib/smarter_csv/reader.rb
CHANGED
|
@@ -32,13 +32,14 @@ module SmarterCSV
|
|
|
32
32
|
# rubocop:disable Naming/MethodName
|
|
33
33
|
def headerA
|
|
34
34
|
record_warning(type: :deprecation, code: :header_a_method) do
|
|
35
|
-
"
|
|
35
|
+
"Deprecation Warning: 'headerA' will be removed in future versions. Use 'headers'"
|
|
36
36
|
end
|
|
37
37
|
@headerA
|
|
38
38
|
end
|
|
39
39
|
# rubocop:enable Naming/MethodName
|
|
40
40
|
|
|
41
|
-
# first parameter:
|
|
41
|
+
# first parameter: a path (String or Pathname) to open, or an already-open readable IO
|
|
42
|
+
# (anything responding to #gets — File, StringIO, Tempfile, Zlib::GzipReader, pipes, ...)
|
|
42
43
|
def initialize(input, given_options = {})
|
|
43
44
|
@input = input
|
|
44
45
|
@has_rails = !!defined?(Rails)
|
|
@@ -123,7 +124,14 @@ module SmarterCSV
|
|
|
123
124
|
@verbose = options[:verbose]
|
|
124
125
|
|
|
125
126
|
begin
|
|
126
|
-
|
|
127
|
+
# Decide whether `input` is an already-open, readable stream or a path we must open.
|
|
128
|
+
# The reader reads lines via #gets (see file_io.rb and PeekableIO), so a public #gets
|
|
129
|
+
# is exactly what we need: real IOs (File, StringIO, Tempfile, Zlib::GzipReader, pipes,
|
|
130
|
+
# custom non-seekable streams) expose it, while path-like inputs (String, Pathname) do
|
|
131
|
+
# not — their only #gets is the private Kernel#gets. 1.17.0 narrowed this to
|
|
132
|
+
# input.is_a?(String), which sent Pathname down the IO branch and then called its
|
|
133
|
+
# private Kernel#gets, raising "private method 'gets' called" (issue #337).
|
|
134
|
+
fh = input.respond_to?(:gets) ? input : File.open(input, "r:#{options[:file_encoding]}")
|
|
127
135
|
|
|
128
136
|
# Rewindable inputs (File, Tempfile, StringIO, Zlib::GzipReader, ...) use
|
|
129
137
|
# native rewind for auto-detection — no wrapper overhead in the hot loop.
|
|
@@ -272,10 +280,14 @@ module SmarterCSV
|
|
|
272
280
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) if on_start || on_complete
|
|
273
281
|
|
|
274
282
|
if on_start
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
283
|
+
# Same path-vs-IO distinction as the File.open above: an already-open IO responds
|
|
284
|
+
# to #gets and we can't know its on-disk size, so we report its class name. A
|
|
285
|
+
# path-like input (String, or a Pathname via #to_path) gets its path and file size.
|
|
286
|
+
input_meta = if @input.respond_to?(:gets)
|
|
278
287
|
{ input: @input.class.name, file_size: nil }
|
|
288
|
+
else
|
|
289
|
+
path = @input.respond_to?(:to_path) ? @input.to_path : @input
|
|
290
|
+
{ input: path, file_size: (File.size(path) rescue nil) }
|
|
279
291
|
end
|
|
280
292
|
on_start.call(input_meta.merge(col_sep: options[:col_sep], row_sep: options[:row_sep]))
|
|
281
293
|
end
|
data/lib/smarter_csv/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smarter_csv
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.17.
|
|
4
|
+
version: 1.17.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tilo Sloboda
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-06-03 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: |
|
|
13
13
|
SmarterCSV is a high-performance CSV reader and writer for Ruby focused on
|