rails-importer 0.0.7 → 0.0.12

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
- SHA1:
3
- metadata.gz: 6281fb4ece61433a46c9365db6929dc23b479d6c
4
- data.tar.gz: 6e6c0730bfb4a252fe827b7116cd521e6f76cb0f
2
+ SHA256:
3
+ metadata.gz: 21fedbfaf0623b35213ec6e37dafab5d3a11040ffaae8add9613e726743b441c
4
+ data.tar.gz: 3ba9d86e6cdd1b2cd4217c52b9718ebc2e654ac128d1d14551165891c3501282
5
5
  SHA512:
6
- metadata.gz: 4940a022355897d904c48cd390c3ba94c0b2f5317685dc023733b6324128f034f553a51604e9c478ac2230e0e1272186c45dda2038829ee864410ad13ddc09fd
7
- data.tar.gz: 750a1b7411b6f88559ad04671e36761b70c1701aecf93d887aef08985400b357fa466f0d78f075ba407f64243db48e9d3777c8c1716ca5589381eb99bf55ef06
6
+ metadata.gz: dddecdf677d03410d18c8df7977be529c5b571ee550263f40aff43544face6b4ef8a9227ae6c5e3f940db62640f49b6f0f6a098707bea9afeb3f7fbd1cb32f76
7
+ data.tar.gz: d20d9a502f0943fe733b655af1c42342565ed04461a3e5c2a4c9d4c86048786e41a16e849aea12c85c6f5a20135afd0efcd4489d320bb771b3e40f9c05d9c5f2
data/README.md CHANGED
@@ -30,12 +30,17 @@ class ExampleImporter < RailsImporter::Base
30
30
 
31
31
  importer do
32
32
  fields :name, :email, :age
33
+ #or fields({:name => "Name", :email => "E-mail", :age => "Idade"})
33
34
  each_record do |record, params|
35
+
34
36
  MyModel.find_or_create_by(name: record[:name], email: record[:email], age: record[:age])
37
+
38
+ return record # or return wherever
35
39
  end
36
40
  end
37
41
 
38
42
  # importer :simple do
43
+ # csv_params col_sep: ';'
39
44
  # xml_structure :root, :row
40
45
  # fields :name, :email, :age
41
46
  # each_record do |record, params|
@@ -49,14 +54,68 @@ end
49
54
  ### How to use
50
55
 
51
56
  You can call `import` from **Importers** objects:
52
- ```erb
57
+ **file param** must be an object that responds to `.path` method
58
+ ```ruby
53
59
  file = params[:import][:file]
54
- records = ExampleImporter.import(file, extra_param: 'Extra')
60
+ records = ExampleImporter.import(file)
55
61
  ```
56
62
 
57
63
  Or with context:
64
+ ```ruby
65
+ file = params[:import][:file]
66
+ records = ExampleImporter.import(file, context: :simple)
67
+ ```
68
+
69
+ Overwrite default fields (called in the block `importer do`):
70
+ ```ruby
71
+ file = params[:import][:file]
72
+ records = ExampleImporter.import(file, fields: [:name, :email, :age])
73
+ ```
58
74
 
59
- ```erb
75
+ With extra params:
76
+ ```ruby
60
77
  file = params[:import][:file]
61
- records = ExampleImporter.import(file, context: :simple, extra_param: 'Extra')
62
- ```
78
+ records = ExampleImporter.import(file, {user: 'john@mail.com'})
79
+ ```
80
+ Then inside each record you can get params:
81
+ ```ruby
82
+ class ExampleImporter < RailsImporter::Base
83
+ importer do
84
+ # ...
85
+ each_record do |record, params|
86
+ # ...
87
+ params[:user]
88
+ # ...
89
+ end
90
+ # ...
91
+ end
92
+ end
93
+ ```
94
+
95
+ With full options:
96
+ ```ruby
97
+ file = params[:import][:file]
98
+ records = ExampleImporter.import(file,
99
+ context: :simple,
100
+ fields: [:name, :email, :age],
101
+ {user: 'john@mail.com', account: '1'})
102
+ ```
103
+
104
+ To return imported values, you need to return values inside of `each_record`:
105
+ ```ruby
106
+ class ExampleImporter < RailsImporter::Base
107
+ importer do
108
+ # ...
109
+ each_record do |record, params|
110
+ # ...
111
+ u = Model.new(record)
112
+ u.created_by = params[:user]
113
+ ok = !!u.save
114
+ return {record: u, success: ok}
115
+ end
116
+ # ...
117
+ end
118
+ end
119
+ records = ExampleImporter.import(file, {user: 'john@mail.com'})
120
+ # [{record: ..., success: true}, {record: ..., success: false}]
121
+ ```
@@ -1,4 +1,7 @@
1
1
  en:
2
2
  importer:
3
3
  error:
4
- invalid_file_type: "Invalid file type allowed: %{file_types}"
4
+ invalid_file: "Invalid File instance."
5
+ invalid_file_type: "Invalid file type allowed: %{file_types}"
6
+ convert_number_to_text: "Error when convert number to text"
7
+
@@ -8,6 +8,7 @@ class <%= @importer_name %>Importer < RailsImporter::Base
8
8
  end
9
9
 
10
10
  # importer :simple do
11
+ # csv_params col_sep: ';'
11
12
  # xml_structure :root, :row
12
13
  # fields :name, :email, :age
13
14
  # each_record do |record, params|
@@ -8,18 +8,23 @@ module RailsImporter
8
8
  class << self
9
9
  def import(file, *args)
10
10
  context = args.try(:context) || :default
11
+ custom_fields = args.try(:fields) || nil
11
12
  result = []
12
13
  begin
13
- ext = (File.extname(file.path)[1..-1] rescue nil)
14
- if file.respond_to?(:path) and self.file_types.include?(ext.to_sym)
15
- rows = self.send("import_from_#{ext}", file)
16
- if rows.present? and rows.is_a?(Array)
17
- result = rows.map do |record|
18
- self.importers[context][:each_record].call(record, *args) if self.importers[context][:each_record].is_a?(Proc)
19
- end.compact
14
+ if file.respond_to?(:path)
15
+ ext = (File.extname(file.path)[1..-1] rescue '')
16
+ if self.file_types.include?(ext.to_sym)
17
+ rows = self.send('import_from_%s' % ext, file, context, custom_fields)
18
+ if rows.present? && rows.is_a?(Array)
19
+ result = rows.map do |record|
20
+ self.importers[context][:each_record].call(record, *args) if self.importers[context][:each_record].is_a?(Proc)
21
+ end.compact
22
+ end
23
+ else
24
+ result = I18n.t(:invalid_file_type, file_types: self.file_types.join(', '), scope: [:importer, :error])
20
25
  end
21
26
  else
22
- I18n.t(:invalid_file_type, file_types: self.file_types.join(', '), scope: [:importer, :error])
27
+ result = I18n.t(:invalid_file, scope: [:importer, :error])
23
28
  end
24
29
  rescue Exception => e
25
30
  result = e.message
@@ -37,8 +42,13 @@ module RailsImporter
37
42
  # end
38
43
  # end
39
44
 
40
- def importer(name=:default, &block)
41
- (self.importers ||= {})[name] ||= {fields: [], xml_structure: [:records, :record], each_record: nil}
45
+ def importer(name = :default, &block)
46
+ (self.importers ||= {})[name] ||= {
47
+ fields: [],
48
+ csv_params: {headers: false, col_sep: ',', force_quotes: true},
49
+ xml_structure: %i[records record],
50
+ each_record: nil
51
+ }
42
52
  @importer_name = name
43
53
  block.call if block_given?
44
54
  self.importers[name]
@@ -52,24 +62,34 @@ module RailsImporter
52
62
  importer_value(:xml_structure, attributes)
53
63
  end
54
64
 
65
+ def csv_params(*attributes)
66
+ options = importer_value(:csv_params)
67
+ params = attributes.first
68
+ options = options.merge(params) if params.is_a?(Hash)
69
+ importer_value(:csv_params, options)
70
+ end
71
+
55
72
  def each_record(&block)
56
73
  importer_value(:each_record, block)
57
74
  end
58
75
 
59
76
  private
60
- def import_from_csv(file, context=:default)
77
+ def import_from_csv(file, context = :default, custom_fields = :nil)
61
78
  records = []
62
- line = 0
63
- CSV.foreach(file.path, {:headers => false, :col_sep => ';', :force_quotes => true}) do |row|
64
- if line>0
65
- records << object_values(row, context) unless array_blank?(row)
79
+ first_line = nil
80
+ options = self.importers[context][:csv_params]
81
+ CSV.foreach(file.path, options.merge(headers: false)) do |row|
82
+ # Skip headers
83
+ if first_line.nil?
84
+ first_line = row
85
+ next
66
86
  end
67
- line+=1
87
+ records << object_values(row, context, custom_fields) unless array_blank?(row)
68
88
  end
69
89
  records
70
90
  end
71
91
 
72
- def import_from_xml(file, context=:default)
92
+ def import_from_xml(file, context = :default, custom_fields = :nil)
73
93
  records = []
74
94
  xml_structure = self.importers[context][:xml_structure]
75
95
  xml = Hash.from_xml(file.read)
@@ -77,59 +97,79 @@ module RailsImporter
77
97
  xml = xml[node.to_s]
78
98
  end
79
99
  xml.each do |elem|
80
- records << object_values(elem.values, context) unless array_blank?(elem.values)
100
+ records << object_values(elem.values, context, custom_fields) unless array_blank?(elem.values)
81
101
  end
82
102
  records
83
103
  end
84
104
 
85
- def import_from_xls(file, context=:default)
105
+ def import_from_xls(file, context = :default, custom_fields = :nil)
86
106
  records = []
87
107
  Spreadsheet.client_encoding = 'UTF-8'
88
108
  document = Spreadsheet.open(file.path)
89
109
  spreadsheet = document.worksheet 0
90
110
  spreadsheet.each_with_index do |row, i|
91
- next unless i>0
92
- records << object_values(row, context) unless array_blank?(row)
111
+ next if i.zero?
112
+ records << object_values(row, context, custom_fields) unless array_blank?(row)
93
113
  end
94
114
  records
95
115
  end
96
116
 
97
- def object_values(array, context=:default)
98
- attributes = self.importers[context][:fields]
117
+ def object_values(array, context = :default, custom_fields = nil)
118
+ attributes = custom_fields || self.importers[context][:fields]
99
119
  attributes = attributes.keys if attributes.is_a?(Hash)
100
- args = array[0...attributes.size]
101
- hValues = Hash[attributes.zip(args)]
120
+ values = equalize_columns_of_values(attributes, array)
121
+ hash_values = Hash[attributes.zip(values)]
102
122
  attributes.each do |attr|
103
- if hValues[attr].present?
104
- if hValues[attr].is_a?(Numeric)
105
- hValues[attr] = hValues[attr].to_i if hValues[attr].modulo(1).zero?
106
- hValues[attr] = (hValues[attr].to_s.strip rescue '#ERRO AO CONVERTER NUMERO PARA TEXTO')
107
- elsif hValues[attr].is_a?(Date)
108
- hValues[attr] = (I18n.l(hValues[attr], format: '%d/%m/%Y') rescue hValues[attr]).to_s
109
- elsif hValues[attr].is_a?(DateTime)
110
- hValues[attr] = (I18n.l(hValues[attr], format: '%d/%m/%Y %H:%i:%s') rescue hValues[attr]).to_s
123
+ if hash_values[attr].present?
124
+ if hash_values[attr].is_a?(Numeric)
125
+ hash_values[attr] = hash_values[attr].to_i if hash_values[attr].modulo(1).zero?
126
+ hash_values[attr] = (hash_values[attr].to_s.strip rescue I18n.t(:convert_number_to_text, scope: [:importer, :error]))
127
+ elsif hash_values[attr].is_a?(Date)
128
+ hash_values[attr] = (I18n.l(hash_values[attr], format: '%d/%m/%Y') rescue hash_values[attr]).to_s
129
+ elsif hash_values[attr].is_a?(DateTime)
130
+ hash_values[attr] = (I18n.l(hash_values[attr], format: '%d/%m/%Y %H:%i:%s') rescue hash_values[attr]).to_s
111
131
  else
112
132
  #PARA QUALQUER OUTRO VALOR, FORÇA CONVERTER PARA STRING
113
- hValues[attr] = (hValues[attr].to_s.strip rescue '')
133
+ hash_values[attr] = (hash_values[attr].to_s.strip rescue '')
114
134
  end
115
135
  else
116
- hValues[attr] = ''
136
+ hash_values[attr] = ''
117
137
  end
118
138
  end
119
- OpenStruct.new(hValues)
139
+ OpenStruct.new(hash_values)
120
140
  end
121
141
 
122
142
  def array_blank?(array)
123
- array.all? {|i|i.nil? or i==''}
143
+ array.all?(&:blank?)
144
+ end
145
+
146
+ def importer_value(key, attributes=nil)
147
+ return self.importers[@importer_name][key] if attributes.nil?
148
+ attributes = normalize_fields(attributes) if key == :fields
149
+ self.importers[@importer_name][key] = attributes
124
150
  end
125
151
 
126
- def importer_value(key, attributes)
127
- if attributes.present?
128
- self.importers[@importer_name][key] = (attributes.first.is_a?(Hash) ? attributes.inject(:merge) : attributes)
152
+ def normalize_fields(attributes)
153
+ if attributes.first.is_a?(Hash)
154
+ attributes.inject(:merge)
155
+ elsif attributes.first.is_a?(Array)
156
+ attributes.flatten
129
157
  else
130
- self.importers[@importer_name][key]
158
+ attributes
131
159
  end
132
160
  end
161
+
162
+ def equalize_columns_of_values(attributes, values=[])
163
+ if attributes.size > values.size
164
+ diff_size = (attributes.size - values.size).abs
165
+ values + Array.new(diff_size, nil)
166
+ elsif attributes.size < values.size
167
+ values[0...attributes.size]
168
+ else
169
+ values
170
+ end
171
+ end
172
+
133
173
  end
134
174
 
135
175
  end
@@ -1,3 +1,3 @@
1
1
  module RailsImporter
2
- VERSION = "0.0.7"
2
+ VERSION = "0.0.12"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-importer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruno Porto
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-14 00:00:00.000000000 Z
11
+ date: 2021-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3'
19
+ version: '4'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6'
22
+ version: '7'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '3'
29
+ version: '4'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6'
32
+ version: '7'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: spreadsheet
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +67,6 @@ files:
67
67
  - lib/generators/templates/generic_importer.erb
68
68
  - lib/rails-importer.rb
69
69
  - lib/rails_importer.rb
70
- - lib/rails_importer/_importer.rb
71
70
  - lib/rails_importer/base.rb
72
71
  - lib/rails_importer/engine.rb
73
72
  - lib/rails_importer/version.rb
@@ -75,7 +74,7 @@ homepage: https://github.com/brunoporto/rails-importer
75
74
  licenses:
76
75
  - MIT
77
76
  metadata: {}
78
- post_install_message:
77
+ post_install_message:
79
78
  rdoc_options: []
80
79
  require_paths:
81
80
  - lib
@@ -90,9 +89,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
89
  - !ruby/object:Gem::Version
91
90
  version: '0'
92
91
  requirements: []
93
- rubyforge_project:
94
- rubygems_version: 2.6.8
95
- signing_key:
92
+ rubygems_version: 3.2.15
93
+ signing_key:
96
94
  specification_version: 4
97
95
  summary: Rails Importer
98
96
  test_files: []
@@ -1,138 +0,0 @@
1
- require 'ostruct'
2
-
3
- module RailsImporter
4
-
5
- def self.included(base)
6
- base.extend ClassMethods
7
-
8
- base.define_singleton_method 'colunas' do |*args|
9
- @importacao_colunas = nil unless @importacao_colunas.present?
10
- if args.present?
11
- @importacao_colunas = (args.first.is_a?(Hash) ? args.inject(:merge) : args)
12
- else
13
- @importacao_colunas
14
- end
15
- end
16
-
17
- base.define_singleton_method 'estrutura_xml' do |*args|
18
- @importacao_estrutura_xml = nil unless @importacao_estrutura_xml.present?
19
- if args.present?
20
- @importacao_estrutura_xml = args
21
- else
22
- @importacao_estrutura_xml
23
- end
24
- end
25
-
26
- base.define_singleton_method 'para_cada_linha' do |&block|
27
- define_singleton_method('importar_registro') do |registro, *args|
28
- block.call(registro, *args)
29
- end
30
- end
31
-
32
- end
33
-
34
- def self.tipos_de_arquivos
35
- [:csv, :xls, :xml]
36
- end
37
-
38
- module ClassMethods
39
-
40
- def importacao(&block)
41
- block.call if block_given?
42
- self.class.class_eval do
43
- define_method :importar do |arquivo, *args|
44
- retorno = []
45
- begin
46
- ext = (File.extname(arquivo.path)[1..-1] rescue nil)
47
- if arquivo.respond_to?(:path) and RailsImporter.tipos_de_arquivos.include?(ext.to_sym)
48
- registros = self.send("#{ext}_para_array", arquivo)
49
- if registros.present? and registros.is_a?(Array)
50
- retorno = registros.map do |registro|
51
- importar_registro(registro, *args)
52
- end
53
- end
54
- else
55
- raise "Tipo de arquivo inválido. Arquivos permitidos: #{RailsImporter.tipos_de_arquivos.join(', ')}"
56
- end
57
- rescue Exception => e
58
- retorno = e.message
59
- end
60
- retorno
61
- end
62
- end
63
- end
64
-
65
- private
66
- def csv_para_array(arquivo)
67
- registros = []
68
- linha=0
69
- CSV.foreach(arquivo.path, {:headers => false, :col_sep => ';', :force_quotes => true}) do |row|
70
- if linha>0
71
- registros << object_values(row) unless array_blank?(row)
72
- end
73
- linha+=1
74
- end
75
- registros
76
- end
77
-
78
- def xml_para_array(arquivo)
79
- registros = []
80
- estrutura_xml = self.send(:estrutura_xml)
81
- if estrutura_xml.present? and estrutura_xml.is_a?(Array) and estrutura_xml.count > 0
82
- xml = Hash.from_xml(arquivo.read)
83
- estrutura_xml.each do |node|
84
- xml = xml[node.to_s]
85
- end
86
- xml.each do |elem|
87
- registros << object_values(elem.values) unless array_blank?(elem.values)
88
- end
89
- else
90
- raise 'Você precisa informar a estrutura_xml no seu Model'
91
- end
92
- registros
93
- end
94
-
95
- def xls_para_array(arquivo)
96
- registros = []
97
- Spreadsheet.client_encoding = 'UTF-8'
98
- documento = Spreadsheet.open(arquivo.path)
99
- planilha = documento.worksheet 0
100
- planilha.each_with_index do |row, i|
101
- next unless i>0
102
- registros << object_values(row) unless array_blank?(row)
103
- end
104
- registros
105
- end
106
-
107
- def object_values(array)
108
- atributos = self.send(:colunas)
109
- atributos = atributos.keys if atributos.is_a?(Hash)
110
- args = array[0...atributos.size]
111
- hValores = Hash[atributos.zip(args)]
112
- #Ajustando valores inválidos
113
- atributos.each do |atributo|
114
- if hValores[atributo].present?
115
- if hValores[atributo].is_a?(Numeric)
116
- hValores[atributo] = hValores[atributo].to_i if hValores[atributo].modulo(1).zero?
117
- hValores[atributo] = (hValores[atributo].to_s.strip rescue '#ERRO AO CONVERTER NUMERO PARA TEXTO')
118
- elsif hValores[atributo].is_a?(Date)
119
- hValores[atributo] = (I18n.l(hValores[atributo], format: '%d/%m/%Y') rescue hValores[atributo]).to_s
120
- elsif hValores[atributo].is_a?(DateTime)
121
- hValores[atributo] = (I18n.l(hValores[atributo], format: '%d/%m/%Y %H:%i:%s') rescue hValores[atributo]).to_s
122
- else
123
- #PARA QUALQUER OUTRO VALOR, FORÇA CONVERTER PARA STRING
124
- hValores[atributo] = (hValores[atributo].to_s.strip rescue '')
125
- end
126
- else
127
- hValores[atributo] = ''
128
- end
129
- end
130
- OpenStruct.new(hValores)
131
- end
132
-
133
- def array_blank?(array)
134
- array.all? {|i|i.nil? or i==''}
135
- end
136
-
137
- end
138
- end