datashift 0.9.0 → 0.10.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/README.markdown +63 -64
- data/Rakefile +4 -7
- data/VERSION +1 -1
- data/datashift.gemspec +92 -62
- data/lib/applications/apache_poi_extensions.rb +62 -0
- data/lib/applications/excel.rb +78 -0
- data/lib/applications/excel_base.rb +65 -0
- data/lib/applications/jexcel_file.rb +222 -0
- data/lib/applications/jexcel_file_extensions.rb +244 -0
- data/lib/applications/jruby/{jexcel_file.rb → old_pre_proxy_jexcel_file.rb} +0 -0
- data/lib/applications/ruby_poi_translations.rb +64 -0
- data/lib/applications/spreadsheet_extensions.rb +31 -0
- data/lib/datashift/method_details_manager.rb +4 -0
- data/lib/exporters/csv_exporter.rb +3 -1
- data/lib/exporters/excel_exporter.rb +59 -74
- data/lib/generators/excel_generator.rb +70 -74
- data/lib/guards.rb +57 -0
- data/lib/loaders/excel_loader.rb +105 -105
- data/lib/loaders/loader_base.rb +43 -21
- data/lib/loaders/paperclip/attachment_loader.rb +104 -0
- data/lib/loaders/paperclip/datashift_paperclip.rb +78 -0
- data/lib/loaders/paperclip/{image_loader.rb → image_loading.rb} +2 -18
- data/lib/thor/{generate_excel.thor → generate.thor} +48 -0
- data/lib/thor/paperclip.thor +85 -0
- data/lib/thor/tools.thor +23 -2
- data/spec/Gemfile +1 -7
- data/spec/csv_exporter_spec.rb +4 -4
- data/spec/csv_loader_spec.rb +1 -1
- data/spec/excel_exporter_spec.rb +43 -45
- data/spec/excel_generator_spec.rb +132 -60
- data/spec/excel_loader_spec.rb +134 -140
- data/spec/excel_spec.rb +179 -0
- data/spec/fixtures/ProjectsMultiCategoriesHeaderLookup.xls +0 -0
- data/spec/fixtures/config/database.yml +2 -2
- data/spec/fixtures/db/datashift_test_models_db.sqlite +0 -0
- data/spec/{db → fixtures/db}/migrate/20110803201325_create_test_bed.rb +0 -0
- data/spec/fixtures/load_datashift.thor +3 -0
- data/spec/fixtures/models/category.rb +7 -0
- data/spec/fixtures/models/empty.rb +2 -0
- data/spec/fixtures/models/loader_release.rb +10 -0
- data/spec/fixtures/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/fixtures/models/milestone.rb +8 -0
- data/spec/fixtures/models/owner.rb +5 -0
- data/spec/fixtures/models/project.rb +26 -0
- data/spec/fixtures/models/test_model_defs.rb +67 -0
- data/spec/fixtures/models/version.rb +7 -0
- data/spec/loader_spec.rb +4 -3
- data/spec/method_dictionary_spec.rb +7 -6
- data/spec/method_mapper_spec.rb +3 -2
- data/spec/rails_sandbox/.gitignore +15 -0
- data/spec/rails_sandbox/Gemfile +40 -0
- data/spec/rails_sandbox/README.rdoc +261 -0
- data/spec/rails_sandbox/Rakefile +7 -0
- data/spec/rails_sandbox/app/assets/images/rails.png +0 -0
- data/spec/rails_sandbox/app/assets/javascripts/application.js +15 -0
- data/spec/rails_sandbox/app/assets/stylesheets/application.css +13 -0
- data/spec/rails_sandbox/app/controllers/application_controller.rb +3 -0
- data/spec/rails_sandbox/app/helpers/application_helper.rb +2 -0
- data/spec/rails_sandbox/app/mailers/.gitkeep +0 -0
- data/spec/rails_sandbox/app/models/.gitkeep +0 -0
- data/spec/rails_sandbox/app/models/category.rb +7 -0
- data/spec/rails_sandbox/app/models/empty.rb +2 -0
- data/spec/rails_sandbox/app/models/loader_release.rb +10 -0
- data/spec/rails_sandbox/app/models/long_and_complex_table_linked_to_version.rb +6 -0
- data/spec/rails_sandbox/app/models/milestone.rb +8 -0
- data/spec/rails_sandbox/app/models/owner.rb +5 -0
- data/spec/rails_sandbox/app/models/project.rb +26 -0
- data/spec/rails_sandbox/app/models/test_model_defs.rb +67 -0
- data/spec/rails_sandbox/app/models/version.rb +7 -0
- data/spec/rails_sandbox/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_sandbox/config.ru +4 -0
- data/spec/rails_sandbox/config/application.rb +62 -0
- data/spec/rails_sandbox/config/boot.rb +6 -0
- data/spec/rails_sandbox/config/database.yml +20 -0
- data/spec/rails_sandbox/config/environment.rb +5 -0
- data/spec/rails_sandbox/config/environments/development.rb +37 -0
- data/spec/rails_sandbox/config/environments/production.rb +67 -0
- data/spec/rails_sandbox/config/environments/test.rb +37 -0
- data/spec/rails_sandbox/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_sandbox/config/initializers/inflections.rb +15 -0
- data/spec/rails_sandbox/config/initializers/mime_types.rb +5 -0
- data/spec/rails_sandbox/config/initializers/secret_token.rb +7 -0
- data/spec/rails_sandbox/config/initializers/session_store.rb +8 -0
- data/spec/rails_sandbox/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_sandbox/config/locales/en.yml +5 -0
- data/spec/rails_sandbox/config/routes.rb +58 -0
- data/spec/rails_sandbox/db/migrate/20110803201325_create_test_bed.rb +96 -0
- data/spec/rails_sandbox/db/schema.rb +81 -0
- data/spec/rails_sandbox/db/seeds.rb +7 -0
- data/spec/rails_sandbox/lib/assets/.gitkeep +0 -0
- data/spec/rails_sandbox/lib/tasks/.gitkeep +0 -0
- data/spec/rails_sandbox/log/.gitkeep +0 -0
- data/spec/rails_sandbox/public/404.html +26 -0
- data/spec/rails_sandbox/public/422.html +26 -0
- data/spec/rails_sandbox/public/500.html +25 -0
- data/spec/rails_sandbox/public/favicon.ico +0 -0
- data/spec/rails_sandbox/public/index.html +241 -0
- data/spec/rails_sandbox/public/robots.txt +5 -0
- data/spec/rails_sandbox/script/rails +6 -0
- data/spec/rails_sandbox/test/fixtures/.gitkeep +0 -0
- data/spec/rails_sandbox/test/functional/.gitkeep +0 -0
- data/spec/rails_sandbox/test/integration/.gitkeep +0 -0
- data/spec/rails_sandbox/test/performance/browsing_test.rb +12 -0
- data/spec/rails_sandbox/test/test_helper.rb +13 -0
- data/spec/rails_sandbox/test/unit/.gitkeep +0 -0
- data/spec/rails_sandbox/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/rails_sandbox/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/rails_sandbox/vendor/plugins/.gitkeep +0 -0
- data/spec/spec_helper.rb +144 -121
- data/spec/thor_spec.rb +34 -14
- metadata +207 -194
- data/lib/helpers/spree_helper.rb +0 -213
- data/lib/loaders/spreadsheet_loader.rb +0 -144
- data/lib/loaders/spree/image_loader.rb +0 -90
- data/lib/loaders/spree/product_loader.rb +0 -354
- data/lib/thor/spree/bootstrap_cleanup.thor +0 -61
- data/lib/thor/spree/products_images.thor +0 -252
- data/lib/thor/spree/reports.thor +0 -56
- data/public/spree/products/large/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/large/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/large/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/mini/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/mini/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/mini/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/original/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/original/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/original/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/product/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/product/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/product/DEMO_003_ror_mug.jpeg +0 -0
- data/public/spree/products/small/DEMO_001_ror_bag.jpeg +0 -0
- data/public/spree/products/small/DEMO_002_Powerstation.jpg +0 -0
- data/public/spree/products/small/DEMO_003_ror_mug.jpeg +0 -0
- data/spec/fixtures/datashift_Spree_db.sqlite +0 -0
- data/spec/fixtures/datashift_test_models_db.sqlite +0 -0
- data/spec/fixtures/negative/SpreeProdMiss1Mandatory.csv +0 -4
- data/spec/fixtures/negative/SpreeProdMiss1Mandatory.xls +0 -0
- data/spec/fixtures/negative/SpreeProdMissManyMandatory.csv +0 -4
- data/spec/fixtures/negative/SpreeProdMissManyMandatory.xls +0 -0
- data/spec/fixtures/spree/SpreeImages.xls +0 -0
- data/spec/fixtures/spree/SpreeMultiVariant.csv +0 -4
- data/spec/fixtures/spree/SpreeProducts.csv +0 -4
- data/spec/fixtures/spree/SpreeProducts.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsDefaults.yml +0 -15
- data/spec/fixtures/spree/SpreeProductsMandatoryOnly.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsMultiColumn.csv +0 -4
- data/spec/fixtures/spree/SpreeProductsMultiColumn.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsSimple.csv +0 -4
- data/spec/fixtures/spree/SpreeProductsSimple.xls +0 -0
- data/spec/fixtures/spree/SpreeProductsWithImages.csv +0 -4
- data/spec/fixtures/spree/SpreeProductsWithImages.xls +0 -0
- data/spec/fixtures/spree/SpreeZoneExample.csv +0 -5
- data/spec/fixtures/spree/SpreeZoneExample.xls +0 -0
- data/spec/spree_exporter_spec.rb +0 -72
- data/spec/spree_generator_spec.rb +0 -96
- data/spec/spree_images_loader_spec.rb +0 -107
- data/spec/spree_loader_spec.rb +0 -375
- data/spec/spree_method_mapping_spec.rb +0 -226
- data/spec/spree_variants_loader_spec.rb +0 -189
- data/tasks/export/excel_generator.rake +0 -102
- data/tasks/import/excel.rake +0 -75
- data/test/helper.rb +0 -18
- data/test/test_interact.rb +0 -7
data/lib/guards.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Copyright:: (c) Autotelik Media Ltd 2010 - 2012 Tom Statter
|
|
2
|
+
# Author :: Tom Statter
|
|
3
|
+
# Date :: Aug 2010
|
|
4
|
+
# License:: Free, Open Source.
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
7
|
+
# a copy of this software and associated documentation files (the
|
|
8
|
+
# "Software"), to deal in the Software without restriction, including
|
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
12
|
+
# the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be
|
|
15
|
+
# included in all copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
21
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
22
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
23
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
24
|
+
#++
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# Details:: Active Record Loader
|
|
28
|
+
#
|
|
29
|
+
# To pull DataShift commands into your main application :
|
|
30
|
+
#
|
|
31
|
+
# require 'datashift'
|
|
32
|
+
#
|
|
33
|
+
# DataShift::load_commands
|
|
34
|
+
#
|
|
35
|
+
require 'rbconfig'
|
|
36
|
+
|
|
37
|
+
module DataShift
|
|
38
|
+
|
|
39
|
+
module Guards
|
|
40
|
+
|
|
41
|
+
def self.jruby?
|
|
42
|
+
return RUBY_PLATFORM == "java"
|
|
43
|
+
end
|
|
44
|
+
def self.mac?
|
|
45
|
+
RbConfig::CONFIG['target_os'] =~ /darwin/i
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.linux?
|
|
49
|
+
RbConfig::CONFIG['target_os'] =~ /linux/i
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.windows?
|
|
53
|
+
RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
end
|
data/lib/loaders/excel_loader.rb
CHANGED
|
@@ -15,149 +15,149 @@ require 'datashift/exceptions'
|
|
|
15
15
|
|
|
16
16
|
module DataShift
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
require 'loaders/loader_base'
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
require 'excel'
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
require 'jexcel_file'
|
|
22
|
+
module ExcelLoading
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
# Options:
|
|
25
|
+
# [:sheet_number] : Default is 0. The index of the Excel Worksheet to use.
|
|
26
|
+
# [:header_row] : Default is 0. Use alternative row as header definition.
|
|
27
|
+
# [:mandatory] : Array of mandatory column names
|
|
28
|
+
# [:force_inclusion] : Array of inbound column names to force into mapping
|
|
29
|
+
# [:strict] : Raise exception when no mapping found for a column heading (non mandatory)
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
# [:sheet_number] : Default is 0. The index of the Excel Worksheet to use.
|
|
29
|
-
# [:header_row] : Default is 0. Use alternative row as header definition.
|
|
30
|
-
# [:mandatory] : Array of mandatory column names
|
|
31
|
-
# [:force_inclusion] : Array of inbound column names to force into mapping
|
|
32
|
-
# [:strict] : Raise exception when no mapping found for a column heading (non mandatory)
|
|
31
|
+
def perform_excel_load( file_name, options = {} )
|
|
33
32
|
|
|
33
|
+
raise MissingHeadersError, "Minimum row for Headers is 0 - passed #{options[:header_row]}" if(options[:header_row] && options[:header_row].to_i < 0)
|
|
34
|
+
|
|
35
|
+
@excel = Excel.new
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
@excel = JExcelFile.new
|
|
38
|
-
|
|
39
|
-
@excel.open(file_name)
|
|
37
|
+
@excel.open(file_name)
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
#if(options[:verbose])
|
|
40
|
+
puts "\n\n\nLoading from Excel file: #{file_name}"
|
|
43
41
|
|
|
44
|
-
|
|
42
|
+
sheet_number = options[:sheet_number] || 0
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
|
|
45
|
+
@sheet = @excel.worksheet( sheet_number )
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
header_row_index = options[:header_row] || 0
|
|
48
|
+
@header_row = @sheet.row(header_row_index)
|
|
50
49
|
|
|
51
|
-
|
|
50
|
+
raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" unless(@header_row)
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
(0..JExcelFile::MAX_COLUMNS).each do |i|
|
|
56
|
-
cell = @header_row.getCell(i)
|
|
57
|
-
break unless cell
|
|
58
|
-
header = "#{@excel.cell_value(cell).to_s}".strip
|
|
59
|
-
break if header.empty?
|
|
60
|
-
@headers << header
|
|
61
|
-
end
|
|
52
|
+
@headers = []
|
|
62
53
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
54
|
+
# TODO - make more robust - currently end on first empty column
|
|
55
|
+
# There is no actual max columns in Excel .. you will run out of memory though at some point
|
|
56
|
+
(0..1024).each do |column|
|
|
57
|
+
cell = @header_row[column]
|
|
58
|
+
break unless cell
|
|
59
|
+
header = "#{cell.to_s}".strip
|
|
60
|
+
break if header.empty?
|
|
61
|
+
@headers << header
|
|
62
|
+
end
|
|
72
63
|
|
|
73
|
-
|
|
64
|
+
raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" if(@headers.empty?)
|
|
74
65
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
# got no better idea than ending once we hit the first completely empty row
|
|
80
|
-
break if @excel.sheet.getRow(row).nil?
|
|
66
|
+
|
|
67
|
+
# Create a method_mapper which maps list of headers into suitable calls on the Active Record class
|
|
68
|
+
# For example if model has an attribute 'price' will map columns called Price, price, PRICE etc to this attribute
|
|
69
|
+
map_headers_to_operators( @headers, options )
|
|
81
70
|
|
|
82
|
-
|
|
71
|
+
logger.info "Excel Loader processing #{@sheet.num_rows} rows"
|
|
72
|
+
|
|
73
|
+
loaded_objects.clear
|
|
83
74
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
75
|
+
load_object_class.transaction do
|
|
76
|
+
|
|
77
|
+
@sheet.each_with_index do |row, i|
|
|
78
|
+
|
|
79
|
+
next if(i == header_row_index)
|
|
80
|
+
|
|
81
|
+
# Excel num_rows seems to return all 'visible' rows, which appears to be greater than the actual data rows
|
|
82
|
+
# (TODO - write spec to process .xls with a huge number of rows)
|
|
83
|
+
#
|
|
84
|
+
# This is rubbish but currently manually detect when actual data ends, this isn't very smart but
|
|
85
|
+
# got no better idea than ending once we hit the first completely empty row
|
|
86
|
+
break if row.nil?
|
|
87
|
+
|
|
88
|
+
contains_data = false
|
|
89
|
+
|
|
90
|
+
# First assign any default values for columns not included in parsed_file
|
|
91
|
+
process_missing_columns_with_defaults
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
# TODO - Smart sorting of column processing order ....
|
|
94
|
+
# Does not currently ensure mandatory columns (for valid?) processed first but model needs saving
|
|
95
|
+
# before associations can be processed so user should ensure mandatory columns are prior to associations
|
|
91
96
|
|
|
92
|
-
|
|
93
|
-
|
|
97
|
+
# as part of this we also attempt to save early, for example before assigning to
|
|
98
|
+
# has_and_belongs_to associations which require the load_object has an id for the join table
|
|
94
99
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
# Iterate over the columns method_mapper found in Excel,
|
|
101
|
+
# pulling data out of associated column
|
|
102
|
+
@method_mapper.method_details.each_with_index do |method_detail, col|
|
|
98
103
|
|
|
99
|
-
|
|
104
|
+
value = row[col]
|
|
100
105
|
|
|
101
|
-
|
|
106
|
+
contains_data = true unless(value.nil? || value.to_s.empty?)
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
prepare_data(method_detail, value)
|
|
104
109
|
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
process()
|
|
111
|
+
end
|
|
107
112
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
113
|
+
break unless(contains_data == true)
|
|
114
|
+
|
|
115
|
+
# TODO - requirements to handle not valid ?
|
|
116
|
+
# all or nothing or carry on and dump out the exception list at end
|
|
117
|
+
#puts "DEBUG: FINAL SAVE #{load_object.inspect}"
|
|
118
|
+
unless(save)
|
|
119
|
+
failure
|
|
120
|
+
logger.error "Failed to save row [#{row}]"
|
|
121
|
+
logger.error load_object.errors.inspect
|
|
122
|
+
else
|
|
123
|
+
logger.info "Row #{row} succesfully SAVED : ID #{load_object.id}"
|
|
124
|
+
end
|
|
120
125
|
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
# don't forget to reset the object or we'll update rather than create
|
|
127
|
+
new_load_object
|
|
123
128
|
|
|
124
|
-
end
|
|
125
129
|
end
|
|
126
|
-
puts "Excel loading stage complete - #{loaded_objects.size} rows added."
|
|
127
|
-
puts "There were NO failures." if failed_objects.empty?
|
|
128
|
-
|
|
129
|
-
puts "WARNING : Check logs : #{failed_objects.size} rows contained errors and #{failed_objects.size} records NOT created." unless failed_objects.empty?
|
|
130
130
|
end
|
|
131
|
+
|
|
132
|
+
loaded_objects.compact! if(loaded_objects)
|
|
133
|
+
|
|
134
|
+
puts "Excel loading stage complete - #{loaded_objects.size} rows added."
|
|
135
|
+
puts "There were NO failures." if failed_objects.empty?
|
|
136
|
+
|
|
137
|
+
puts "WARNING : Check logs : #{failed_objects.size} rows contained errors and #{failed_objects.size} records NOT created." unless failed_objects.empty?
|
|
138
|
+
end
|
|
131
139
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
end
|
|
140
|
+
def value_at(row, column)
|
|
141
|
+
@excel[row, column]
|
|
135
142
|
end
|
|
143
|
+
end
|
|
136
144
|
|
|
137
145
|
|
|
138
|
-
|
|
146
|
+
class ExcelLoader < LoaderBase
|
|
139
147
|
|
|
140
|
-
|
|
148
|
+
include ExcelLoading
|
|
141
149
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
150
|
+
def initialize(klass, object = nil, options = {})
|
|
151
|
+
super( klass, object, options )
|
|
152
|
+
raise "Cannot load - failed to create a #{klass}" unless @load_object
|
|
153
|
+
end
|
|
147
154
|
|
|
148
|
-
def perform_load( file_name, options = {} )
|
|
149
|
-
perform_excel_load( file_name, options )
|
|
150
155
|
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
def perform_load( file_name, options = {} )
|
|
157
|
+
perform_excel_load( file_name, options )
|
|
153
158
|
|
|
159
|
+
puts "Excel loading stage complete - #{loaded_objects.size} rows added."
|
|
154
160
|
end
|
|
155
|
-
|
|
156
|
-
else
|
|
157
|
-
|
|
158
|
-
module ExcelLoading
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
+
|
|
161
162
|
end
|
|
162
|
-
|
|
163
163
|
end
|
data/lib/loaders/loader_base.rb
CHANGED
|
@@ -28,8 +28,10 @@ module DataShift
|
|
|
28
28
|
|
|
29
29
|
attr_accessor :loaded_objects, :failed_objects
|
|
30
30
|
|
|
31
|
-
attr_accessor :
|
|
31
|
+
attr_accessor :config, :verbose
|
|
32
32
|
|
|
33
|
+
def options() return @config; end
|
|
34
|
+
|
|
33
35
|
# Support multiple associations being added to a base object to be specified in a single column.
|
|
34
36
|
#
|
|
35
37
|
# Entry represents the association to find via supplied name, value to use in the lookup.
|
|
@@ -110,9 +112,9 @@ module DataShift
|
|
|
110
112
|
end unless(options[:load] == false)
|
|
111
113
|
|
|
112
114
|
@method_mapper = DataShift::MethodMapper.new
|
|
113
|
-
@
|
|
115
|
+
@config = options.dup # clone can cause issues like 'can't modify frozen hash'
|
|
114
116
|
|
|
115
|
-
@verbose = @
|
|
117
|
+
@verbose = @config[:verbose]
|
|
116
118
|
@headers = []
|
|
117
119
|
|
|
118
120
|
@default_data_objects ||= {}
|
|
@@ -123,6 +125,8 @@ module DataShift
|
|
|
123
125
|
@prefixes = {}
|
|
124
126
|
@postfixes = {}
|
|
125
127
|
|
|
128
|
+
@loaded_objects = []
|
|
129
|
+
|
|
126
130
|
reset(object)
|
|
127
131
|
end
|
|
128
132
|
|
|
@@ -149,7 +153,6 @@ module DataShift
|
|
|
149
153
|
ext = File.extname(file_name)
|
|
150
154
|
|
|
151
155
|
if(ext.casecmp('.xls') == 0)
|
|
152
|
-
raise DataShift::BadRuby, "Please install and use JRuby for loading .xls files" unless(Guards::jruby?)
|
|
153
156
|
perform_excel_load(file_name, options)
|
|
154
157
|
elsif(ext.casecmp('.csv') == 0)
|
|
155
158
|
perform_csv_load(file_name, options)
|
|
@@ -227,23 +230,42 @@ module DataShift
|
|
|
227
230
|
end
|
|
228
231
|
|
|
229
232
|
|
|
230
|
-
# Find a record for model klazz, looking up on field
|
|
233
|
+
# Find a record for model klazz, looking up on field containing search_terms
|
|
231
234
|
# Responds to global Options :
|
|
232
|
-
#
|
|
233
|
-
#
|
|
235
|
+
# :case_sensitive : Default is a case insensitive lookup.
|
|
236
|
+
# :use_like : Attempts a lookup using ike and x% ratehr than equality
|
|
234
237
|
|
|
235
|
-
def get_record_by(klazz, field,
|
|
238
|
+
def get_record_by(klazz, field, search_terms, split_on = ' ', split_on_prefix = nil)
|
|
236
239
|
|
|
237
240
|
begin
|
|
238
|
-
if(@
|
|
239
|
-
|
|
240
|
-
elsif(@
|
|
241
|
-
|
|
241
|
+
record = if(@config[:case_sensitive])
|
|
242
|
+
klazz.send("find_by_#{field}", search_terms)
|
|
243
|
+
elsif(@config[:use_like])
|
|
244
|
+
klazz.where("#{field} like ?", "#{search_terms}%").first
|
|
242
245
|
else
|
|
243
|
-
|
|
246
|
+
klazz.where("lower(#{field}) = ?", search_terms.downcase).first
|
|
244
247
|
end
|
|
248
|
+
|
|
249
|
+
# try the separate individual portions of the search_terms, front -> back
|
|
250
|
+
search_terms.split(split_on).each do |x|
|
|
251
|
+
z = "#{split_on_prefix}#{x}" if(split_on_prefix)
|
|
252
|
+
|
|
253
|
+
record = get_record_by(klazz, field, z, split_on, split_on_prefix)
|
|
254
|
+
break if record
|
|
255
|
+
end unless(record)
|
|
256
|
+
|
|
257
|
+
# this time try sequentially and incrementally scanning
|
|
258
|
+
search_terms.split(split_on).inject("") do |str, term|
|
|
259
|
+
z = (split_on_prefix) ? "#{split_on_prefix}#{str}#{term}": "#{str}#{term}"
|
|
260
|
+
record = get_record_by(klazz, field, z, split_on, split_on_prefix)
|
|
261
|
+
break if record
|
|
262
|
+
term
|
|
263
|
+
end unless(record)
|
|
264
|
+
|
|
265
|
+
return record
|
|
266
|
+
|
|
245
267
|
rescue => e
|
|
246
|
-
logger.error("Exception attempting to find a record for [#{
|
|
268
|
+
logger.error("Exception attempting to find a record for [#{search_terms}] on #{klazz}.#{field}")
|
|
247
269
|
logger.error e.backtrace
|
|
248
270
|
logger.error e.inspect
|
|
249
271
|
return nil
|
|
@@ -311,14 +333,14 @@ module DataShift
|
|
|
311
333
|
end
|
|
312
334
|
|
|
313
335
|
if(data['LoaderBase'])
|
|
314
|
-
@
|
|
336
|
+
@config.merge!(data['LoaderBase'])
|
|
315
337
|
end
|
|
316
338
|
|
|
317
339
|
if(data[self.class.name])
|
|
318
|
-
@
|
|
340
|
+
@config.merge!(data[self.class.name])
|
|
319
341
|
end
|
|
320
342
|
|
|
321
|
-
logger.info("Loader Options : #{@
|
|
343
|
+
logger.info("Loader Options : #{@config.inspect}")
|
|
322
344
|
end
|
|
323
345
|
|
|
324
346
|
# Set member variables to hold details and value.
|
|
@@ -380,7 +402,7 @@ module DataShift
|
|
|
380
402
|
#
|
|
381
403
|
def process()
|
|
382
404
|
|
|
383
|
-
logger.info("Current value to assign : #{@current_value}") #if @
|
|
405
|
+
logger.info("Current value to assign : #{@current_value}") #if @config['verboose_logging']
|
|
384
406
|
|
|
385
407
|
if(@current_method_detail.operator_for(:has_many))
|
|
386
408
|
|
|
@@ -420,7 +442,7 @@ module DataShift
|
|
|
420
442
|
unless(find_by_values.size == @current_value.size)
|
|
421
443
|
found = @current_value.collect {|f| f.send(find_operator) }
|
|
422
444
|
@load_object.errors.add( @current_method_detail.operator, "Association with key(s) #{(find_by_values - found).inspect} NOT found")
|
|
423
|
-
puts "WARNING: Association with key(s) #{(
|
|
445
|
+
puts "WARNING: Association #{@current_method_detail.operator} with key(s) #{(find_by_values - found).inspect} NOT found - Not added."
|
|
424
446
|
next if(@current_value.empty?)
|
|
425
447
|
end
|
|
426
448
|
|
|
@@ -464,7 +486,7 @@ module DataShift
|
|
|
464
486
|
failure
|
|
465
487
|
puts "Error saving #{@load_object.class} : #{e.inspect}"
|
|
466
488
|
logger.error e.backtrace
|
|
467
|
-
raise "Error in save whilst processing column #{@current_method_detail.name}" if(@
|
|
489
|
+
raise "Error in save whilst processing column #{@current_method_detail.name}" if(@config[:strict])
|
|
468
490
|
end
|
|
469
491
|
end
|
|
470
492
|
|
|
@@ -522,7 +544,7 @@ module DataShift
|
|
|
522
544
|
end
|
|
523
545
|
|
|
524
546
|
def abort_on_failure?
|
|
525
|
-
@
|
|
547
|
+
@config[:abort_on_failure] == 'true'
|
|
526
548
|
end
|
|
527
549
|
|
|
528
550
|
def loaded_count
|