dsv 0.12.11 → 0.12.12
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 +9 -0
- data/README.md +9 -0
- data/TODO +25 -26
- data/lib/DSV/VERSION.rb +1 -1
- data/lib/dsv.rb +11 -3
- data/test/dsv_test.rb +15 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d83c84d7b20fd4f67811f8259313a7c9f7c52cb48430feab0316c96137c3bbd0
|
|
4
|
+
data.tar.gz: 26bf580f0b29c4886796f267a415548bec6354009bede7a12b45b8fbbe3668a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9ee707193d1e740d503ec877f0c079a2868ab3ba848459771760cf96992b002763d6e337e3a9b9ac6f97428c98cf4700b5b32866e00a5729ab3fa50c5ba24094
|
|
7
|
+
data.tar.gz: 007524b8e1cffeb88f7d12b6ebe195b07aaafe85cc060bb1b74c6b372869e944505983ac3629ecabbce84f7f28fecc7e72537133e14ac19e5040dde8020f6344
|
data/CHANGELOG
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## 20261103
|
|
4
4
|
|
|
5
|
+
0.12.12: as_array: with a column selection gives the columns selected.
|
|
6
|
+
|
|
7
|
+
1. ~ parse_fields(): under as_array:, a selection gives the selected fields; + positions(). Each column not selected had come back as nil, and a selection by position had lost its values.
|
|
8
|
+
2. ~ DSV#each: under as_array:, selects by position. A selection by name had raised TypeError.
|
|
9
|
+
3. ~ test/dsv_test.rb: + selections under as_array:, by name, by position, by a repeated name, and from rows already read.
|
|
10
|
+
4. ~ README.md: + as_array:, and a selection under it.
|
|
11
|
+
5. ~ TODO: - 1.
|
|
12
|
+
6. ~ lib/DSV/VERSION.rb: /0.12.11/0.12.12/.
|
|
13
|
+
|
|
5
14
|
0.12.11: the class methods close the files they open, and return an Enumerator without a block.
|
|
6
15
|
|
|
7
16
|
1. ~ DSV.each, .read, .write, .header_row, .first_row, .attributes, .columns: + opened(), so that a path or text given is closed after the call, an early exit included; an IO given is left open. Each had left its file open.
|
data/README.md
CHANGED
|
@@ -40,6 +40,13 @@ DSV.read("1,2,3\n4,5,6\n")
|
|
|
40
40
|
# => [{0 => "1", 1 => "2", 2 => "3"}, {0 => "4", 1 => "5", 2 => "6"}]
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
With `as_array: true` each row is an Array of its values in column order, the form stdlib CSV gives:
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
DSV.read("1,2,3\n4,5,6\n", as_array: true)
|
|
47
|
+
# => [["1", "2", "3"], ["4", "5", "6"]]
|
|
48
|
+
```
|
|
49
|
+
|
|
43
50
|
A String that names an existing file is read as a file; any other String is read as text.
|
|
44
51
|
|
|
45
52
|
### Selecting columns
|
|
@@ -53,6 +60,8 @@ DSV.read('people.csv', 'name', headers: true)
|
|
|
53
60
|
DSV.read('people.csv', headers: true, selected_columns: ['name'])
|
|
54
61
|
```
|
|
55
62
|
|
|
63
|
+
Under `as_array:` the Arrays hold the columns selected, in column order.
|
|
64
|
+
|
|
56
65
|
### Enumerating from the class
|
|
57
66
|
|
|
58
67
|
The Enumerable calls are available on a source directly, each taking the same options:
|
data/TODO
CHANGED
|
@@ -2,44 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
## 0.12.x, fixes
|
|
4
4
|
|
|
5
|
-
1.
|
|
6
|
-
2.
|
|
7
|
-
3.
|
|
8
|
-
4. :
|
|
9
|
-
5.
|
|
10
|
-
6.
|
|
11
|
-
7.
|
|
12
|
-
8. The internals private.
|
|
5
|
+
1. Reading honours quote: given as a String, as writing does; DSV.parse_line honours quote:.
|
|
6
|
+
2. A space as the column separator splits on each space, not as String#split(' ') does.
|
|
7
|
+
3. :double back to 0.12.4's reading, undoing 0.12.5 item 2: a row not starting with a quote split plainly, one starting with a quote split on quote-separator-quote, and one which leaves a lone quote in a field read in full as wholly quoted. The README back to 0.12.3's wording.
|
|
8
|
+
4. :single read, as :double is with a single quote.
|
|
9
|
+
5. filter, a class-level alias of select.
|
|
10
|
+
6. A String under a write mode taken as a path, so that a file not yet there can be written by name.
|
|
11
|
+
7. The internals private.
|
|
13
12
|
|
|
14
13
|
## 0.13.0, modes as declarations
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
8. An unknown quote mode, file mode or option raises ArgumentError, where each is ignored today.
|
|
16
|
+
9. :mixed, the name of the default.
|
|
17
|
+
10. A mode raises on a contradiction which costs nothing to see, every row alike, header included: under :double, a row not starting with a quote, and a bare field in a row read in full. Declaring :mixed reads such a row.
|
|
19
18
|
|
|
20
19
|
## 0.14.0, streaming
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
11. each yields each row as it is read and returns its receiver, so that detect and break stop reading and memory does not grow with the file; rows is no longer filled by each. Chunks come from each_slice. A source read once, start to end, with no rewind, so that a pipe or $stdin can be read: the header from the first row read, and the line of an error found by seeking only where the source can; a rewind left to r+ rewriting and first_row called alone.
|
|
23
22
|
|
|
24
23
|
## 1.0
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
12. A corpus in the tests, a day of NEMWEB's dispatch files trimmed and the RFC 4180 cases, each checked against stdlib CSV's rows.
|
|
26
|
+
13. A benchmark script against stdlib CSV, and the README's speed sentence written from its output.
|
|
27
|
+
14. README: every mode by example, and a table matching each to stdlib CSV's and Python's settings.
|
|
29
28
|
|
|
30
29
|
## 1.x, speed, results unchanged
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
15. A per-row fast path for the default: split, the fields bare or wrapped in two quotes unwrapped, any other row read in full.
|
|
32
|
+
16. as_array: returning the split fields, rather than building a Hash and then an Array from it.
|
|
33
|
+
17. The splitter chosen once, at construction, as row_renderer is for writing.
|
|
34
|
+
18. Two string predicates in place of four regex matches per piece; rows built by zip.to_h; the scanner-based parser, at the tag scanner-parser-20261006, judged against the rest.
|
|
36
35
|
|
|
37
36
|
## 1.x, features
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
19. :rfc_4180, a quote mode reading what RFC 4180 allows as :mixed does and raising on what it forbids.
|
|
39
|
+
20. field_count:, :header or an Integer, off by default: a row of another width raises.
|
|
40
|
+
21. Writing: minimal quoting, a field quoted only where it holds a separator, a quote or a row terminator; a row terminator inside a field kept, quoted, or folded to a space; the encoding declared and a transcode offered with any loss marked.
|
|
41
|
+
22. A line number in each parse error, found only when the error is raised, as UnterminatedQuote finds its, where the source can seek. line_numbers:, off by default, counts lines as it reads instead, for any source a pipe included: the read loop chosen once, at construction, as row_renderer is for writing, so that without it no row pays for the count.
|
|
42
|
+
23. The instance-level header_row renamed headers?, kept as an alias; << to append a row and generate to build a string.
|
|
43
|
+
24. Symbols and Strings interchangeable for column names, in a selection, a columns: list and a row's keys.
|
|
44
|
+
25. The duplicate-header modes as an option: keep all as an Array, the default; index, a, a.1; first; last; error.
|
data/lib/DSV/VERSION.rb
CHANGED
data/lib/dsv.rb
CHANGED
|
@@ -388,6 +388,8 @@ class DSV
|
|
|
388
388
|
end
|
|
389
389
|
|
|
390
390
|
def parse_fields(fields, *selected_columns)
|
|
391
|
+
selected_columns.flatten!
|
|
392
|
+
return fields.values_at(*positions(selected_columns)) if @as_array && !selected_columns.empty?
|
|
391
393
|
parsed_row = {}
|
|
392
394
|
i = -1
|
|
393
395
|
if selected_columns.empty?
|
|
@@ -399,7 +401,6 @@ class DSV
|
|
|
399
401
|
fields.each{|column_value| store_field(parsed_row, attributes[i += 1], column_value)}
|
|
400
402
|
end
|
|
401
403
|
else
|
|
402
|
-
selected_columns.flatten!
|
|
403
404
|
case selected_columns[0]
|
|
404
405
|
when Integer
|
|
405
406
|
fields.each{|column_value| parsed_row[i] = column_value unless !selected_columns.include?(i += 1)}
|
|
@@ -418,6 +419,11 @@ class DSV
|
|
|
418
419
|
end
|
|
419
420
|
end
|
|
420
421
|
|
|
422
|
+
# The positions of the columns selected, in column order, a repeated name giving each of its own.
|
|
423
|
+
def positions(selected_columns)
|
|
424
|
+
selected_columns.flat_map{|column| column.is_a?(::Integer) ? column : Array((columns || {})[column])}.sort
|
|
425
|
+
end
|
|
426
|
+
|
|
421
427
|
# With no columns defined, rows keyed by name supply them, and the header, from the first row's keys; rows keyed by position write positionally and have no header to write.
|
|
422
428
|
def write(*selected_columns)
|
|
423
429
|
prepare_to_rewrite if @mode == 'r+'
|
|
@@ -492,14 +498,16 @@ class DSV
|
|
|
492
498
|
if @rows[0]
|
|
493
499
|
if selected_columns.empty?
|
|
494
500
|
@rows.each{|row| yield row}
|
|
501
|
+
elsif @as_array
|
|
502
|
+
@rows.each{|row| yield row.values_at(*positions(selected_columns))}
|
|
495
503
|
else
|
|
496
504
|
@rows.each do |row|
|
|
497
505
|
yield selected_columns.inject({}){|hash, column_name| hash[column_name] = row[column_name]; hash}
|
|
498
506
|
end
|
|
499
507
|
end
|
|
500
508
|
else
|
|
501
|
-
if selected_columns.empty?
|
|
502
|
-
read_csv.each{|row| yield row}
|
|
509
|
+
if selected_columns.empty? || @as_array
|
|
510
|
+
read_csv(selected_columns).each{|row| yield row}
|
|
503
511
|
else
|
|
504
512
|
read_csv(selected_columns).each do |row|
|
|
505
513
|
yield selected_columns.inject({}){|hash, column_name| hash[column_name] = row[column_name]; hash}
|
data/test/dsv_test.rb
CHANGED
|
@@ -118,6 +118,15 @@ describe DSV do
|
|
|
118
118
|
_(yielded(:each, DATA, 'a', headers: true)).must_equal [{'a' => '1'}, {'a' => '4'}]
|
|
119
119
|
_(yielded(:parse, DATA, 'b', headers: true)).must_equal [{'b' => '2'}, {'b' => '5'}]
|
|
120
120
|
end
|
|
121
|
+
|
|
122
|
+
it "gives only the columns selected under as_array:, in column order" do
|
|
123
|
+
_(DSV.read(DATA, 'a', headers: true, as_array: true)).must_equal [['1'], ['4']]
|
|
124
|
+
_(DSV.read(DATA, ['c', 'a'], headers: true, as_array: true)).must_equal [['1', '3'], ['4', '6']]
|
|
125
|
+
_(DSV.read(DATA, headers: true, as_array: true, selected_columns: ['b'])).must_equal [['2'], ['5']]
|
|
126
|
+
_(DSV.read("1,2,3\n4,5,6\n", 1, as_array: true)).must_equal [['2'], ['5']]
|
|
127
|
+
_(DSV.read("a,a,b\n1,2,3\n", 'a', headers: true, as_array: true)).must_equal [['1', '2']]
|
|
128
|
+
_(yielded(:each, DATA, 'a', headers: true, as_array: true)).must_equal [['1'], ['4']]
|
|
129
|
+
end
|
|
121
130
|
end
|
|
122
131
|
|
|
123
132
|
describe ".parse" do
|
|
@@ -415,6 +424,12 @@ describe DSV do
|
|
|
415
424
|
end
|
|
416
425
|
|
|
417
426
|
describe "#each" do
|
|
427
|
+
it "selects from rows already read under as_array:, in column order" do
|
|
428
|
+
csv = DSV.new(DATA, headers: true, as_array: true)
|
|
429
|
+
csv.read
|
|
430
|
+
_(csv.each(['c', 'a']).to_a).must_equal [['1', '3'], ['4', '6']]
|
|
431
|
+
end
|
|
432
|
+
|
|
418
433
|
it "yields each row, reading the source first if it has not been read" do
|
|
419
434
|
rows = []
|
|
420
435
|
DSV.new(DATA, headers: true).each{|row| rows << row}
|