importance 0.2.0 → 0.2.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0df06e38c78ddb548f82dd7108a1ff45ac679ad21c8b6549ccba6107cbf37b3
4
- data.tar.gz: 1cd461bbaf521ab3d4358faa4accf85553d47fbb9941b8462d7e4342a154b45e
3
+ metadata.gz: 9f0dbf1d26a306836bbe35292350eb8f7cb58cbe665c0e37e06449f47d8c119c
4
+ data.tar.gz: b1bcbb1da753d6ffb93b7602afeb7c990f93744f1c9b17b0a3b4de6b61858f46
5
5
  SHA512:
6
- metadata.gz: 855023fbe7167ff911683626c1e3f0d2eb0ae058f261f56c7f2e9d96afb01dc40e8a7e192f62fb1f47c79e824a971b8b46dee408d0b68370fc304695a0e66020
7
- data.tar.gz: 0b98ee22a71bb61a5cf7a218795eb934b418317dde08ebd22bd267757d7648c531d0ae0e432ec5e4746146ca54562620c2d397c005473fc237aa19cde80f8b23
6
+ metadata.gz: 05b520199b43d3db0af5d4a276494c7f5d9b7224bf6ec775fafb55def64e856a971bc0a411df5c345fe97c7cec997e8381839295acc952dd1f49d1746c4d1c70
7
+ data.tar.gz: 6b466a41845678c9e572e3e930874fe84d7e0e6e9f4e30fa1bda2c6ee979566ff4d14761a9b81c00065e4a79b40f791454fca418deda3d46141c6fdf294b30ea
data/README.md CHANGED
@@ -130,6 +130,7 @@ the first row is automatically treated as the header row.
130
130
  ```erb
131
131
  <%= form_with url: importance.submit_path(importer: :students), multipart: true do |form| %>
132
132
  <%= form.file_field :file, accept: ".xlsx,.xls,.csv" %>
133
+ <%= form.hidden_field :redirect_url, value: root_path >
133
134
  <%= form.submit "Submit" %>
134
135
  <% end %>
135
136
  ```
data/Rakefile CHANGED
@@ -6,3 +6,13 @@ load "rails/tasks/engine.rake"
6
6
  load "rails/tasks/statistics.rake"
7
7
 
8
8
  require "bundler/gem_tasks"
9
+
10
+ require "rake/testtask"
11
+
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << "test"
14
+ t.pattern = "test/**/*_test.rb"
15
+ t.verbose = false
16
+ end
17
+
18
+ task default: :test
@@ -1,4 +1,4 @@
1
- require "xsv"
1
+ require "roo"
2
2
  require "csv"
3
3
 
4
4
  module Importance
@@ -26,6 +26,7 @@ module Importance
26
26
 
27
27
  session[:path] = persist_path
28
28
  session[:importer] = params[:importer].to_sym
29
+ session[:redirect_url] = params[:redirect_url]
29
30
 
30
31
  redirect_to map_path
31
32
  end
@@ -36,22 +37,19 @@ module Importance
36
37
 
37
38
  raise ArgumentError, "Importer cannot be nil" if importer.nil?
38
39
 
39
- if csv_file?
40
- csv_data = CSV.read(session[:path], headers: true)
41
- @file_headers = csv_data.headers
42
- @samples = csv_data.first(5).map(&:to_h)
43
- else
44
- workbook = Xsv.open(session[:path], parse_headers: true)
45
- worksheet = workbook.first
46
- @file_headers = worksheet.first.keys
47
- @samples = worksheet.first(5)
48
- end
40
+ workbook = Roo::Spreadsheet.open(session[:path], { csv_options: { encoding: "bom|utf-8" } })
41
+ worksheet = workbook.sheet(0)
42
+ @file_headers = worksheet.row(1)
43
+ @samples = worksheet.parse[1..5]
44
+ @full_count = worksheet.count - 1
49
45
 
50
46
  @importer_attributes = importer.attributes
51
47
  @layout = "Importance::#{Importance.configuration.layout.to_s.camelize}Layout".constantize
52
48
  end
53
49
 
54
50
  # Import page. Load the file according to the mapping and import it.
51
+ # Mappings param is of the form mappings[excel_column_idx] = target_attribute
52
+ # mappings[0] = "first_name", mappings[1] = "", mappings[2] = "last_name" ...
55
53
  def import
56
54
  importer = Importance.configuration.importers[session[:importer].to_sym]
57
55
  mappings = params[:mappings]
@@ -81,7 +79,7 @@ module Importance
81
79
  if importer.teardown_callback
82
80
  instance_exec(&importer.teardown_callback)
83
81
  else
84
- redirect_to session[:redirect_url] || root_path, notice: "Import completed."
82
+ redirect_to (session[:redirect_url] || main_app.root_path), notice: "Import completed."
85
83
  end
86
84
 
87
85
  rescue => e
@@ -97,33 +95,31 @@ module Importance
97
95
  File.extname(session[:path]).downcase == ".csv"
98
96
  end
99
97
 
98
+ # Yields each processed row (a hash of attribute => value) to the given block.
99
+ # Skips empty rows (all values nil or empty).
100
100
  def each_processed_row(mappings)
101
- if csv_file?
102
- CSV.foreach(session[:path], headers: true) do |row|
103
- record = process_row(row.to_h, mappings)
104
- next if record.empty? || record.values.all? { |v| v.nil? || v.to_s.strip.empty? }
105
- yield record
106
- end
107
- else
108
- workbook = Xsv.open(session[:path], parse_headers: true)
109
- worksheet = workbook.first
110
- worksheet.each do |row|
111
- record = process_row(row, mappings)
112
- next if record.empty? || record.values.all? { |v| v.nil? || v.to_s.strip.empty? }
113
- yield record
114
- end
101
+ workbook = Roo::Spreadsheet.open(session[:path], { csv_options: { encoding: "bom|utf-8" } })
102
+ worksheet = workbook.sheet(0)
103
+ worksheet.each_with_index do |row, idx|
104
+ next if idx == 0 # Skip header row
105
+ record = process_row(row, mappings)
106
+ next if record.empty? || record.values.all? { |v| v.nil? || v.to_s.strip.empty? }
107
+ yield record
115
108
  end
116
109
  end
117
110
 
111
+ # Turn a row of the form ["Hans", "Robert", 1970, "male", "Apple Inc.", "hr@apple.com"]
112
+ # and a mapping of the form {"0"=>"first_name", "1"=>"last_name", "2"=>"", "3"=>"", "4"=>"", "5"=>"email"}
113
+ # into a record of the form { first_name: "Hans", last_name: "Robert", email: "hr@apple.com" }
118
114
  def process_row(row, mappings)
119
115
  record = {}
120
- row.each do |row_header, value|
121
- attribute = mappings.permit!.to_h.find { |column_name, attribute_name| column_name == row_header }
122
- next if attribute.nil?
123
- attribute = attribute[1]
124
- next if attribute.nil? || attribute == ""
125
- record[attribute.to_sym] = value
116
+
117
+ mappings.each do |column_index, attribute_name|
118
+ next if attribute_name.nil? || attribute_name == ""
119
+ value = row[column_index.to_i]
120
+ record[attribute_name.to_sym] = value
126
121
  end
122
+
127
123
  record
128
124
  end
129
125
 
@@ -4,14 +4,14 @@
4
4
  <table class="importance-table <%= @layout.table_class %>">
5
5
  <thead>
6
6
  <tr>
7
- <% @file_headers.each do |file_header| %>
7
+ <% @file_headers.each_with_index do |file_header, file_header_idx| %>
8
8
  <th>
9
9
  <%= t('importance.use_column_as') %>
10
10
  <%
11
11
  attribute_mappings = Importance::Header.match_attributes_to_headers(@importer_attributes, @file_headers)
12
12
  default_value = Importance::Header.default_value_for_header(file_header, attribute_mappings)
13
13
  %>
14
- <%= form.select "mappings[#{file_header}]",
14
+ <%= form.select "mappings[#{file_header_idx}]",
15
15
  options_for_select(
16
16
  [[t('importance.ignore'), ""]] +
17
17
  @importer_attributes.map { |attr| [attr.labels.first, attr.key] },
@@ -29,13 +29,16 @@
29
29
  <tbody>
30
30
  <% @samples.each do |sample| %>
31
31
  <tr>
32
- <% @file_headers.each do |file_header| %>
33
- <td><%= sample[file_header] %></td>
32
+ <% @file_headers.each_with_index do |file_header, file_header_idx| %>
33
+ <td><%= sample[file_header_idx] %></td>
34
34
  <% end %>
35
35
  </tr>
36
36
  <% end %>
37
37
  </tbody>
38
38
  </table>
39
+ <p>
40
+ <%= t('importance.import_description', count: @samples.count, full_count: @full_count) %>
41
+ </p>
39
42
  </div>
40
43
  <% end %>
41
44
 
@@ -3,3 +3,4 @@ de:
3
3
  use_column_as: Spalte verwenden als
4
4
  ignore: Ignorieren
5
5
  import: Importieren
6
+ import_description: "Es werden %{count} von %{full_count} Beispieldatensätzen angezeigt."
@@ -3,3 +3,4 @@ en:
3
3
  use_column_as: Use column as
4
4
  ignore: Ignore
5
5
  import: Import
6
+ import_description: "Showing %{count} of %{full_count} sample records."
@@ -3,3 +3,4 @@ fr:
3
3
  use_column_as: Utiliser la colonne comme
4
4
  ignore: Ignorer
5
5
  import: Importer
6
+ import_description: "Affichage de %{count} sur %{full_count} exemples d'enregistrements."
@@ -3,3 +3,4 @@ it:
3
3
  use_column_as: Utilizzare come
4
4
  ignore: Ignora
5
5
  import: Importare
6
+ import_description: "Mostrati %{count} di %{full_count} record di esempio."
@@ -1,3 +1,3 @@
1
1
  module Importance
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: importance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lukas_Skywalker
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-06-07 00:00:00.000000000 Z
11
+ date: 2025-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 7.0.2
27
27
  - !ruby/object:Gem::Dependency
28
- name: xsv
28
+ name: roo
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.3'
33
+ version: '3.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.3'
40
+ version: '3.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: ostruct
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -45,27 +45,13 @@ dependencies:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0.6'
48
- type: :development
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0.6'
55
- - !ruby/object:Gem::Dependency
56
- name: debug
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '1.10'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '1.10'
69
55
  description: Importance is a Rails engine that allows users to upload Excel and CSV
70
56
  files and interactively map columns to model attributes. It handles files with arbitrary
71
57
  headers by letting users select which columns to import and which to ignore, with
@@ -127,7 +113,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
113
  - !ruby/object:Gem::Version
128
114
  version: '0'
129
115
  requirements: []
130
- rubygems_version: 3.5.16
116
+ rubygems_version: 3.5.22
131
117
  signing_key:
132
118
  specification_version: 4
133
119
  summary: Flexible Excel and CSV import engine with column mapping for Rails applications