smarter_csv 1.0.16 → 1.0.17

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -135,6 +135,7 @@ The options and the block are optional.
135
135
  ---------------------------------------------------------------------------------------------------------------------------------
136
136
  | :col_sep | ',' | column separator |
137
137
  | :row_sep | $/ ,"\n" | row separator or record separator , defaults to system's $/ , which defaults to "\n" |
138
+ | | | this can also be set to :auto , but will process the whole cvs file first |
138
139
  | :quote_char | '"' | quotation character |
139
140
  | :comment_regexp | /^#/ | regular expression which matches comment lines (see NOTE about the CSV header) |
140
141
  | :chunk_size | nil | if set, determines the desired chunk-size (defaults to nil, no chunk processing) |
@@ -228,6 +229,9 @@ Or install it yourself as:
228
229
 
229
230
  ## Changes
230
231
 
232
+ #### 1.0.17 (2014-01-13)
233
+ * added option to set :row_sep to :auto , for automatic detection of the row-separator (issue #22)
234
+
231
235
  #### 1.0.16 (2014-01-13)
232
236
  * :convert_values_to_numeric option can now be qualified with :except or :only (thanks to Hugo Lepetit)
233
237
  * removed deprecated `process_csv` method
@@ -18,9 +18,14 @@ module SmarterCSV
18
18
  old_row_sep = $/
19
19
  line_count = 0
20
20
  begin
21
- $/ = options[:row_sep]
22
21
  f = input.respond_to?(:readline) ? input : File.open(input, "r:#{options[:file_encoding]}")
23
22
 
23
+ if options[:row_sep] == :auto
24
+ options[:row_sep] = SmarterCSV.guess_line_ending( f )
25
+ f.rewind
26
+ end
27
+ $/ = options[:row_sep]
28
+
24
29
  if options[:headers_in_file] # extract the header line
25
30
  # process the header line in the CSV file..
26
31
  # the first line of a CSV file contains the header .. it might be commented out, so we need to read it anyhow
@@ -185,5 +190,18 @@ module SmarterCSV
185
190
  end
186
191
  return false
187
192
  end
193
+
194
+ # limitation: this currently reads the whole file in before making a decision
195
+ def self.guess_line_ending( filehandle )
196
+ counts = {"\n" => 0 , "\r" => 0, "\r\n" => 0}
197
+
198
+ filehandle.each_char do |c|
199
+ next if c !~ /\r|\n|\r\n/
200
+ counts[c] += 1 # count how many of the pre-defined line-endings we find
201
+ end
202
+ # find the key/value pair with the largest counter:
203
+ k,v = counts.max_by{|k,v| v}
204
+ return k # the most frequent one is it
205
+ end
188
206
  end
189
207
 
@@ -1,3 +1,3 @@
1
1
  module SmarterCSV
2
- VERSION = "1.0.16"
2
+ VERSION = "1.0.17"
3
3
  end
@@ -0,0 +1,4 @@
1
+ name,count,price
2
+ hammer,4,12.50
3
+ axe,2,7.30
4
+ crowbar,3,17.50
@@ -0,0 +1 @@
1
+ name,count,price
@@ -0,0 +1,4 @@
1
+ name,count,price
2
+ hammer,4,12.50
3
+ axe,2,7.30
4
+ crowbar,3,17.50
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ fixture_path = 'spec/fixtures'
4
+
5
+ describe 'process files with line endings explicitly pre-specified' do
6
+ it 'reads file with \n line endings' do
7
+ options = {:row_sep => "\n"}
8
+ data = SmarterCSV.process("#{fixture_path}/line_endings_n.csv", options)
9
+ data.size.should == 3
10
+ end
11
+
12
+ it 'reads file with \r line endings' do
13
+ options = {:row_sep => "\r"}
14
+ data = SmarterCSV.process("#{fixture_path}/line_endings_r.csv", options)
15
+ data.size.should == 3
16
+ end
17
+
18
+ it 'reads file with \r\n line endings' do
19
+ options = {:row_sep => "\r\n"}
20
+ data = SmarterCSV.process("#{fixture_path}/line_endings_rn.csv", options)
21
+ data.size.should == 3
22
+ end
23
+ end
24
+
25
+ describe 'process files with line endings in automatic mode' do
26
+ it 'reads file with \n line endings' do
27
+ options = {:row_sep => :auto}
28
+ data = SmarterCSV.process("#{fixture_path}/line_endings_n.csv", options)
29
+ data.size.should == 3
30
+ end
31
+
32
+ it 'reads file with \r line endings' do
33
+ options = {:row_sep => :auto}
34
+ data = SmarterCSV.process("#{fixture_path}/line_endings_r.csv", options)
35
+ data.size.should == 3
36
+ end
37
+
38
+ it 'reads file with \r\n line endings' do
39
+ options = {:row_sep => :auto}
40
+ data = SmarterCSV.process("#{fixture_path}/line_endings_rn.csv", options)
41
+ data.size.should == 3
42
+ end
43
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smarter_csv
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.16
4
+ version: 1.0.17
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -55,6 +55,9 @@ files:
55
55
  - spec/fixtures/basic.csv
56
56
  - spec/fixtures/binary.csv
57
57
  - spec/fixtures/chunk_cornercase.csv
58
+ - spec/fixtures/line_endings_n.csv
59
+ - spec/fixtures/line_endings_r.csv
60
+ - spec/fixtures/line_endings_rn.csv
58
61
  - spec/fixtures/lots_of_columns.csv
59
62
  - spec/fixtures/no_header.csv
60
63
  - spec/fixtures/numeric.csv
@@ -67,6 +70,7 @@ files:
67
70
  - spec/smarter_csv/column_separator_spec.rb
68
71
  - spec/smarter_csv/convert_values_to_numeric_spec.rb
69
72
  - spec/smarter_csv/key_mapping_spec.rb
73
+ - spec/smarter_csv/line_ending_spec.rb
70
74
  - spec/smarter_csv/load_basic_spec.rb
71
75
  - spec/smarter_csv/no_header_spec.rb
72
76
  - spec/smarter_csv/not_downcase_header_spec.rb
@@ -112,6 +116,9 @@ test_files:
112
116
  - spec/fixtures/basic.csv
113
117
  - spec/fixtures/binary.csv
114
118
  - spec/fixtures/chunk_cornercase.csv
119
+ - spec/fixtures/line_endings_n.csv
120
+ - spec/fixtures/line_endings_r.csv
121
+ - spec/fixtures/line_endings_rn.csv
115
122
  - spec/fixtures/lots_of_columns.csv
116
123
  - spec/fixtures/no_header.csv
117
124
  - spec/fixtures/numeric.csv
@@ -124,6 +131,7 @@ test_files:
124
131
  - spec/smarter_csv/column_separator_spec.rb
125
132
  - spec/smarter_csv/convert_values_to_numeric_spec.rb
126
133
  - spec/smarter_csv/key_mapping_spec.rb
134
+ - spec/smarter_csv/line_ending_spec.rb
127
135
  - spec/smarter_csv/load_basic_spec.rb
128
136
  - spec/smarter_csv/no_header_spec.rb
129
137
  - spec/smarter_csv/not_downcase_header_spec.rb