map_fields 1.0.4 → 2.0.0.beta

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/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 -%>