csv-autoparser 1.0.1 → 1.1.0
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/csv/autoparser.rb +29 -24
- data/lib/csv/autoparser/version.rb +1 -1
- data/test/test_csv/autoparser.rb +33 -3
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 44a33cdb6c52087bcfe3667389cdcccab742a9d5
|
4
|
+
data.tar.gz: 1900f568e8c11343e69d8dc05a7ae8ea8bfe0304
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 095abf30f884f42fd177fbf97b17f9aca67cf56fc629854b2dd2a97571c0e2109ce3c6b2d1c717298686ace768de7bd991579db304ba29830c40cdd6329ecd70
|
7
|
+
data.tar.gz: de518ddbd0e8119ce170fad55ad36194d073c746ac8dcbd68fa9237683c679b05fdf950da8549b815d4c2bc14a8ee1063d4fdfdecae0cb51b0bbeaf5b92da220
|
data/lib/csv/autoparser.rb
CHANGED
@@ -4,6 +4,7 @@ require "csv/autoparser/version"
|
|
4
4
|
class CSV
|
5
5
|
|
6
6
|
class Row
|
7
|
+
attr_reader :line_number
|
7
8
|
alias_method :orig_initialize, :initialize
|
8
9
|
# Defines method style accessors based on header row names.
|
9
10
|
def initialize(*args)
|
@@ -27,17 +28,17 @@ class CSV
|
|
27
28
|
# The rows found before the header row are paired with file and line information. These
|
28
29
|
# objects are available through CSV::AutoParser#pre_header_rows.
|
29
30
|
class PreHeaderRow < Array
|
30
|
-
attr_reader :
|
31
|
+
attr_reader :line_number
|
31
32
|
def self.create original_row, file, line
|
32
33
|
row = PreHeaderRow.new(original_row)
|
33
|
-
row.instance_eval { @
|
34
|
+
row.instance_eval { @line_number = line }
|
34
35
|
return row
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
38
39
|
class HeaderRowNotFound < RuntimeError; end
|
39
40
|
|
40
|
-
attr_reader :pre_header_rows, :header_line_number
|
41
|
+
attr_reader :pre_header_rows, :header_line_number, :file_path
|
41
42
|
|
42
43
|
# +data+ can be path of CSV file in addition to a CSV String or an IO object like CSV.new.
|
43
44
|
# All CSV.new options are supported via +opts+. If an +&is_header+ block is provided, it
|
@@ -48,45 +49,49 @@ class CSV
|
|
48
49
|
@header_line_number = nil
|
49
50
|
@pre_header_rows = []
|
50
51
|
@optional_headers = [opts.delete(:optional_headers)].flatten.compact
|
51
|
-
if data.is_a?(
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
@data_io = if data.is_a?(IO) or data.is_a?(StringIO)
|
53
|
+
data
|
54
|
+
elsif data.is_a?(String)
|
55
|
+
if File.exists?(data)
|
56
|
+
File.open(@file_path = File.expand_path(data), binmode: true)
|
57
|
+
else
|
58
|
+
StringIO.new(data)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
raise ArgumentError, "data must be a path to a CSV file, a CSV formatted String, or an IO object."
|
62
|
+
end
|
55
63
|
if block_given?
|
56
|
-
|
57
|
-
data
|
58
|
-
elsif data.is_a?(String)
|
59
|
-
StringIO.new(data)
|
60
|
-
else
|
61
|
-
raise ArgumentError, "data must be a path to a CSV file, a CSV formatted String, or an IO object."
|
62
|
-
end
|
63
|
-
header_pos = data_io.pos
|
64
|
+
header_pos = @data_io.pos
|
64
65
|
csv_line_number = 0
|
65
|
-
header_finder = CSV.new(data_io, opts.merge(:headers => false)).each do |row|
|
66
|
+
header_finder = CSV.new(@data_io, opts.merge(:headers => false)).each do |row|
|
66
67
|
csv_line_number += 1
|
67
68
|
if is_header.call(csv_line_number, row)
|
68
69
|
@header_line_number = csv_line_number
|
69
70
|
break
|
70
71
|
else
|
71
|
-
@pre_header_rows << CSV::AutoParser::PreHeaderRow.create(row,
|
72
|
+
@pre_header_rows << CSV::AutoParser::PreHeaderRow.create(row, @file_path, csv_line_number)
|
72
73
|
end
|
73
|
-
header_pos = data_io.pos
|
74
|
+
header_pos = @data_io.pos
|
74
75
|
end
|
75
|
-
raise HeaderRowNotFound, "Could not find header row#{
|
76
|
-
data_io.seek header_pos
|
77
|
-
data_io = StringIO.new(data_io.read)
|
78
|
-
super(data_io, opts.merge(:headers => true))
|
76
|
+
raise HeaderRowNotFound, "Could not find header row#{@file_path ? " in #{@file_path}" : "" }." if @header_line_number.nil?
|
77
|
+
@data_io.seek header_pos
|
78
|
+
@data_io = StringIO.new(@data_io.read)
|
79
|
+
super(@data_io, opts.merge(:headers => true))
|
79
80
|
else
|
80
81
|
@header_line_number = 1 if opts[:headers] == :first_row or opts[:headers] == true
|
81
|
-
super(
|
82
|
+
super(@data_io, opts)
|
82
83
|
end
|
83
84
|
end
|
84
85
|
|
85
86
|
alias_method :orig_shift, :shift
|
86
87
|
|
87
|
-
# Overriden to add methods for optional headers which were not present in the CSV.
|
88
|
+
# Overriden to add methods for optional headers which were not present in the CSV. Also,
|
89
|
+
# sets a rows @file_path and @line_number.
|
88
90
|
def shift
|
89
91
|
row = orig_shift
|
92
|
+
if row and row.is_a?(Row) and row.line_number.nil? # sometimes nil. sometimes not a row. sometimes row is repeated.
|
93
|
+
row.instance_variable_set(:@line_number, @data_io.lineno + (@header_line_number || 1) - 1) #if @data_io
|
94
|
+
end
|
90
95
|
[@optional_headers].flatten.compact.each do |h|
|
91
96
|
method_name = self.class.convert_header_to_method_name(h)
|
92
97
|
unless row.respond_to? method_name
|
data/test/test_csv/autoparser.rb
CHANGED
@@ -30,8 +30,25 @@ describe CSV::AutoParser do
|
|
30
30
|
parser.header_line_number.must_equal 3
|
31
31
|
parser.pre_header_rows.first.last.must_equal "years of age"
|
32
32
|
parser.pre_header_rows.last.first.must_equal "bob"
|
33
|
-
|
34
|
-
|
33
|
+
end
|
34
|
+
|
35
|
+
it "it will give file path and line number" do
|
36
|
+
csv_path = fixture_file_path('persons.csv')
|
37
|
+
parser = CSV::AutoParser.new(csv_path) do |line_num, header_row|
|
38
|
+
["name", "Job title"].all? {|cell| header_row.include?(cell) }
|
39
|
+
end
|
40
|
+
line_number = 1
|
41
|
+
parser.file_path.must_equal csv_path
|
42
|
+
parser.pre_header_rows.each do |row|
|
43
|
+
row.line_number.must_equal line_number
|
44
|
+
line_number += 1
|
45
|
+
end
|
46
|
+
table = parser.read
|
47
|
+
line_number = parser.header_line_number + 1
|
48
|
+
table.each do |row|
|
49
|
+
row.line_number.must_equal line_number
|
50
|
+
line_number += 1
|
51
|
+
end
|
35
52
|
end
|
36
53
|
|
37
54
|
it "will raise an exception if it can't find the header row" do
|
@@ -95,7 +112,12 @@ describe CSV::AutoParser do
|
|
95
112
|
end
|
96
113
|
|
97
114
|
it "should work just like CSV.new when not passed a block except that it can now take a file path as data too" do
|
98
|
-
input_objects = [
|
115
|
+
input_objects = [
|
116
|
+
fixture_file_path('persons.csv'),
|
117
|
+
File.open(fixture_file_path('persons.csv')),
|
118
|
+
File.read(fixture_file_path('persons.csv')),
|
119
|
+
StringIO.new(File.read(fixture_file_path('persons.csv')))
|
120
|
+
]
|
99
121
|
input_objects.each do |obj|
|
100
122
|
parser = CSV::AutoParser.new(obj, header_converters: :symbol, headers: :first_row)
|
101
123
|
parser.header_line_number.must_equal 1
|
@@ -105,14 +127,22 @@ describe CSV::AutoParser do
|
|
105
127
|
table.first[:fullname].must_equal "bob"
|
106
128
|
# method names are based off of converted header names!
|
107
129
|
table.first.fullname.must_equal "bob"
|
130
|
+
if obj.is_a?(String) and File.exists?(obj)
|
131
|
+
parser.file_path.must_equal fixture_file_path('persons.csv')
|
132
|
+
else
|
133
|
+
parser.file_path.must_be_nil
|
134
|
+
end
|
135
|
+
table.first.line_number.must_equal 2
|
108
136
|
end
|
109
137
|
parser = CSV::AutoParser.new(fixture_file_path('persons.csv'), header_converters: :symbol, headers: "first_col,second_col,third_col,fourth_col")
|
110
138
|
parser.header_line_number.must_equal nil
|
111
139
|
parser.pre_header_rows.must_be_empty
|
140
|
+
parser.file_path.must_equal fixture_file_path('persons.csv')
|
112
141
|
table = parser.read
|
113
142
|
table.length.must_equal 6
|
114
143
|
table[0].first_col.must_equal "full-name"
|
115
144
|
table[1].first_col.must_equal "bob"
|
145
|
+
table[1].line_number.must_equal 2
|
116
146
|
end
|
117
147
|
|
118
148
|
end
|
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csv-autoparser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Delsol
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: minitest
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
description: ''
|
@@ -44,7 +44,7 @@ executables: []
|
|
44
44
|
extensions: []
|
45
45
|
extra_rdoc_files: []
|
46
46
|
files:
|
47
|
-
-
|
47
|
+
- .gitignore
|
48
48
|
- LICENSE.txt
|
49
49
|
- README.md
|
50
50
|
- Rakefile
|
@@ -66,17 +66,17 @@ require_paths:
|
|
66
66
|
- lib
|
67
67
|
required_ruby_version: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
|
-
- -
|
69
|
+
- - '>='
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: '0'
|
72
72
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- -
|
74
|
+
- - '>='
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: '0'
|
77
77
|
requirements: []
|
78
78
|
rubyforge_project:
|
79
|
-
rubygems_version: 2.
|
79
|
+
rubygems_version: 2.0.3
|
80
80
|
signing_key:
|
81
81
|
specification_version: 4
|
82
82
|
summary: Can parse a CSV file automatically given a user specified header row.
|