rgarner-csv-mapper 0.5.1 → 0.7.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.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/csv-mapper/attribute_map.rb +5 -1
- data/lib/csv-mapper/row_map.rb +39 -6
- data/spec/csv-mapper_spec.rb +38 -0
- metadata +5 -5
data/Rakefile
CHANGED
@@ -41,7 +41,7 @@ Rake::RDocTask.new do |rdoc|
|
|
41
41
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
42
42
|
|
43
43
|
rdoc.rdoc_dir = 'rdoc'
|
44
|
-
rdoc.title = "csv-mapper #{version}"
|
44
|
+
rdoc.title = "rgarner-csv-mapper #{version}"
|
45
45
|
rdoc.rdoc_files.include('README*')
|
46
46
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
47
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.7.0
|
@@ -8,6 +8,10 @@ module CsvMapper
|
|
8
8
|
def initialize(name, index, map_context)
|
9
9
|
@name, @index, @map_context = name, index, map_context
|
10
10
|
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"#{@index}: #{@name}"
|
14
|
+
end
|
11
15
|
|
12
16
|
# Set the index that this map is targeting.
|
13
17
|
#
|
@@ -51,5 +55,5 @@ module CsvMapper
|
|
51
55
|
@transformer.call(csv_row, @index)
|
52
56
|
end
|
53
57
|
end
|
54
|
-
end
|
58
|
+
end
|
55
59
|
end
|
data/lib/csv-mapper/row_map.rb
CHANGED
@@ -17,6 +17,7 @@ module CsvMapper
|
|
17
17
|
@csv_data = csv_data
|
18
18
|
@before_filters = []
|
19
19
|
@after_filters = []
|
20
|
+
@named_columns = false
|
20
21
|
@parser_options = {}
|
21
22
|
@start_at_row = 0
|
22
23
|
@stop_at_row = Infinity
|
@@ -49,17 +50,14 @@ module CsvMapper
|
|
49
50
|
#
|
50
51
|
# i.e. read_attributes_from_file('files+' => 'files_plus', 'files-' => 'files_minus)
|
51
52
|
def read_attributes_from_file aliases = {}
|
52
|
-
attributes = FasterCSV.new(@csv_data, @parser_options).readline
|
53
|
-
@start_at_row = [ @start_at_row, 1 ].max
|
54
|
-
@csv_data.rewind
|
55
53
|
unnamed_number = 1
|
56
|
-
|
54
|
+
iterate_headers do |name, index|
|
57
55
|
if name.nil?
|
58
56
|
name = "_field_#{unnamed_number}"
|
59
|
-
unnamed_number += 1
|
57
|
+
unnamed_number += 1
|
60
58
|
end
|
61
59
|
name.strip!
|
62
|
-
use_name = aliases[name] || name
|
60
|
+
use_name = aliases[name] || attributize_field_name(name)
|
63
61
|
add_attribute use_name, index
|
64
62
|
end
|
65
63
|
end
|
@@ -72,6 +70,12 @@ module CsvMapper
|
|
72
70
|
@parser_options.merge :col_sep => @delimited_by
|
73
71
|
end
|
74
72
|
|
73
|
+
# Default csv_mapper behaviour is to use the ordinal position of a mapped attribute.
|
74
|
+
# If you prefer to look for a column with the name of the attribute, use this method.
|
75
|
+
def named_columns
|
76
|
+
@named_columns = true
|
77
|
+
end
|
78
|
+
|
75
79
|
# Convenience method to 'move' the cursor skipping the current index.
|
76
80
|
def _SKIP_
|
77
81
|
self.move_cursor
|
@@ -151,6 +155,17 @@ module CsvMapper
|
|
151
155
|
# An optional first argument is used to move this maps cursor position and as the index of the
|
152
156
|
# new AttributeMap
|
153
157
|
def method_missing(name, *args) # :nodoc:
|
158
|
+
existing_map = self.mapped_attributes.find {|attr| attr.name == name}
|
159
|
+
return existing_map if existing_map
|
160
|
+
|
161
|
+
# Effectively add an alias when we see new_field('With/Aliased/Name')
|
162
|
+
if args[0].is_a? String
|
163
|
+
return add_attribute(name, headers_to_indices.fetch(args[0].downcase))
|
164
|
+
end
|
165
|
+
|
166
|
+
if @named_columns
|
167
|
+
return add_attribute(name, headers_to_indices.fetch(name.to_s))
|
168
|
+
end
|
154
169
|
|
155
170
|
if index = args[0]
|
156
171
|
self.move_cursor(index - self.cursor)
|
@@ -168,6 +183,20 @@ module CsvMapper
|
|
168
183
|
end).flatten!
|
169
184
|
end
|
170
185
|
|
186
|
+
def iterate_headers
|
187
|
+
attributes = FasterCSV.new(@csv_data, @parser_options).readline
|
188
|
+
@start_at_row = [ @start_at_row, 1 ].max
|
189
|
+
@csv_data.rewind
|
190
|
+
attributes.each_with_index { |name, index| yield name, index }
|
191
|
+
end
|
192
|
+
|
193
|
+
def headers_to_indices
|
194
|
+
return @h_to_i if @h_to_i
|
195
|
+
@h_to_i = {}
|
196
|
+
iterate_headers { |name, index| @h_to_i[name.strip.downcase] = index if name }
|
197
|
+
@h_to_i
|
198
|
+
end
|
199
|
+
|
171
200
|
def map_to_class # :nodoc:
|
172
201
|
unless @map_to_klass
|
173
202
|
attrs = mapped_attributes.collect {|attr_map| attr_map.name}
|
@@ -180,5 +209,9 @@ module CsvMapper
|
|
180
209
|
def cursor=(value) # :nodoc:
|
181
210
|
@cursor=value
|
182
211
|
end
|
212
|
+
|
213
|
+
def attributize_field_name(name)
|
214
|
+
name.gsub(/\s+/, '_').gsub(/[\W]+/, '').downcase
|
215
|
+
end
|
183
216
|
end
|
184
217
|
end
|
data/spec/csv-mapper_spec.rb
CHANGED
@@ -143,6 +143,44 @@ describe CsvMapper do
|
|
143
143
|
results[1].number_of_years_old.should == '26'
|
144
144
|
end
|
145
145
|
|
146
|
+
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 }
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should have Last name aliased as surname" do
|
156
|
+
@results[1].surname.should == 'Doe'
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should transform age to 26 (a Fixnum)" do
|
160
|
+
@results[1].age.should == 26
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should not have First Name at all" do
|
164
|
+
lambda { @results[1].first_name }.should raise_error(NoMethodError)
|
165
|
+
end
|
166
|
+
|
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)
|
173
|
+
end
|
174
|
+
|
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')
|
179
|
+
end
|
180
|
+
}.should raise_error(IndexError)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
146
184
|
it "should be able to assign default column names when column names are null" do
|
147
185
|
results = CsvMapper.import(File.dirname(__FILE__) + '/test_with_empty_column_names.csv') do
|
148
186
|
read_attributes_from_file
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgarner-csv-mapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 7
|
9
|
+
- 0
|
10
|
+
version: 0.7.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Luke Pillow
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-08-
|
19
|
+
date: 2010-08-27 00:00:00 +01:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|