rgarner-csv-mapper 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -35,6 +35,22 @@ The following example will import a CSV file to an Array of Struct[http://www.ru
35
35
  results.first.last_name # Doe
36
36
  results.first.age # 27
37
37
 
38
+ ==== Named Columns Example
39
+ Columns which aren't mentioned won't appear in the results.
40
+
41
+ # Don't mention first name
42
+ results = CsvMapper.import('/path/to/file_with_header_row.csv') do
43
+ named_columns
44
+
45
+ surname('last_name')
46
+ age
47
+ end
48
+
49
+ results.first.surname # Doe
50
+ results.first.age # 27
51
+ results.first.first_name # nil
52
+ results.first.last_name # nil
53
+
38
54
  ==== Import to ActiveRecord Example
39
55
  Although CsvMapper has no dependency on ActiveRecord; it's easy to import a CSV file to ActiveRecord models and save them.
40
56
 
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ begin
10
10
  gem.email = "rgarner@zephyros-systems.co.uk"
11
11
  gem.homepage = "http://github.com/rgarner/csv-mapper"
12
12
  gem.authors = ["Luke Pillow", "Russell Garner"]
13
- gem.add_development_dependency "rspec", ">= 1.2.9"
13
+ gem.add_development_dependency "rspec", ">= 2.0.0"
14
14
  gem.add_dependency "fastercsv"
15
15
  gem.extra_rdoc_files << "History.txt"
16
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
@@ -20,13 +20,13 @@ rescue LoadError
20
20
  puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
21
  end
22
22
 
23
- require 'spec/rake/spectask'
24
- Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ require 'rspec/core/rake_task'
24
+ RSpec::Core::RakeTask.new(:spec) do |spec|
25
25
  spec.libs << 'lib' << 'spec'
26
- spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ spec.pattern = 'spec/**/*_spec.rb'
27
27
  end
28
28
 
29
- Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
30
30
  spec.libs << 'lib' << 'spec'
31
31
  spec.pattern = 'spec/**/*_spec.rb'
32
32
  spec.rcov = true
@@ -36,8 +36,8 @@ task :spec => :check_dependencies
36
36
 
37
37
  task :default => :spec
38
38
 
39
- require 'rake/rdoctask'
40
- Rake::RDocTask.new do |rdoc|
39
+ require 'rdoc/task'
40
+ RDoc::Task.new do |rdoc|
41
41
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
42
42
 
43
43
  rdoc.rdoc_dir = 'rdoc'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.0
1
+ 0.8.0
@@ -184,8 +184,14 @@ module CsvMapper
184
184
  end
185
185
 
186
186
  def iterate_headers
187
- attributes = FasterCSV.new(@csv_data, @parser_options).readline
188
187
  @start_at_row = [ @start_at_row, 1 ].max
188
+
189
+ csv = FasterCSV.new(@csv_data, @parser_options)
190
+
191
+ # Header is for now assumed to be one row above data
192
+ (@start_at_row - 1).times { csv.readline } if @start_at_row > 1
193
+
194
+ attributes = csv.readline
189
195
  @csv_data.rewind
190
196
  attributes.each_with_index { |name, index| yield name, index }
191
197
  end
data/lib/csv-mapper.rb CHANGED
@@ -45,7 +45,8 @@ end
45
45
  #
46
46
  # ===== The Basics
47
47
  # * +map_to+ - Override the default Struct target. Accepts a class and an optional hash of default attribute names and values.
48
- # * +start_at_row+ - Specify what row to begin parsing at. Use this to skip headers.
48
+ # * +named_columns+ - Enables named columns mode. Headers are required. See "Named Column Mappings" below.
49
+ # * +start_at_row+ - Specify what row to begin parsing at. Use this to skip headers. When +named_columns+ is used, headers are assumed to be one line above this row.
49
50
  # * +before_row+ - Accepts an Array of method name symbols or lambdas to be invoked before parsing each row.
50
51
  # * +after_row+ - Accepts an Array of method name symbols or lambdas to be invoked after parsing each row.
51
52
  # * +delimited_by+ - Accepts a character to be used to delimit columns. Use this to specify pipe-delimited files.
@@ -70,6 +71,13 @@ end
70
71
  # Attribute mapping declarations and "modifiers" may be chained
71
72
  # foo.at(4).map :some_transform
72
73
  #
74
+ # === Named Columns Mappings
75
+ # When +named_columns+ is called, column names will be read from one row above +start_at_row+. This allows
76
+ # you to map cell properties to named columns in the CSV. For example:
77
+ # surname('Last Name') # Where 'Last Name' is the name of a column in the CSV
78
+ #
79
+ # Columns which go unmentioned will be omitted from the results.
80
+ #
73
81
  # === Create Reusable Mappings
74
82
  # The +import+ method accepts an instance of RowMap as an optional mapping parameter.
75
83
  # The easiest way to create an instance of a RowMap is by using +map_csv+.
@@ -2,47 +2,48 @@ require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
 
3
3
  describe CsvMapper do
4
4
  describe "included" do
5
- before(:each) do
5
+ before(:each) do
6
6
  @mapped_klass = Class.new do
7
- include CsvMapper
8
- def upcase_name(row, index)
9
- row[index].upcase
10
- end
11
- end
7
+ include CsvMapper
8
+
9
+ def upcase_name(row, index)
10
+ row[index].upcase
11
+ end
12
+ end
12
13
  @mapped = @mapped_klass.new
13
14
  end
14
15
 
15
16
  it "should allow the creation of CSV mappings" do
16
17
  mapping = @mapped.map_csv do
17
- start_at_row 2
18
+ start_at_row 2
18
19
  end
19
-
20
+
20
21
  mapping.should be_instance_of(CsvMapper::RowMap)
21
22
  mapping.start_at_row.should == 2
22
23
  end
23
-
24
+
24
25
  it "should import a CSV IO" do
25
26
  io = 'foo,bar,00,01'
26
- results = @mapped.import(io, :type => :io) do
27
+ results = @mapped.import(io, :type => :io) do
27
28
  first
28
29
  second
29
30
  end
30
-
31
+
31
32
  results.should be_kind_of(Enumerable)
32
33
  results.should have(1).things
33
34
  results[0].first.should == 'foo'
34
35
  results[0].second.should == 'bar'
35
36
  end
36
-
37
+
37
38
  it "should import a CSV File IO" do
38
39
  results = @mapped.import(File.dirname(__FILE__) + '/test.csv') do
39
40
  start_at_row 1
40
41
  [first_name, last_name, age]
41
42
  end
42
-
43
+
43
44
  results.size.should == 3
44
- end
45
-
45
+ end
46
+
46
47
  it "should stop importing at a specified row" do
47
48
  results = @mapped.import(File.dirname(__FILE__) + '/test.csv') do
48
49
  start_at_row 1
@@ -65,64 +66,64 @@ describe CsvMapper do
65
66
 
66
67
  it "should import non-comma delimited files" do
67
68
  piped_io = 'foo|bar|00|01'
68
-
69
+
69
70
  results = @mapped.import(piped_io, :type => :io) do
70
71
  delimited_by '|'
71
72
  [first, second]
72
73
  end
73
-
74
+
74
75
  results.should have(1).things
75
76
  results[0].first.should == 'foo'
76
77
  results[0].second.should == 'bar'
77
78
  end
78
-
79
+
79
80
  it "should allow named tranformation mappings" do
80
81
  def upcase_name(row)
81
82
  row[0].upcase
82
83
  end
83
-
84
+
84
85
  results = @mapped.import(File.dirname(__FILE__) + '/test.csv') do
85
86
  start_at_row 1
86
-
87
+
87
88
  first_name.map :upcase_name
88
89
  end
89
-
90
+
90
91
  results[0].first_name.should == 'JOHN'
91
92
  end
92
93
  end
93
-
94
+
94
95
  describe "extended" do
95
96
  it "should allow the creation of CSV mappings" do
96
97
  mapping = CsvMapper.map_csv do
97
- start_at_row 2
98
+ start_at_row 2
98
99
  end
99
-
100
+
100
101
  mapping.should be_instance_of(CsvMapper::RowMap)
101
102
  mapping.start_at_row.should == 2
102
103
  end
103
-
104
+
104
105
  it "should import a CSV IO" do
105
106
  io = 'foo,bar,00,01'
106
- results = CsvMapper.import(io, :type => :io) do
107
+ results = CsvMapper.import(io, :type => :io) do
107
108
  first
108
109
  second
109
110
  end
110
-
111
+
111
112
  results.should be_kind_of(Enumerable)
112
113
  results.should have(1).things
113
114
  results[0].first.should == 'foo'
114
115
  results[0].second.should == 'bar'
115
116
  end
116
-
117
+
117
118
  it "should import a CSV File IO" do
118
119
  results = CsvMapper.import(File.dirname(__FILE__) + '/test.csv') do
119
120
  start_at_row 1
120
121
  [first_name, last_name, age]
121
122
  end
122
-
123
+
123
124
  results.size.should == 3
124
- end
125
-
125
+ end
126
+
126
127
  it "should stop importing at a specified row" do
127
128
  results = CsvMapper.import(File.dirname(__FILE__) + '/test.csv') do
128
129
  start_at_row 1
@@ -144,40 +145,58 @@ describe CsvMapper do
144
145
  end
145
146
 
146
147
  describe "Adding only certain attributes by name or alias" do
147
- before :all do
148
- @results = CsvMapper.import(File.dirname(__FILE__) + '/test_with_empty_column_names.csv') do
149
- named_columns
150
- surname('Last Name')
151
- age.map { |row, index| row[index].to_i }
148
+ context "A file with headers and empty column names" do
149
+ before :all do
150
+ @results = CsvMapper.import(File.dirname(__FILE__) + '/test_with_empty_column_names.csv') do
151
+ named_columns
152
+ surname('Last Name')
153
+ age.map { |row, index| row[index].to_i }
154
+ end
152
155
  end
153
- end
154
156
 
155
- it "should have Last name aliased as surname" do
156
- @results[1].surname.should == 'Doe'
157
- end
157
+ it "should have Last name aliased as surname" do
158
+ @results[1].surname.should == 'Doe'
159
+ end
158
160
 
159
- it "should transform age to 26 (a Fixnum)" do
160
- @results[1].age.should == 26
161
- end
161
+ it "should transform age to 26 (a Fixnum)" do
162
+ @results[1].age.should == 26
163
+ end
162
164
 
163
- it "should not have First Name at all" do
164
- lambda { @results[1].first_name }.should raise_error(NoMethodError)
165
- end
165
+ it "should not have First Name at all" do
166
+ lambda { @results[1].first_name }.should raise_error(NoMethodError)
167
+ end
166
168
 
167
- it "should raise IndexError when adding non-existent fields" do
168
- lambda {
169
- @results = CsvMapper.import(File.dirname(__FILE__) + '/test_with_empty_column_names.csv') do
170
- add_attributes_by_name('doesnt_exist')
171
- end
172
- }.should raise_error(IndexError)
169
+ it "should raise IndexError when adding non-existent fields" do
170
+ lambda {
171
+ @results = CsvMapper.import(File.dirname(__FILE__) + '/test_with_empty_column_names.csv') do
172
+ add_attributes_by_name('doesnt_exist')
173
+ end
174
+ }.should raise_error(IndexError)
175
+ end
176
+
177
+ it "should raise IndexError when adding non-existent aliases" do
178
+ lambda {
179
+ @results = CsvMapper.import(File.dirname(__FILE__) + '/test_with_empty_column_names.csv') do
180
+ my_new_field('doesnt_exist')
181
+ end
182
+ }.should raise_error(IndexError)
183
+ end
173
184
  end
174
185
 
175
- it "should raise IndexError when adding non-existent aliases" do
176
- lambda {
177
- @results = CsvMapper.import(File.dirname(__FILE__) + '/test_with_empty_column_names.csv') do
178
- my_new_field('doesnt_exist')
186
+ context "A crazy not-really CSV file with some lines to ignore at the top" do
187
+ before :all do
188
+ @results = CsvMapper.import(File.dirname(__FILE__) + '/test_with_pushed_down_header.csv') do
189
+ start_at_row 5
190
+ named_columns
191
+ surname('Last Name')
192
+ age.map { |row, index| row[index].to_i }
179
193
  end
180
- }.should raise_error(IndexError)
194
+ end
195
+
196
+ it "should transform age to 26" do
197
+ @results[1].age.should == 26
198
+ end
199
+
181
200
  end
182
201
  end
183
202
 
@@ -191,26 +210,26 @@ describe CsvMapper do
191
210
 
192
211
  it "should import non-comma delimited files" do
193
212
  piped_io = 'foo|bar|00|01'
194
-
213
+
195
214
  results = CsvMapper.import(piped_io, :type => :io) do
196
215
  delimited_by '|'
197
216
  [first, second]
198
217
  end
199
-
218
+
200
219
  results.should have(1).things
201
220
  results[0].first.should == 'foo'
202
221
  results[0].second.should == 'bar'
203
222
  end
204
-
223
+
205
224
  it "should not allow transformation mappings" do
206
225
  def upcase_name(row)
207
226
  row[0].upcase
208
227
  end
209
-
210
- (lambda do
228
+
229
+ (lambda do
211
230
  results = CsvMapper.import(File.dirname(__FILE__) + '/test.csv') do
212
231
  start_at_row 1
213
-
232
+
214
233
  first_name.map :upcase_name
215
234
  end
216
235
  end).should raise_error(Exception)
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,3 @@
1
1
  $LOAD_PATH.unshift(File.dirname(__FILE__))
2
2
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
3
  require 'csv-mapper'
4
- require 'spec'
5
- require 'spec/autorun'
6
-
7
- Spec::Runner.configure do |config|
8
-
9
- end
@@ -0,0 +1,8 @@
1
+ "Some data"
2
+
3
+ This is a test file whose header line starts at the 0-indexed 4th row and the data starts at the 5th. I know. It's not a CSV as such, but they exist...
4
+
5
+ First Name, Last Name, Age,,,
6
+ John,Doe,27,,,
7
+ Jane,Doe,26,unnamed_value,,
8
+ Bat,Man,52,,,
metadata CHANGED
@@ -1,66 +1,50 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: rgarner-csv-mapper
3
- version: !ruby/object:Gem::Version
4
- hash: 3
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 7
9
- - 0
10
- version: 0.7.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Luke Pillow
14
9
  - Russell Garner
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2010-08-27 00:00:00 +01:00
20
- default_executable:
21
- dependencies:
22
- - !ruby/object:Gem::Dependency
13
+ date: 2012-11-21 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
23
16
  name: rspec
24
- prerelease: false
25
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: &2155992480 !ruby/object:Gem::Requirement
26
18
  none: false
27
- requirements:
28
- - - ">="
29
- - !ruby/object:Gem::Version
30
- hash: 13
31
- segments:
32
- - 1
33
- - 2
34
- - 9
35
- version: 1.2.9
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
36
23
  type: :development
37
- version_requirements: *id001
38
- - !ruby/object:Gem::Dependency
39
- name: fastercsv
40
24
  prerelease: false
41
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: *2155992480
26
+ - !ruby/object:Gem::Dependency
27
+ name: fastercsv
28
+ requirement: &2156007300 !ruby/object:Gem::Requirement
42
29
  none: false
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- hash: 3
47
- segments:
48
- - 0
49
- version: "0"
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
50
34
  type: :runtime
51
- version_requirements: *id002
52
- description: CSV Mapper makes it easy to import data from CSV files directly to a collection of any type of Ruby object. The simplest way to create mappings is declare the names of the attributes in the order corresponding to the CSV file column order.
35
+ prerelease: false
36
+ version_requirements: *2156007300
37
+ description: CSV Mapper makes it easy to import data from CSV files directly to a
38
+ collection of any type of Ruby object. The simplest way to create mappings is declare
39
+ the names of the attributes in the order corresponding to the CSV file column order.
53
40
  email: rgarner@zephyros-systems.co.uk
54
41
  executables: []
55
-
56
42
  extensions: []
57
-
58
- extra_rdoc_files:
43
+ extra_rdoc_files:
59
44
  - History.txt
60
45
  - LICENSE
61
46
  - README.rdoc
62
- files:
63
- - .gitignore
47
+ files:
64
48
  - History.txt
65
49
  - LICENSE
66
50
  - README.rdoc
@@ -76,42 +60,31 @@ files:
76
60
  - spec/spec_helper.rb
77
61
  - spec/test.csv
78
62
  - spec/test_with_empty_column_names.csv
79
- has_rdoc: true
63
+ - spec/test_with_pushed_down_header.csv
80
64
  homepage: http://github.com/rgarner/csv-mapper
81
65
  licenses: []
82
-
83
66
  post_install_message:
84
- rdoc_options:
85
- - --charset=UTF-8
86
- require_paths:
67
+ rdoc_options: []
68
+ require_paths:
87
69
  - lib
88
- required_ruby_version: !ruby/object:Gem::Requirement
70
+ required_ruby_version: !ruby/object:Gem::Requirement
89
71
  none: false
90
- requirements:
91
- - - ">="
92
- - !ruby/object:Gem::Version
93
- hash: 3
94
- segments:
95
- - 0
96
- version: "0"
97
- required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
77
  none: false
99
- requirements:
100
- - - ">="
101
- - !ruby/object:Gem::Version
102
- hash: 3
103
- segments:
104
- - 0
105
- version: "0"
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
106
82
  requirements: []
107
-
108
83
  rubyforge_project:
109
- rubygems_version: 1.3.7
84
+ rubygems_version: 1.8.16
110
85
  signing_key:
111
86
  specification_version: 3
112
- summary: rgarner-CsvMapper is a fork of a small library intended to simplify the common steps involved with importing CSV files to a usable form in Ruby. It has support for null column names. When this is merged, this gem will be removed.
113
- test_files:
114
- - spec/csv-mapper/attribute_map_spec.rb
115
- - spec/csv-mapper/row_map_spec.rb
116
- - spec/csv-mapper_spec.rb
117
- - spec/spec_helper.rb
87
+ summary: rgarner-CsvMapper is a fork of a small library intended to simplify the common
88
+ steps involved with importing CSV files to a usable form in Ruby. It has support
89
+ for null column names. When this is merged, this gem will be removed.
90
+ test_files: []
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- pkg/*
2
- doc/*
3
- .idea/*
4
- *.gemspec