csvreader 1.1.4 → 1.1.5
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/lib/csvreader/builder.rb +27 -79
- data/lib/csvreader/converter.rb +2 -1
- data/lib/csvreader/parser_tab.rb +6 -1
- data/lib/csvreader/reader.rb +27 -26
- data/lib/csvreader/reader_hash.rb +20 -26
- data/lib/csvreader/version.rb +1 -1
- data/test/test_parser.rb +1 -1
- data/test/test_parser_directive.rb +1 -1
- data/test/test_parser_meta.rb +1 -1
- data/test/test_parser_tab.rb +7 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a26d07e0e618e2cfb6803c8f059e76cf0541a47
|
4
|
+
data.tar.gz: 71ed3dba6b2d0df06e733832b35a709bd427aabc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10a4ef973d7c573243fd02c224ee16951a7403ad8472ad5a7b0806c252ec718be3ef404c90e3c32ff41dc2388e441e6a3931226330ce870da54dcff979ced024
|
7
|
+
data.tar.gz: '09030d9645657ef71643c1703209806613b29d6da34aa9c01eb88f3c9a7530c6b2b4953931e5f3789d5fc4a3a2daac9e65317544305dee00347f84cd5e41d22d'
|
data/lib/csvreader/builder.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
class CsvReader
|
4
|
-
class Builder
|
4
|
+
class Builder
|
5
5
|
|
6
6
|
|
7
7
|
def initialize( parser )
|
@@ -11,53 +11,35 @@ class Builder ## rename to CsvReaderBuilder - why? why not?
|
|
11
11
|
|
12
12
|
## (auto-)forward to wrapped parser
|
13
13
|
## note/fix: not all parser use/have config e.g. ParserTab, ParserFixed, etc.
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
##
|
17
15
|
## todo/fix:
|
18
16
|
## add parser config (attribute) setter e.g.
|
19
17
|
## - sep=(value)
|
20
18
|
## - comment=(value)
|
21
19
|
## - and so on!!!
|
20
|
+
def config() @parser.config; end
|
21
|
+
|
22
22
|
|
23
|
-
def open( path, mode=nil,
|
24
|
-
sep: nil,
|
25
|
-
converters: nil,
|
26
|
-
width: nil,
|
27
|
-
parser: @parser, &block )
|
28
|
-
CsvReader.open( path, mode,
|
29
|
-
sep: sep, converters: converters, width: width,
|
30
|
-
parser: @parser, &block )
|
31
|
-
end
|
32
23
|
|
33
|
-
def
|
34
|
-
|
35
|
-
width: nil )
|
36
|
-
CsvReader.read( path,
|
37
|
-
sep: sep, converters: converters, width: width,
|
38
|
-
parser: @parser )
|
24
|
+
def open( path, mode=nil, **kwargs, &block )
|
25
|
+
CsvReader.open( path, mode, parser: @parser, **kwargs, &block )
|
39
26
|
end
|
40
27
|
|
41
|
-
def
|
42
|
-
CsvReader.
|
43
|
-
sep: sep, width: width,
|
44
|
-
parser: @parser )
|
28
|
+
def read( path, **kwargs )
|
29
|
+
CsvReader.read( path, parser: @parser, **kwargs )
|
45
30
|
end
|
46
31
|
|
47
|
-
def
|
48
|
-
|
49
|
-
CsvReader.foreach( path,
|
50
|
-
sep: sep, converters: converters, width: width,
|
51
|
-
parser: @parser, &block )
|
32
|
+
def header( path, **kwargs )
|
33
|
+
CsvReader.header( path, parser: @parser, **kwargs )
|
52
34
|
end
|
53
35
|
|
36
|
+
def foreach( path, **kwargs, &block )
|
37
|
+
CsvReader.foreach( path, parser: @parser, **kwargs, &block )
|
38
|
+
end
|
54
39
|
|
55
40
|
|
56
|
-
def parse(
|
57
|
-
|
58
|
-
CsvReader.parse( data,
|
59
|
-
sep: sep, converters: converters, width: width,
|
60
|
-
parser: @parser, &block )
|
41
|
+
def parse( str_or_readable, **kwargs, &block )
|
42
|
+
CsvReader.parse( str_or_readable, parser: @parser, **kwargs, &block )
|
61
43
|
end
|
62
44
|
end # class Builder
|
63
45
|
end # class CsvReader
|
@@ -65,72 +47,38 @@ end # class CsvReader
|
|
65
47
|
|
66
48
|
|
67
49
|
class CsvHashReader
|
68
|
-
class Builder
|
50
|
+
class Builder
|
69
51
|
def initialize( parser )
|
70
52
|
@parser = parser
|
71
53
|
end
|
72
54
|
|
73
55
|
## (auto-)forward to wrapped parser
|
74
56
|
## note/fix: not all parser use/have config e.g. ParserTab, ParserFixed, etc.
|
75
|
-
|
76
|
-
|
57
|
+
##
|
77
58
|
## todo/fix:
|
78
59
|
## add parser config (attribute) setter e.g.
|
79
60
|
## - sep=(value)
|
80
61
|
## - comment=(value)
|
81
62
|
## - and so on!!!
|
63
|
+
def config() @parser.config; end
|
64
|
+
|
82
65
|
|
83
66
|
|
84
|
-
def open( path, mode=nil,
|
85
|
-
|
86
|
-
sep: nil,
|
87
|
-
converters: nil,
|
88
|
-
header_converters: nil,
|
89
|
-
width: nil,
|
90
|
-
parser: @parser, &block )
|
91
|
-
CsvHashReader.open( path, mode,
|
92
|
-
headers: headers, sep: sep, converters: converters,
|
93
|
-
header_converters: header_converters,
|
94
|
-
width: width,
|
95
|
-
parser: @parser, &block )
|
67
|
+
def open( path, mode=nil, **kwargs, &block )
|
68
|
+
CsvHashReader.open( path, mode, parser: @parser, **kwargs, &block )
|
96
69
|
end
|
97
70
|
|
98
|
-
def read( path,
|
99
|
-
|
100
|
-
converters: nil,
|
101
|
-
header_converters: nil,
|
102
|
-
width: nil )
|
103
|
-
CsvHashReader.read( path,
|
104
|
-
headers: headers,
|
105
|
-
sep: sep, converters: converters,
|
106
|
-
header_converters: header_converters,
|
107
|
-
width: width,
|
108
|
-
parser: @parser )
|
71
|
+
def read( path, **kwargs )
|
72
|
+
CsvHashReader.read( path, parser: @parser, **kwargs )
|
109
73
|
end
|
110
74
|
|
111
|
-
def foreach( path,
|
112
|
-
|
113
|
-
converters: nil,
|
114
|
-
header_converters: nil, width: nil, &block )
|
115
|
-
CsvHashReader.foreach( path,
|
116
|
-
headers: headers,
|
117
|
-
sep: sep, converters: converters,
|
118
|
-
header_converters: header_converters,
|
119
|
-
width: width,
|
120
|
-
parser: @parser, &block )
|
75
|
+
def foreach( path, **kwargs, &block )
|
76
|
+
CsvHashReader.foreach( path, parser: @parser, **kwargs, &block )
|
121
77
|
end
|
122
78
|
|
123
79
|
|
124
|
-
def parse(
|
125
|
-
|
126
|
-
converters: nil,
|
127
|
-
header_converters: nil, width: nil, &block )
|
128
|
-
CsvHashReader.parse( data,
|
129
|
-
headers: headers,
|
130
|
-
sep: sep, converters: converters,
|
131
|
-
header_converters: header_converters,
|
132
|
-
width: width,
|
133
|
-
parser: @parser, &block )
|
80
|
+
def parse( str_or_readable, **kwargs, &block )
|
81
|
+
CsvHashReader.parse( str_or_readable, parser: @parser, **kwargs, &block )
|
134
82
|
end
|
135
83
|
end # class Builder
|
136
84
|
end # class CsvHashReader
|
data/lib/csvreader/converter.rb
CHANGED
@@ -110,7 +110,8 @@ def initialize( converters, registry=CONVERTERS )
|
|
110
110
|
add_converter( converter, registry )
|
111
111
|
end
|
112
112
|
end
|
113
|
-
|
113
|
+
end
|
114
|
+
|
114
115
|
|
115
116
|
def to_a() @converters; end ## todo: rename to/use converters attribute name - why? why not?
|
116
117
|
def empty?() @converters.empty?; end
|
data/lib/csvreader/parser_tab.rb
CHANGED
@@ -44,7 +44,12 @@ def parse_lines( input, &block )
|
|
44
44
|
## pp line
|
45
45
|
|
46
46
|
# note: trailing empty fields get (auto-)trimmed by split !!!!!!!
|
47
|
-
|
47
|
+
# Solution!! change split( "\t" ) to split( "\t", -1 )
|
48
|
+
# If the limit parameter is omitted, trailing null fields are suppressed.
|
49
|
+
# If limit is a positive number, at most that number of fields will be returned
|
50
|
+
# (if limit is 1, the entire string is returned as the only entry in an array).
|
51
|
+
# If negative, there is no limit to the number of fields returned, and trailing null fields are not suppressed.
|
52
|
+
values = line.split( "\t", -1 )
|
48
53
|
## pp values
|
49
54
|
|
50
55
|
## note: requires block - enforce? how? why? why not?
|
data/lib/csvreader/reader.rb
CHANGED
@@ -5,15 +5,13 @@ class CsvReader
|
|
5
5
|
def self.open( path, mode=nil,
|
6
6
|
sep: nil,
|
7
7
|
converters: nil,
|
8
|
-
|
9
|
-
parser: nil, &block ) ## rename path to filename or name - why? why not?
|
8
|
+
parser: nil, **kwargs, &block ) ## rename path to filename or name - why? why not?
|
10
9
|
|
11
10
|
## note: default mode (if nil/not passed in) to 'r:bom|utf-8'
|
12
11
|
f = File.open( path, mode ? mode : 'r:bom|utf-8' )
|
13
|
-
csv = new(f, sep:
|
12
|
+
csv = new(f, sep: sep,
|
14
13
|
converters: converters,
|
15
|
-
|
16
|
-
parser: parser )
|
14
|
+
parser: parser, **kwargs )
|
17
15
|
|
18
16
|
# handle blocks like Ruby's open(), not like the (old old) CSV library
|
19
17
|
if block_given?
|
@@ -30,22 +28,21 @@ class CsvReader
|
|
30
28
|
|
31
29
|
def self.read( path, sep: nil,
|
32
30
|
converters: nil,
|
33
|
-
|
34
|
-
|
31
|
+
parser: nil, **kwargs )
|
32
|
+
|
35
33
|
open( path,
|
36
34
|
sep: sep,
|
37
35
|
converters: converters,
|
38
|
-
|
39
|
-
parser: parser ) { |csv| csv.read }
|
36
|
+
parser: parser, **kwargs ) { |csv| csv.read }
|
40
37
|
end
|
41
38
|
|
42
39
|
|
43
|
-
def self.header( path, sep: nil,
|
40
|
+
def self.header( path, sep: nil, parser: nil, **kwargs ) ## use header or headers - or use both (with alias)?
|
44
41
|
# read first lines (only)
|
45
42
|
# and parse with csv to get header from csv library itself
|
46
43
|
|
47
44
|
records = []
|
48
|
-
open( path, sep: sep,
|
45
|
+
open( path, sep: sep, parser: parser, **kwargs ) do |csv|
|
49
46
|
csv.each do |record|
|
50
47
|
records << record
|
51
48
|
break ## only parse/read first record
|
@@ -60,8 +57,8 @@ class CsvReader
|
|
60
57
|
|
61
58
|
|
62
59
|
def self.foreach( path, sep: nil,
|
63
|
-
converters: nil,
|
64
|
-
csv = open( path, sep: sep, converters: converters,
|
60
|
+
converters: nil, parser: nil, **kwargs, &block )
|
61
|
+
csv = open( path, sep: sep, converters: converters, parser: parser, **kwargs )
|
65
62
|
|
66
63
|
if block_given?
|
67
64
|
begin
|
@@ -78,11 +75,10 @@ class CsvReader
|
|
78
75
|
end # method self.foreach
|
79
76
|
|
80
77
|
|
81
|
-
def self.parse(
|
78
|
+
def self.parse( str_or_readable, sep: nil,
|
82
79
|
converters: nil,
|
83
|
-
|
84
|
-
|
85
|
-
csv = new( data, sep: sep, converters: converters, width: width, parser: parser )
|
80
|
+
parser: nil, **kwargs, &block )
|
81
|
+
csv = new( str_or_readable, sep: sep, converters: converters, parser: parser, **kwargs )
|
86
82
|
|
87
83
|
if block_given?
|
88
84
|
csv.each( &block ) ## note: caller (responsible) must close file!!! - add autoclose - why? why not?
|
@@ -93,14 +89,15 @@ class CsvReader
|
|
93
89
|
|
94
90
|
|
95
91
|
|
92
|
+
|
96
93
|
############################
|
97
94
|
## note: only add parse_line convenience helper for default
|
98
95
|
## always use parse (do NOT/NOT/NOT use parse_line) - why? why not?
|
99
96
|
## todo/fix: remove parse_line!!!
|
100
|
-
def self.parse_line(
|
101
|
-
converters: nil,
|
97
|
+
def self.parse_line( str_or_readable, sep: nil,
|
98
|
+
converters: nil, **kwargs )
|
102
99
|
records = []
|
103
|
-
parse(
|
100
|
+
parse( str_or_readable, sep: sep, converters: converters, **kwargs ) do |record|
|
104
101
|
records << record
|
105
102
|
break # only parse first record
|
106
103
|
end
|
@@ -110,15 +107,15 @@ class CsvReader
|
|
110
107
|
|
111
108
|
|
112
109
|
|
113
|
-
def initialize(
|
114
|
-
raise ArgumentError.new( "Cannot parse nil as CSV" ) if
|
110
|
+
def initialize( str_or_readable, sep: nil, converters: nil, parser: nil, **kwargs )
|
111
|
+
raise ArgumentError.new( "Cannot parse nil as CSV" ) if str_or_readable.nil?
|
115
112
|
## todo: use (why? why not) - raise ArgumentError, "Cannot parse nil as CSV" if data.nil?
|
116
113
|
|
117
114
|
# create the IO object we will read from
|
118
|
-
@io =
|
115
|
+
@io = str_or_readable.is_a?(String) ? StringIO.new(str_or_readable) : str_or_readable
|
119
116
|
|
120
|
-
@sep
|
121
|
-
@
|
117
|
+
@sep = sep # (optional) for ParserStd, ParserStrict
|
118
|
+
@kwargs = kwargs # e.g. (optional) :width for ParserFixed
|
122
119
|
|
123
120
|
@converters = Converter.create_converters( converters )
|
124
121
|
|
@@ -150,7 +147,11 @@ class CsvReader
|
|
150
147
|
## todo/fix: change sep keyword to "known" classes!!!!
|
151
148
|
kwargs[:sep] = @sep if @sep && @parser.respond_to?( :'sep=' )
|
152
149
|
|
153
|
-
|
150
|
+
|
151
|
+
kwargs[:width] = @kwargs[:width] if @parser.is_a?( ParserFixed )
|
152
|
+
|
153
|
+
## todo/fix: print warning about unused / unknown kwargs!!!!!
|
154
|
+
|
154
155
|
|
155
156
|
## check array / pipeline of converters is empty (size=0 e.g. is [])
|
156
157
|
if @converters.empty?
|
@@ -15,8 +15,7 @@ def self.open( path, mode=nil,
|
|
15
15
|
sep: nil,
|
16
16
|
converters: nil,
|
17
17
|
header_converters: nil,
|
18
|
-
|
19
|
-
parser: nil, &block ) ## rename path to filename or name - why? why not?
|
18
|
+
parser: nil, **kwargs, &block ) ## rename path to filename or name - why? why not?
|
20
19
|
|
21
20
|
## note: default mode (if nil/not passed in) to 'r:bom|utf-8'
|
22
21
|
f = File.open( path, mode ? mode : 'r:bom|utf-8' )
|
@@ -24,8 +23,7 @@ def self.open( path, mode=nil,
|
|
24
23
|
sep: sep,
|
25
24
|
converters: converters,
|
26
25
|
header_converters: header_converters,
|
27
|
-
|
28
|
-
parser: parser )
|
26
|
+
parser: parser, **kwargs )
|
29
27
|
|
30
28
|
# handle blocks like Ruby's open(), not like the (old old) CSV library
|
31
29
|
if block_given?
|
@@ -44,15 +42,14 @@ def self.read( path, headers: nil,
|
|
44
42
|
sep: nil,
|
45
43
|
converters: nil,
|
46
44
|
header_converters: nil,
|
47
|
-
|
48
|
-
|
45
|
+
parser: nil,
|
46
|
+
**kwargs )
|
49
47
|
open( path,
|
50
48
|
headers: headers,
|
51
49
|
sep: sep,
|
52
50
|
converters: converters,
|
53
51
|
header_converters: header_converters,
|
54
|
-
|
55
|
-
parser: parser ) { |csv| csv.read }
|
52
|
+
parser: parser, **kwargs ) { |csv| csv.read }
|
56
53
|
end
|
57
54
|
|
58
55
|
|
@@ -61,15 +58,14 @@ def self.foreach( path, headers: nil,
|
|
61
58
|
sep: nil,
|
62
59
|
converters: nil,
|
63
60
|
header_converters: nil,
|
64
|
-
|
65
|
-
parser: nil, &block )
|
61
|
+
parser: nil, **kwargs, &block )
|
66
62
|
csv = open( path,
|
67
63
|
headers: headers,
|
68
64
|
sep: sep,
|
69
65
|
converters: converters,
|
70
66
|
header_converters: header_converters,
|
71
|
-
|
72
|
-
|
67
|
+
parser: parser,
|
68
|
+
**kwargs )
|
73
69
|
|
74
70
|
if block_given?
|
75
71
|
begin
|
@@ -86,19 +82,17 @@ def self.foreach( path, headers: nil,
|
|
86
82
|
end # method self.foreach
|
87
83
|
|
88
84
|
|
89
|
-
def self.parse(
|
85
|
+
def self.parse( str_or_readable, headers: nil,
|
90
86
|
sep: nil,
|
91
87
|
converters: nil,
|
92
88
|
header_converters: nil,
|
93
|
-
|
94
|
-
|
95
|
-
csv = new( data,
|
89
|
+
parser: nil, **kwargs, &block )
|
90
|
+
csv = new( str_or_readable,
|
96
91
|
headers: headers,
|
97
92
|
sep: sep,
|
98
93
|
converters: converters,
|
99
94
|
header_converters: header_converters,
|
100
|
-
|
101
|
-
parser: parser )
|
95
|
+
parser: parser, **kwargs )
|
102
96
|
|
103
97
|
if block_given?
|
104
98
|
csv.each( &block ) ## note: caller (responsible) must close file!!! - add autoclose - why? why not?
|
@@ -111,24 +105,24 @@ end # method self.parse
|
|
111
105
|
|
112
106
|
|
113
107
|
|
114
|
-
def initialize(
|
108
|
+
def initialize( str_or_readable, headers: nil, sep: nil,
|
115
109
|
converters: nil,
|
116
110
|
header_converters: nil,
|
117
|
-
|
118
|
-
|
119
|
-
raise ArgumentError.new( "Cannot parse nil as CSV" ) if
|
111
|
+
parser: nil,
|
112
|
+
**kwargs )
|
113
|
+
raise ArgumentError.new( "Cannot parse nil as CSV" ) if str_or_readable.nil?
|
120
114
|
## todo: use (why? why not) - raise ArgumentError, "Cannot parse nil as CSV" if data.nil?
|
121
115
|
|
122
116
|
# create the IO object we will read from
|
123
|
-
@io =
|
117
|
+
@io = str_or_readable.is_a?(String) ? StringIO.new(str_or_readable) : str_or_readable
|
124
118
|
|
125
119
|
## pass in headers as array e.g. ['A', 'B', 'C']
|
126
120
|
## double check: run header_converters on passed in headers?
|
127
121
|
## for now - do NOT auto-convert passed in headers - keep them as-is (1:1)
|
128
122
|
@names = headers ? headers : nil
|
129
123
|
|
130
|
-
@sep
|
131
|
-
@
|
124
|
+
@sep = sep
|
125
|
+
@kwargs = kwargs
|
132
126
|
|
133
127
|
@converters = Converter.create_converters( converters )
|
134
128
|
@header_converters = Converter.create_header_converters( header_converters )
|
@@ -170,7 +164,7 @@ def_delegators :@io,
|
|
170
164
|
## todo/fix: change sep keyword to "known" classes!!!!
|
171
165
|
kwargs[:sep] = @sep if @sep && @parser.respond_to?( :'sep=' )
|
172
166
|
|
173
|
-
kwargs[:width] = @width
|
167
|
+
kwargs[:width] = @kwargs[:width] if @parser.is_a?( ParserFixed )
|
174
168
|
|
175
169
|
|
176
170
|
@parser.parse( @io, kwargs ) do |raw_values| # sep: sep
|
data/lib/csvreader/version.rb
CHANGED
data/test/test_parser.rb
CHANGED
data/test/test_parser_meta.rb
CHANGED
data/test/test_parser_tab.rb
CHANGED
@@ -11,7 +11,7 @@ class TestParserTab < MiniTest::Test
|
|
11
11
|
|
12
12
|
|
13
13
|
def parser
|
14
|
-
|
14
|
+
CsvReader::Parser::TAB
|
15
15
|
end
|
16
16
|
|
17
17
|
|
@@ -33,11 +33,12 @@ def test_parse
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_parse_empties
|
36
|
-
# note: trailing empty fields
|
37
|
-
|
38
|
-
assert_equal [[]],
|
39
|
-
assert_equal [["
|
40
|
-
assert_equal [["1"]],
|
36
|
+
# note: trailing empty fields got (auto-)trimmed !!!!!!!;
|
37
|
+
# add missing -1 limit option :-) now works
|
38
|
+
assert_equal [["","",""]], parser.parse( "\t\t" )
|
39
|
+
assert_equal [["","","","",""]], parser.parse( "\t\t\t\t" )
|
40
|
+
assert_equal [["1","",""]], parser.parse( "1\t\t" )
|
41
|
+
assert_equal [["1","","","",""]], parser.parse( "1\t\t\t\t" )
|
41
42
|
assert_equal [["","","3"]], parser.parse( "\t\t3" )
|
42
43
|
assert_equal [["","","","","5"]], parser.parse( "\t\t\t\t5" )
|
43
44
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csvreader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rdoc
|