map_fields 1.0.4 → 2.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -4,48 +4,48 @@
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- A Rails plugin which provides a hook to preview and map the fields of an uploaded CSV file to a pre-defined schema
7
+ A Rails gem which provides a hook to preview and map the fields of an uploaded CSV file to a pre-defined schema
8
8
 
9
9
  == FEATURES/PROBLEMS:
10
10
 
11
11
  * Captures the post and provides an intermediate view where a user can map their data to the expected schema
12
12
  * Provides a default mapping view that can be customised
13
13
  * Allows the import to be part of a larger form (The form fields are remembered through the mapping)
14
+ * Can only handle a single uploaded file at a time
14
15
 
15
- == SYNOPSIS:
16
+ == INSTALLATION:
16
17
 
17
- ===Lists controller
18
- class ListsController < AppliactionController
19
- map_fields :create, ['Title', 'First name', 'Last name'], :file_field => :file, :params => [:list]
18
+ gem install map_fields
20
19
 
21
- def index
22
- @lists = List.find(:all)
23
- end
20
+ == EXAMPLE:
21
+
22
+ ===TestController
23
+ class TestController < AppliactionController
24
24
 
25
25
  def new
26
26
  @list = List.new
27
27
  end
28
28
 
29
29
  def create
30
- @list = List.new(params[:list])
31
- if fields_mapped?
32
- mapped_fields.each do |row|
33
- @list.contact.create(:title => row[0],
34
- :first_name => row[1],
35
- :last_name => row[2])
30
+ map_fields :get_fields, params[:file] do
31
+ @list = List.create(params[:list])
32
+ @mapping.rows.each do |row|
33
+ @list.contact.create(:title => row[:title],
34
+ :first_name => row[:first_name],
35
+ :last_name => row[:last_name])
36
36
  end
37
37
  flash[:notice] = 'Contact list created'
38
38
  redirect_to :action => :index
39
- else
40
- render
41
39
  end
42
- rescue MapFields::InconsistentStateError
43
- flash[:error] = 'Please try again'
44
- redirect_to :action => :new
45
- rescue MapFields::MissingFileContentsError
40
+ rescue MapFields::MissingFileError
46
41
  flash[:error] = 'Please upload a file'
47
42
  redirect_to :action => :new
48
43
  end
44
+
45
+ private
46
+ def get_fields
47
+ ['Title', 'First name', 'Last name']
48
+ end
49
49
  end
50
50
 
51
51
  ===New view (new.html.erb)
@@ -67,19 +67,12 @@ A Rails plugin which provides a hook to preview and map the fields of an uploade
67
67
  ===Create view (create.html.erb)
68
68
  <h1>Import a new List</h1>
69
69
  <p>Please map the details you're importing</p>
70
- =render :partial => 'map_fields/map_fields'
70
+ =render :partial => 'map_fields/mapping'
71
71
 
72
72
  == REQUIREMENTS:
73
73
 
74
- * FasterCSV
75
-
76
- == INSTALL:
77
-
78
- sudo gem install map-fields
79
-
80
- or
81
-
82
- ./script/plugin install git://github.com/internuity/map-fields.git
74
+ * Rails 3.1
75
+ * Ruby 1.9.3 (Not tested on 1.9.1 or 1.9.2
83
76
 
84
77
  == LICENSE:
85
78
 
@@ -0,0 +1,15 @@
1
+ require 'map_fields/mapper'
2
+
3
+ module MapFields
4
+ module Controller
5
+ def map_fields(fields, file, &block)
6
+ @mapper = Mapper.new(self, fields, file)
7
+ if @mapper.mapped?
8
+ block.call
9
+ else
10
+ append_view_path File.expand_path('../../../views/', __FILE__)
11
+ render
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,108 @@
1
+ require 'csv'
2
+ require 'tempfile'
3
+ require 'map_fields/mapping'
4
+ require 'map_fields/params_parser'
5
+
6
+ module MapFields
7
+ class MissingFileError < StandardError; end
8
+
9
+ class Mapper
10
+ def initialize(controller, fields, file)
11
+ params = controller.params
12
+ @fields = get_fields(controller, fields)
13
+ @params = ParamsParser.parse(params)
14
+
15
+ if file
16
+ file = save_file controller, file
17
+ @rows = parse_first_few_lines file
18
+ else
19
+ raise MissingFileError unless controller.session[:map_fields_file] && File.exist?(controller.session[:map_fields_file])
20
+ @mapped = true
21
+ @rows = map_fields(controller, params.delete(:mapped_fields), fields)
22
+ end
23
+ end
24
+ attr_reader :rows, :fields, :params
25
+
26
+ def mapped?
27
+ @mapped
28
+ end
29
+
30
+ private
31
+ def parse_params(params)
32
+ params = params.except(:controller, :action)
33
+ end
34
+
35
+ def map_fields(controller, mapped_fields, fields)
36
+ ignore_first_row = mapped_fields.delete(:ignore_first_row)
37
+ mapping = Mapping.new(mapped_fields, fields)
38
+ CSVReader.new(controller.session[:map_fields_file], mapping, ignore_first_row)
39
+ end
40
+
41
+ def get_fields(controller, fields)
42
+ if fields.is_a?(Symbol)
43
+ controller.send(fields)
44
+ elsif fields.respond_to?(:call)
45
+ fields.call
46
+ else
47
+ fields
48
+ end
49
+ end
50
+
51
+ def save_file(controller, file)
52
+ Tempfile.open(['map_fields', '.csv']) do |tmpfile|
53
+ tmpfile.write file.read
54
+ controller.session[:map_fields_file] = tmpfile.path
55
+ tmpfile.path
56
+ end
57
+ end
58
+
59
+ def parse_first_few_lines(file)
60
+ rows = []
61
+ rowcount = 0
62
+ CSV.foreach(file) do |row|
63
+ rows << row
64
+ break if (rowcount += 1) >= 10
65
+ end
66
+ rows
67
+ end
68
+ end
69
+
70
+ class CSVReader
71
+ def initialize(file, mapping, ignore_first_row)
72
+ @mapping = mapping
73
+ @ignore_first_row = ignore_first_row
74
+ @csv = CSV.open(file, :headers => ignore_first_row)
75
+ @rows = nil
76
+ end
77
+
78
+ def [](index)
79
+ get_row index
80
+ end
81
+
82
+ def each(&block)
83
+ @csv.each do |row|
84
+ block.call CSVRow.new(row, @mapping)
85
+ end
86
+ end
87
+
88
+ private
89
+ def get_row(index)
90
+ CSVRow.new((@rows ||= parse_csv)[index], @mapping)
91
+ end
92
+
93
+ def parse_csv
94
+ @csv.read
95
+ end
96
+ end
97
+
98
+ class CSVRow
99
+ def initialize(row, mapping)
100
+ @row = row
101
+ @mapping = mapping
102
+ end
103
+
104
+ def [](index)
105
+ @row[@mapping[index]]
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,26 @@
1
+ module MapFields
2
+ class Mapping
3
+ def initialize(mapping, fields)
4
+ @mapping = mapping
5
+ @fields = fields
6
+
7
+ @mapping = mapping.each_with_object({}){ |arr, hash|
8
+ key = arr[0].to_i
9
+ value = arr[1].to_i
10
+
11
+ hash[key] = value
12
+ hash[@fields[key]] = value
13
+ hash[field_to_symbol(@fields[key])] = value
14
+ }
15
+ end
16
+
17
+ def [](index)
18
+ @mapping[index]
19
+ end
20
+
21
+ private
22
+ def field_to_symbol(field)
23
+ field.to_s.downcase.gsub(/[^a-z0-9]+/, '_').to_sym
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,39 @@
1
+ module MapFields
2
+ class ParamsParser
3
+ def self.parse(params, field = nil)
4
+ result = []
5
+ params.each do |key, value|
6
+ next if [:controller, :action].include?(key.to_sym)
7
+ if field.nil? || field.to_s == key.to_s
8
+ check_values(value) do |k,v|
9
+ result << ["#{key.to_s}#{k}", v]
10
+ end
11
+ end
12
+ end
13
+ result
14
+ end
15
+
16
+ private
17
+ def self.check_values(value, &block)
18
+ result = []
19
+ if value.kind_of?(Hash)
20
+ value.each do |k,v|
21
+ check_values(v) do |k2,v2|
22
+ result << ["[#{k.to_s}]#{k2}", v2]
23
+ end
24
+ end
25
+ elsif value.kind_of?(Array)
26
+ value.each do |v|
27
+ check_values(v) do |k2, v2|
28
+ result << ["[]#{k2}", v2]
29
+ end
30
+ end
31
+ else
32
+ result << ["", value] unless value.respond_to?(:read)
33
+ end
34
+ result.each do |arr|
35
+ yield arr[0], arr[1]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ module MapFields
2
+ class Railtie < Rails::Railtie
3
+ AbstractController::Base.send(:include, MapFields::Controller)
4
+ end
5
+ end
data/lib/map_fields.rb CHANGED
@@ -1,201 +1,202 @@
1
- require 'fastercsv'
2
-
3
- module MapFields
4
- VERSION = '1.0.0'
5
-
6
- def self.included(base)
7
- base.extend(ClassMethods)
8
- end
9
-
10
- def map_fields
11
- default_options = {
12
- :file_field => 'file',
13
- :params => []
14
- }
15
- options = default_options.merge(
16
- self.class.read_inheritable_attribute(:map_fields_options)
17
- )
18
-
19
- RAILS_DEFAULT_LOGGER.debug("session[:map_fields]: #{session[:map_fields]}")
20
- RAILS_DEFAULT_LOGGER.debug("params[options[:file_field]]: #{params[options[:file_field]]}")
21
- if session[:map_fields].nil? || !params[options[:file_field]].blank?
22
- session[:map_fields] = {}
23
- if params[options[:file_field]].blank?
24
- @map_fields_error = MissingFileContentsError
25
- return
26
- end
27
-
28
- file_field = params[options[:file_field]]
29
-
30
- temp_path = File.join(Dir::tmpdir, "map_fields_#{Time.now.to_i}_#{$$}")
31
- File.open(temp_path, 'wb') do |f|
32
- f.write file_field.read
33
- end
34
-
35
- session[:map_fields][:file] = temp_path
36
- else
37
- if session[:map_fields][:file].nil? || params[:fields].nil?
38
- session[:map_fields] = nil
39
- @map_fields_error = InconsistentStateError
40
- else
41
- expected_fields = self.class.read_inheritable_attribute(:map_fields_fields)
42
- if expected_fields.respond_to?(:call)
43
- expected_fields = expected_fields.call(params)
44
- end
45
- @mapped_fields = MappedFields.new(session[:map_fields][:file],
46
- expected_fields,
47
- params[:fields],
48
- params[:ignore_first_row])
49
- end
50
- end
51
-
52
- unless @map_fields_error
53
- @rows = []
54
- begin
55
- FasterCSV.foreach(session[:map_fields][:file]) do |row|
56
- @rows << row
57
- break if @rows.size == 10
58
- end
59
- rescue FasterCSV::MalformedCSVError => e
60
- @map_fields_error = e
61
- end
62
- expected_fields = self.class.read_inheritable_attribute(:map_fields_fields)
63
- if expected_fields.respond_to?(:call)
64
- expected_fields = expected_fields.call(params)
65
- end
66
- @fields = ([nil] + expected_fields).inject([]){ |o, e| o << [e, o.size]}
67
- @parameters = []
68
- options[:params].each do |param|
69
- @parameters += ParamsParser.parse(params, param)
70
- end
71
- end
72
- end
73
-
74
- def mapped_fields
75
- @mapped_fields
76
- end
77
-
78
- def fields_mapped?
79
- raise @map_fields_error if @map_fields_error
80
- @mapped_fields
81
- end
82
-
83
- def map_field_parameters(&block)
84
-
85
- end
86
-
87
- def map_fields_cleanup
88
- if @mapped_fields
89
- if session[:map_fields][:file]
90
- File.delete(session[:map_fields][:file])
91
- end
92
- session[:map_fields] = nil
93
- @mapped_fields = nil
94
- @map_fields_error = nil
95
- end
96
- end
97
-
98
- module ClassMethods
99
- def map_fields(actions, fields, options = {})
100
- write_inheritable_attribute(:map_fields_fields, fields)
101
- write_inheritable_attribute(:map_fields_options, options)
102
- before_filter :map_fields, :only => actions
103
- after_filter :map_fields_cleanup, :only => actions
104
- end
105
- end
106
-
107
- class MappedFields
108
- attr_reader :mapping, :ignore_first_row, :file
109
-
110
- def initialize(file, fields, mapping, ignore_first_row)
111
- @file = file
112
- @fields = fields
113
- @mapping = {}
114
- @ignore_first_row = ignore_first_row == '1'
115
-
116
- mapping.each do |k,v|
117
- unless v.to_i == 0
118
- #Numeric mapping
119
- @mapping[v.to_i - 1] = k.to_i - 1
120
- #Text mapping
121
- @mapping[fields[v.to_i-1]] = k.to_i - 1
122
- #Symbol mapping
123
- sym_key = fields[v.to_i-1].downcase.
124
- gsub(/[-\s\/]+/, '_').
125
- gsub(/[^a-zA-Z0-9_]+/, '').
126
- to_sym
127
- @mapping[sym_key] = k.to_i - 1
128
- end
129
- end
130
- end
131
-
132
- def is_mapped?(field)
133
- !@mapping[field].nil?
134
- end
135
-
136
- def each
137
- row_number = 1
138
- FasterCSV.foreach(@file) do |csv_row|
139
- unless row_number == 1 && @ignore_first_row
140
- row = {}
141
- @mapping.each do |k,v|
142
- row[k] = csv_row[v]
143
- end
144
- row.class.send(:define_method, :number) { row_number }
145
- yield(row)
146
- end
147
- row_number += 1
148
- end
149
- end
150
- end
151
-
152
- class InconsistentStateError < StandardError
153
- end
154
-
155
- class MissingFileContentsError < StandardError
156
- end
157
-
158
- class ParamsParser
159
- def self.parse(params, field = nil)
160
- result = []
161
- params.each do |key,value|
162
- if field.nil? || field.to_s == key.to_s
163
- check_values(value) do |k,v|
164
- result << ["#{key.to_s}#{k}", v]
165
- end
166
- end
167
- end
168
- result
169
- end
170
-
171
- private
172
- def self.check_values(value, &block)
173
- result = []
174
- if value.kind_of?(Hash)
175
- value.each do |k,v|
176
- check_values(v) do |k2,v2|
177
- result << ["[#{k.to_s}]#{k2}", v2]
178
- end
179
- end
180
- elsif value.kind_of?(Array)
181
- value.each do |v|
182
- check_values(v) do |k2, v2|
183
- result << ["[]#{k2}", v2]
184
- end
185
- end
186
- else
187
- result << ["", value]
188
- end
189
- result.each do |arr|
190
- yield arr[0], arr[1]
191
- end
192
- end
193
- end
194
- end
195
-
196
- if defined?(Rails) and defined?(ActionController)
197
- ActionController::Base.send(:include, MapFields)
198
- ActionController::Base.view_paths.push File.expand_path(File.join(File.dirname(__FILE__), '..', 'views'))
199
- #This is a hack but the above code is not enough when using bundler and Rails 2.3.5
200
- ActionController::Base.view_paths.push "app/views"
201
- end
1
+ require 'map_fields/controller'
2
+ require 'map_fields/railtie' if defined?(Rails)
3
+
4
+ # module MapFields
5
+ # VERSION = '1.0.0'
6
+
7
+ # def self.included(base)
8
+ # base.extend(ClassMethods)
9
+ # end
10
+
11
+ # def map_fields
12
+ # default_options = {
13
+ # :file_field => 'file',
14
+ # :params => []
15
+ # }
16
+ # options = default_options.merge(
17
+ # self.class.read_inheritable_attribute(:map_fields_options)
18
+ # )
19
+
20
+ # RAILS_DEFAULT_LOGGER.debug("session[:map_fields]: #{session[:map_fields]}")
21
+ # RAILS_DEFAULT_LOGGER.debug("params[options[:file_field]]: #{params[options[:file_field]]}")
22
+ # if session[:map_fields].nil? || !params[options[:file_field]].blank?
23
+ # session[:map_fields] = {}
24
+ # if params[options[:file_field]].blank?
25
+ # @map_fields_error = MissingFileContentsError
26
+ # return
27
+ # end
28
+
29
+ # file_field = params[options[:file_field]]
30
+
31
+ # temp_path = File.join(Dir::tmpdir, "map_fields_#{Time.now.to_i}_#{$$}")
32
+ # File.open(temp_path, 'wb') do |f|
33
+ # f.write file_field.read
34
+ # end
35
+
36
+ # session[:map_fields][:file] = temp_path
37
+ # else
38
+ # if session[:map_fields][:file].nil? || params[:fields].nil?
39
+ # session[:map_fields] = nil
40
+ # @map_fields_error = InconsistentStateError
41
+ # else
42
+ # expected_fields = self.class.read_inheritable_attribute(:map_fields_fields)
43
+ # if expected_fields.respond_to?(:call)
44
+ # expected_fields = expected_fields.call(params)
45
+ # end
46
+ # @mapped_fields = MappedFields.new(session[:map_fields][:file],
47
+ # expected_fields,
48
+ # params[:fields],
49
+ # params[:ignore_first_row])
50
+ # end
51
+ # end
52
+
53
+ # unless @map_fields_error
54
+ # @rows = []
55
+ # begin
56
+ # FasterCSV.foreach(session[:map_fields][:file]) do |row|
57
+ # @rows << row
58
+ # break if @rows.size == 10
59
+ # end
60
+ # rescue FasterCSV::MalformedCSVError => e
61
+ # @map_fields_error = e
62
+ # end
63
+ # expected_fields = self.class.read_inheritable_attribute(:map_fields_fields)
64
+ # if expected_fields.respond_to?(:call)
65
+ # expected_fields = expected_fields.call(params)
66
+ # end
67
+ # @fields = ([nil] + expected_fields).inject([]){ |o, e| o << [e, o.size]}
68
+ # @parameters = []
69
+ # options[:params].each do |param|
70
+ # @parameters += ParamsParser.parse(params, param)
71
+ # end
72
+ # end
73
+ # end
74
+
75
+ # def mapped_fields
76
+ # @mapped_fields
77
+ # end
78
+
79
+ # def fields_mapped?
80
+ # raise @map_fields_error if @map_fields_error
81
+ # @mapped_fields
82
+ # end
83
+
84
+ # def map_field_parameters(&block)
85
+
86
+ # end
87
+
88
+ # def map_fields_cleanup
89
+ # if @mapped_fields
90
+ # if session[:map_fields][:file]
91
+ # File.delete(session[:map_fields][:file])
92
+ # end
93
+ # session[:map_fields] = nil
94
+ # @mapped_fields = nil
95
+ # @map_fields_error = nil
96
+ # end
97
+ # end
98
+
99
+ # module ClassMethods
100
+ # def map_fields(actions, fields, options = {})
101
+ # write_inheritable_attribute(:map_fields_fields, fields)
102
+ # write_inheritable_attribute(:map_fields_options, options)
103
+ # before_filter :map_fields, :only => actions
104
+ # after_filter :map_fields_cleanup, :only => actions
105
+ # end
106
+ # end
107
+
108
+ # class MappedFields
109
+ # attr_reader :mapping, :ignore_first_row, :file
110
+
111
+ # def initialize(file, fields, mapping, ignore_first_row)
112
+ # @file = file
113
+ # @fields = fields
114
+ # @mapping = {}
115
+ # @ignore_first_row = ignore_first_row == '1'
116
+
117
+ # mapping.each do |k,v|
118
+ # unless v.to_i == 0
119
+ # #Numeric mapping
120
+ # @mapping[v.to_i - 1] = k.to_i - 1
121
+ # #Text mapping
122
+ # @mapping[fields[v.to_i-1]] = k.to_i - 1
123
+ # #Symbol mapping
124
+ # sym_key = fields[v.to_i-1].downcase.
125
+ # gsub(/[-\s\/]+/, '_').
126
+ # gsub(/[^a-zA-Z0-9_]+/, '').
127
+ # to_sym
128
+ # @mapping[sym_key] = k.to_i - 1
129
+ # end
130
+ # end
131
+ # end
132
+
133
+ # def is_mapped?(field)
134
+ # !@mapping[field].nil?
135
+ # end
136
+
137
+ # def each
138
+ # row_number = 1
139
+ # FasterCSV.foreach(@file) do |csv_row|
140
+ # unless row_number == 1 && @ignore_first_row
141
+ # row = {}
142
+ # @mapping.each do |k,v|
143
+ # row[k] = csv_row[v]
144
+ # end
145
+ # row.class.send(:define_method, :number) { row_number }
146
+ # yield(row)
147
+ # end
148
+ # row_number += 1
149
+ # end
150
+ # end
151
+ # end
152
+
153
+ # class InconsistentStateError < StandardError
154
+ # end
155
+
156
+ # class MissingFileContentsError < StandardError
157
+ # end
158
+
159
+ # class ParamsParser
160
+ # def self.parse(params, field = nil)
161
+ # result = []
162
+ # params.each do |key,value|
163
+ # if field.nil? || field.to_s == key.to_s
164
+ # check_values(value) do |k,v|
165
+ # result << ["#{key.to_s}#{k}", v]
166
+ # end
167
+ # end
168
+ # end
169
+ # result
170
+ # end
171
+
172
+ # private
173
+ # def self.check_values(value, &block)
174
+ # result = []
175
+ # if value.kind_of?(Hash)
176
+ # value.each do |k,v|
177
+ # check_values(v) do |k2,v2|
178
+ # result << ["[#{k.to_s}]#{k2}", v2]
179
+ # end
180
+ # end
181
+ # elsif value.kind_of?(Array)
182
+ # value.each do |v|
183
+ # check_values(v) do |k2, v2|
184
+ # result << ["[]#{k2}", v2]
185
+ # end
186
+ # end
187
+ # else
188
+ # result << ["", value]
189
+ # end
190
+ # result.each do |arr|
191
+ # yield arr[0], arr[1]
192
+ # end
193
+ # end
194
+ # end
195
+ # end
196
+
197
+ # if defined?(Rails) and defined?(ActionController)
198
+ # ActionController::Base.send(:include, MapFields)
199
+ # ActionController::Base.view_paths.push File.expand_path(File.join(File.dirname(__FILE__), '..', 'views'))
200
+ # #This is a hack but the above code is not enough when using bundler and Rails 2.3.5
201
+ # ActionController::Base.view_paths.push "app/views"
202
+ # end
data/spec/spec_helper.rb CHANGED
@@ -1,45 +1,13 @@
1
- RAILS_ROOT = File.join(File.dirname(__FILE__), 'rails_root')
2
- RAILS_ENV = 'test'
1
+ ENV['RAILS_ENV'] = 'test'
3
2
 
4
- #Needed for autospec
5
- $LOAD_PATH << "spec"
6
- $LOAD_PATH << "lib"
3
+ $:.unshift File.expand_path('../../lib', __FILE__)
7
4
 
8
- require 'rubygems'
9
- #Needed for rspec_rails
10
- require 'rails/version'
11
- require 'action_controller'
12
- require 'action_controller/test_process'
13
- require 'spec/rails'
14
- require File.join(File.dirname(__FILE__), '..', 'lib', 'map_fields')
5
+ require 'bundler'
6
+ require File.expand_path('../../rails_app/config/environment.rb', __FILE__)
7
+ require 'rails/test_help'
8
+ require 'rspec/rails'
9
+ require 'map_fields'
15
10
 
16
- require File.join(File.dirname(__FILE__), '..', 'init')
17
-
18
- Spec::Runner.configure do |config|
19
- #config.use_transactional_fixtures = true
20
- end
21
-
22
- class TestController < ApplicationController
23
- map_fields :create, ['Title', 'First name', 'Last name'], :params => [:user]
24
-
25
- def new
26
- end
27
-
28
- def create
29
- if fields_mapped?
30
- mapped_fields.each do |row|
31
- #deal with the data
32
- row[0] #=> will be Title
33
- row[1] #=> will be First name
34
- row[2] #=> will be Last name
35
- end
36
- render :text => ''
37
- else
38
- render 'map_fields/_map_fields'
39
- end
40
- end
41
- end
42
-
43
- ActionController::Routing::Routes.draw do |map|
44
- map.resources :test
11
+ RailsApp::Application.routes.draw do
12
+ resources :test
45
13
  end
metadata CHANGED
@@ -1,71 +1,55 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: map_fields
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 1.0.4
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0.beta
5
+ prerelease: 6
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Andrew Timberlake
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-06-13 00:00:00 +02:00
14
- default_executable:
12
+ date: 2011-06-13 00:00:00.000000000 Z
15
13
  dependencies: []
16
-
17
14
  description:
18
15
  email: andrew@andrewtimberlake.com
19
16
  executables: []
20
-
21
17
  extensions: []
22
-
23
- extra_rdoc_files:
18
+ extra_rdoc_files:
24
19
  - README.rdoc
25
- files:
26
- - .autotest
20
+ files:
27
21
  - README.rdoc
28
- - Rakefile
29
- - VERSION
30
- - announcement.txt
31
- - init.rb
22
+ - lib/map_fields/controller.rb
23
+ - lib/map_fields/mapper.rb
24
+ - lib/map_fields/mapping.rb
25
+ - lib/map_fields/params_parser.rb
26
+ - lib/map_fields/railtie.rb
32
27
  - lib/map_fields.rb
33
- - spec/application_controller.rb
34
- - spec/controllers/test_controller_spec.rb
35
- - spec/lib/params_parser_spec.rb
36
28
  - spec/spec_helper.rb
37
- - spec/test-file.csv
38
- - views/map_fields/_map_fields.erb
39
- has_rdoc: true
40
29
  homepage: http://github.com/internuity/map-fields
41
30
  licenses: []
42
-
43
31
  post_install_message:
44
32
  rdoc_options: []
45
-
46
- require_paths:
33
+ require_paths:
47
34
  - lib
48
- required_ruby_version: !ruby/object:Gem::Requirement
35
+ required_ruby_version: !ruby/object:Gem::Requirement
49
36
  none: false
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: "0"
54
- required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
42
  none: false
56
- requirements:
57
- - - ">="
58
- - !ruby/object:Gem::Version
59
- version: "0"
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
60
47
  requirements: []
61
-
62
48
  rubyforge_project:
63
- rubygems_version: 1.5.2
49
+ rubygems_version: 1.8.10
64
50
  signing_key:
65
51
  specification_version: 3
66
- summary: Rails plugin to allow a user to map the fields of a CSV to an expected list of fields
67
- test_files:
68
- - spec/application_controller.rb
69
- - spec/controllers/test_controller_spec.rb
70
- - spec/lib/params_parser_spec.rb
52
+ summary: Rails gem to allow a user to map the fields of a CSV to an expected list
53
+ of fields
54
+ test_files:
71
55
  - spec/spec_helper.rb
data/.autotest DELETED
@@ -1,2 +0,0 @@
1
- # -*- ruby -*-
2
- require 'autotest/redgreen'
data/Rakefile DELETED
@@ -1,16 +0,0 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "map_fields"
8
- gem.summary = %Q{Rails plugin to allow a user to map the fields of a CSV to an expected list of fields}
9
- gem.email = "andrew@andrewtimberlake.com"
10
- gem.homepage = "http://github.com/internuity/map-fields"
11
- gem.authors = ["Andrew Timberlake"]
12
- end
13
- Jeweler::GemcutterTasks.new
14
- rescue LoadError
15
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
16
- end
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.0.4
data/announcement.txt DELETED
@@ -1,12 +0,0 @@
1
- map-fields version 1.0.0
2
- by Andrew Timberlake
3
- http://github.com/internuity/map-fields
4
-
5
- == DESCRIPTION
6
-
7
- A Rails plugin which provides a hook to preview and map the fields of an uploaded CSV file to a pre-defined schema
8
-
9
- == CHANGES
10
-
11
- * Initial release
12
-
data/init.rb DELETED
@@ -1 +0,0 @@
1
- require 'map_fields'
@@ -1,2 +0,0 @@
1
- class ApplicationController < ActionController::Base
2
- end
@@ -1,56 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- describe TestController do
4
-
5
- context "on upload" do
6
- context "with an attached file" do
7
- before do
8
- test_file = ActionController::TestUploadedFile.new(File.join(File.dirname(__FILE__), '..', 'test-file.csv'))
9
-
10
- File.should_receive(:open) do |path, flags|
11
- path.should match(Regexp.new(Dir::tmpdir))
12
- flags.should == 'wb'
13
- end
14
- FasterCSV.should_receive(:foreach)
15
-
16
- post :create, :file => test_file, :user => {:first_name => 'Test', :last_name => 'User'}
17
- end
18
-
19
- it "should assign to @fields" do
20
- assigns[:fields].should_not be_blank
21
- end
22
-
23
- it "should store the file location in the session" do
24
- session[:map_fields][:file].should_not be_blank
25
- end
26
-
27
- it "should assign to @parameters" do
28
- assigns[:parameters].should_not be_blank
29
- end
30
-
31
- it "should have the first name parameter" do
32
- assigns[:parameters].should include(['user[first_name]', 'Test'])
33
- end
34
-
35
- it "should have the last name parameters" do
36
- assigns[:parameters].should include(['user[last_name]', 'User'])
37
- end
38
- end
39
-
40
- context "without an attached file" do
41
- it "should raise an error" do
42
- lambda { post :create }.should raise_error
43
- end
44
- end
45
- end
46
-
47
- context "on second post" do
48
- it "should map the fields" do
49
- session[:map_fields] = {:file => '/tmp/test'}
50
- FasterCSV.expects(:foreach)
51
- File.expects(:delete).with('/tmp/test')
52
-
53
- post :create, :fields => {"1" => "2", "2" => "3", "3" => "1"}
54
- end
55
- end
56
- end
@@ -1,99 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- describe MapFields::ParamsParser do
4
- context "with no specific field specified" do
5
- it "should be able to parse params[:id] = '1'" do
6
- params = {:id => '1'}
7
-
8
- MapFields::ParamsParser.parse(params).should == [["id", "1"]]
9
- end
10
-
11
- it "should be able to parse params[:user][:id] = '1'" do
12
- params = {:user => {:id => '1'}}
13
-
14
- MapFields::ParamsParser.parse(params).should == [["user[id]", "1"]]
15
- end
16
-
17
- it "should be able to parse params[:user][] = '1'" do
18
- params = {:user => ['1']}
19
-
20
- MapFields::ParamsParser.parse(params).should == [["user[]", "1"]]
21
- end
22
-
23
- it "should be able to parse params[:user][] = '1' with multiple entries" do
24
- params = {:user => ['1', '2', '3']}
25
-
26
- MapFields::ParamsParser.parse(params).size.should == 3
27
- MapFields::ParamsParser.parse(params)[0].should == ["user[]", "1"]
28
- MapFields::ParamsParser.parse(params)[1].should == ["user[]", "2"]
29
- MapFields::ParamsParser.parse(params)[2].should == ["user[]", "3"]
30
- end
31
-
32
- it "should be able to parse params[:user][:sub][:id] = '1'" do
33
- params = {:user => {:sub => {:id => '1'}}}
34
-
35
- MapFields::ParamsParser.parse(params).should == [["user[sub][id]", "1"]]
36
- end
37
-
38
- it "should be able to parse params[:user][:sub][] = '1'" do
39
- params = {:user => {:sub => ['1']}}
40
-
41
- MapFields::ParamsParser.parse(params).should == [["user[sub][]", "1"]]
42
- end
43
-
44
- it "should be able to parse params[:user][:sub][] = '1' with multiple entries" do
45
- params = {:user => {:sub => ['1', '2', '3']}}
46
-
47
- MapFields::ParamsParser.parse(params).size.should == 3
48
- MapFields::ParamsParser.parse(params)[0].should == ["user[sub][]", "1"]
49
- MapFields::ParamsParser.parse(params)[1].should == ["user[sub][]", "2"]
50
- MapFields::ParamsParser.parse(params)[2].should == ["user[sub][]", "3"]
51
- end
52
-
53
- it "should be able to parse params[:user][:sub][:sub2][] = '1'" do
54
- params = {:user => {:sub => {:sub2 => ['1']}}}
55
-
56
- MapFields::ParamsParser.parse(params).should == [["user[sub][sub2][]", "1"]]
57
- end
58
-
59
- it "should be able to parse a complicated collection of parameters" do
60
- params = {:user => {:sub => {:sub2 => ['1']}},
61
- :test => '1',
62
- :other => ['collection', 'of', 'parameters'],
63
- :checking => {:if => ['it', 'can'],
64
- :handle => '1',
65
- :big => {:bunch => {:of => {:rubish => ['thrown', 'at'],
66
- :it => 'yes'}}}
67
- }
68
- }
69
-
70
- MapFields::ParamsParser.parse(params).should include(["user[sub][sub2][]", "1"])
71
- MapFields::ParamsParser.parse(params).should include(["test", "1"])
72
- MapFields::ParamsParser.parse(params).should include(["other[]", "collection"])
73
- MapFields::ParamsParser.parse(params).should include(["other[]", "of"])
74
- MapFields::ParamsParser.parse(params).should include(["other[]", "parameters"])
75
- MapFields::ParamsParser.parse(params).should include(["checking[if][]", "it"])
76
- MapFields::ParamsParser.parse(params).should include(["checking[if][]", "can"])
77
- MapFields::ParamsParser.parse(params).should include(["checking[handle]", "1"])
78
- MapFields::ParamsParser.parse(params).should include(["checking[big][bunch][of][rubish][]", "thrown"])
79
- MapFields::ParamsParser.parse(params).should include(["checking[big][bunch][of][rubish][]", "at"])
80
- MapFields::ParamsParser.parse(params).should include(["checking[big][bunch][of][it]", "yes"])
81
- end
82
- end
83
-
84
- context "with a specified parameter" do
85
- it "should be able to get only the requested field" do
86
- params = {:user => {:sub => {:sub2 => ['1']}},
87
- :test => ['another', 'parameter']
88
- }
89
-
90
- MapFields::ParamsParser.parse(params, :user).should == [["user[sub][sub2][]", "1"]]
91
- end
92
-
93
- it "should be able to parse params[:user][:sub][:sub2][] = '1'" do
94
- params = {:user => {:sub => {:sub2 => ['1']}}}
95
-
96
- MapFields::ParamsParser.parse(params, :user).should == [["user[sub][sub2][]", "1"]]
97
- end
98
- end
99
- end
data/spec/test-file.csv DELETED
@@ -1,3 +0,0 @@
1
- Title,Lastname,Firstname,Email
2
- Mr,John,Doe,john.doe@example.com
3
- Mrs,Jane,Doe,jane.doe@example.com
@@ -1,31 +0,0 @@
1
- <% form_tag nil, :id => 'map_fields_form', :method => :post do -%>
2
- <% @parameters.each do |arr| -%>
3
- <%= hidden_field_tag arr[0], arr[1] %>
4
- <% end -%>
5
- <div class="map_fields">
6
- <table cellspacing="0">
7
- <thead>
8
- <tr>
9
- <% (1..@rows[0].size).each do |c| -%>
10
- <th><%= select_tag "fields[#{c}]", options_for_select(@fields), :include_blank => true, :class => 'field_options' %></th>
11
- <% end -%>
12
- </tr>
13
- </thead>
14
- <tbody>
15
- <% @rows.each do |row| -%>
16
- <tr>
17
- <% row.each do |column| -%>
18
- <td><%= h(column) %></td>
19
- <% end -%>
20
- </tr>
21
- <% end -%>
22
- </tbody>
23
- </table>
24
- </div>
25
- <div class="option">
26
- <%= check_box_tag 'ignore_first_row', '1', true, :id => 'ignore_first_row_option' %><label for="ignore_first_row_option">Ignore the first row (headings)</label>
27
- </div>
28
- <div class="action">
29
- <%= submit_tag 'Import' %>
30
- </div>
31
- <% end -%>