csv-autoparser 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 53747202951399caaf327f39b27c05bea53adb65
4
- data.tar.gz: 393d57c30af9348ef1f2e20d9b31e2dd9447b297
3
+ metadata.gz: 44a33cdb6c52087bcfe3667389cdcccab742a9d5
4
+ data.tar.gz: 1900f568e8c11343e69d8dc05a7ae8ea8bfe0304
5
5
  SHA512:
6
- metadata.gz: 694f349ba315f419dfd12d0e95a8c4bcc817fdf14d84bfe0b2c5732ef75008d59e1d7766edd8b6d5c4d8ec76fb6323ad53642a157fbf6a8431bc9e1e0aeb2cdf
7
- data.tar.gz: 7ef182a5fdef94fef12741d77279a158c43b989c3e0c3752a65545e0b5ff802f2d359a2e8f343449c4863bc135ade02058d77dec6266d3da58a375031ceb2462
6
+ metadata.gz: 095abf30f884f42fd177fbf97b17f9aca67cf56fc629854b2dd2a97571c0e2109ce3c6b2d1c717298686ace768de7bd991579db304ba29830c40cdd6329ecd70
7
+ data.tar.gz: de518ddbd0e8119ce170fad55ad36194d073c746ac8dcbd68fa9237683c679b05fdf950da8549b815d4c2bc14a8ee1063d4fdfdecae0cb51b0bbeaf5b92da220
@@ -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 :file, :line
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 { @file = file; @line = line }
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?(String) and File.exists?(data)
52
- file = data
53
- data = File.open(data)
54
- end
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
- data_io = if data.is_a?(IO)
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, file, csv_line_number)
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#{file ? " in #{file}" : "" }." if @header_line_number.nil?
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(data, opts)
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
@@ -1,5 +1,5 @@
1
1
  class CSV
2
2
  class AutoParser < CSV
3
- VERSION = "1.0.1"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -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
- File.basename(parser.pre_header_rows.last.file).must_equal "persons.csv"
34
- parser.pre_header_rows.last.line.must_equal 2
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 = [fixture_file_path('persons.csv'), File.open(fixture_file_path('persons.csv')), File.open(fixture_file_path('persons.csv'))]
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.1
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-04-21 00:00:00.000000000 Z
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
- - ".gitignore"
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.2.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.