datashift 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. data/README.markdown +63 -64
  2. data/Rakefile +4 -7
  3. data/VERSION +1 -1
  4. data/datashift.gemspec +92 -62
  5. data/lib/applications/apache_poi_extensions.rb +62 -0
  6. data/lib/applications/excel.rb +78 -0
  7. data/lib/applications/excel_base.rb +65 -0
  8. data/lib/applications/jexcel_file.rb +222 -0
  9. data/lib/applications/jexcel_file_extensions.rb +244 -0
  10. data/lib/applications/jruby/{jexcel_file.rb → old_pre_proxy_jexcel_file.rb} +0 -0
  11. data/lib/applications/ruby_poi_translations.rb +64 -0
  12. data/lib/applications/spreadsheet_extensions.rb +31 -0
  13. data/lib/datashift/method_details_manager.rb +4 -0
  14. data/lib/exporters/csv_exporter.rb +3 -1
  15. data/lib/exporters/excel_exporter.rb +59 -74
  16. data/lib/generators/excel_generator.rb +70 -74
  17. data/lib/guards.rb +57 -0
  18. data/lib/loaders/excel_loader.rb +105 -105
  19. data/lib/loaders/loader_base.rb +43 -21
  20. data/lib/loaders/paperclip/attachment_loader.rb +104 -0
  21. data/lib/loaders/paperclip/datashift_paperclip.rb +78 -0
  22. data/lib/loaders/paperclip/{image_loader.rb → image_loading.rb} +2 -18
  23. data/lib/thor/{generate_excel.thor → generate.thor} +48 -0
  24. data/lib/thor/paperclip.thor +85 -0
  25. data/lib/thor/tools.thor +23 -2
  26. data/spec/Gemfile +1 -7
  27. data/spec/csv_exporter_spec.rb +4 -4
  28. data/spec/csv_loader_spec.rb +1 -1
  29. data/spec/excel_exporter_spec.rb +43 -45
  30. data/spec/excel_generator_spec.rb +132 -60
  31. data/spec/excel_loader_spec.rb +134 -140
  32. data/spec/excel_spec.rb +179 -0
  33. data/spec/fixtures/ProjectsMultiCategoriesHeaderLookup.xls +0 -0
  34. data/spec/fixtures/config/database.yml +2 -2
  35. data/spec/fixtures/db/datashift_test_models_db.sqlite +0 -0
  36. data/spec/{db → fixtures/db}/migrate/20110803201325_create_test_bed.rb +0 -0
  37. data/spec/fixtures/load_datashift.thor +3 -0
  38. data/spec/fixtures/models/category.rb +7 -0
  39. data/spec/fixtures/models/empty.rb +2 -0
  40. data/spec/fixtures/models/loader_release.rb +10 -0
  41. data/spec/fixtures/models/long_and_complex_table_linked_to_version.rb +6 -0
  42. data/spec/fixtures/models/milestone.rb +8 -0
  43. data/spec/fixtures/models/owner.rb +5 -0
  44. data/spec/fixtures/models/project.rb +26 -0
  45. data/spec/fixtures/models/test_model_defs.rb +67 -0
  46. data/spec/fixtures/models/version.rb +7 -0
  47. data/spec/loader_spec.rb +4 -3
  48. data/spec/method_dictionary_spec.rb +7 -6
  49. data/spec/method_mapper_spec.rb +3 -2
  50. data/spec/rails_sandbox/.gitignore +15 -0
  51. data/spec/rails_sandbox/Gemfile +40 -0
  52. data/spec/rails_sandbox/README.rdoc +261 -0
  53. data/spec/rails_sandbox/Rakefile +7 -0
  54. data/spec/rails_sandbox/app/assets/images/rails.png +0 -0
  55. data/spec/rails_sandbox/app/assets/javascripts/application.js +15 -0
  56. data/spec/rails_sandbox/app/assets/stylesheets/application.css +13 -0
  57. data/spec/rails_sandbox/app/controllers/application_controller.rb +3 -0
  58. data/spec/rails_sandbox/app/helpers/application_helper.rb +2 -0
  59. data/spec/rails_sandbox/app/mailers/.gitkeep +0 -0
  60. data/spec/rails_sandbox/app/models/.gitkeep +0 -0
  61. data/spec/rails_sandbox/app/models/category.rb +7 -0
  62. data/spec/rails_sandbox/app/models/empty.rb +2 -0
  63. data/spec/rails_sandbox/app/models/loader_release.rb +10 -0
  64. data/spec/rails_sandbox/app/models/long_and_complex_table_linked_to_version.rb +6 -0
  65. data/spec/rails_sandbox/app/models/milestone.rb +8 -0
  66. data/spec/rails_sandbox/app/models/owner.rb +5 -0
  67. data/spec/rails_sandbox/app/models/project.rb +26 -0
  68. data/spec/rails_sandbox/app/models/test_model_defs.rb +67 -0
  69. data/spec/rails_sandbox/app/models/version.rb +7 -0
  70. data/spec/rails_sandbox/app/views/layouts/application.html.erb +14 -0
  71. data/spec/rails_sandbox/config.ru +4 -0
  72. data/spec/rails_sandbox/config/application.rb +62 -0
  73. data/spec/rails_sandbox/config/boot.rb +6 -0
  74. data/spec/rails_sandbox/config/database.yml +20 -0
  75. data/spec/rails_sandbox/config/environment.rb +5 -0
  76. data/spec/rails_sandbox/config/environments/development.rb +37 -0
  77. data/spec/rails_sandbox/config/environments/production.rb +67 -0
  78. data/spec/rails_sandbox/config/environments/test.rb +37 -0
  79. data/spec/rails_sandbox/config/initializers/backtrace_silencers.rb +7 -0
  80. data/spec/rails_sandbox/config/initializers/inflections.rb +15 -0
  81. data/spec/rails_sandbox/config/initializers/mime_types.rb +5 -0
  82. data/spec/rails_sandbox/config/initializers/secret_token.rb +7 -0
  83. data/spec/rails_sandbox/config/initializers/session_store.rb +8 -0
  84. data/spec/rails_sandbox/config/initializers/wrap_parameters.rb +14 -0
  85. data/spec/rails_sandbox/config/locales/en.yml +5 -0
  86. data/spec/rails_sandbox/config/routes.rb +58 -0
  87. data/spec/rails_sandbox/db/migrate/20110803201325_create_test_bed.rb +96 -0
  88. data/spec/rails_sandbox/db/schema.rb +81 -0
  89. data/spec/rails_sandbox/db/seeds.rb +7 -0
  90. data/spec/rails_sandbox/lib/assets/.gitkeep +0 -0
  91. data/spec/rails_sandbox/lib/tasks/.gitkeep +0 -0
  92. data/spec/rails_sandbox/log/.gitkeep +0 -0
  93. data/spec/rails_sandbox/public/404.html +26 -0
  94. data/spec/rails_sandbox/public/422.html +26 -0
  95. data/spec/rails_sandbox/public/500.html +25 -0
  96. data/spec/rails_sandbox/public/favicon.ico +0 -0
  97. data/spec/rails_sandbox/public/index.html +241 -0
  98. data/spec/rails_sandbox/public/robots.txt +5 -0
  99. data/spec/rails_sandbox/script/rails +6 -0
  100. data/spec/rails_sandbox/test/fixtures/.gitkeep +0 -0
  101. data/spec/rails_sandbox/test/functional/.gitkeep +0 -0
  102. data/spec/rails_sandbox/test/integration/.gitkeep +0 -0
  103. data/spec/rails_sandbox/test/performance/browsing_test.rb +12 -0
  104. data/spec/rails_sandbox/test/test_helper.rb +13 -0
  105. data/spec/rails_sandbox/test/unit/.gitkeep +0 -0
  106. data/spec/rails_sandbox/vendor/assets/javascripts/.gitkeep +0 -0
  107. data/spec/rails_sandbox/vendor/assets/stylesheets/.gitkeep +0 -0
  108. data/spec/rails_sandbox/vendor/plugins/.gitkeep +0 -0
  109. data/spec/spec_helper.rb +144 -121
  110. data/spec/thor_spec.rb +34 -14
  111. metadata +207 -194
  112. data/lib/helpers/spree_helper.rb +0 -213
  113. data/lib/loaders/spreadsheet_loader.rb +0 -144
  114. data/lib/loaders/spree/image_loader.rb +0 -90
  115. data/lib/loaders/spree/product_loader.rb +0 -354
  116. data/lib/thor/spree/bootstrap_cleanup.thor +0 -61
  117. data/lib/thor/spree/products_images.thor +0 -252
  118. data/lib/thor/spree/reports.thor +0 -56
  119. data/public/spree/products/large/DEMO_001_ror_bag.jpeg +0 -0
  120. data/public/spree/products/large/DEMO_002_Powerstation.jpg +0 -0
  121. data/public/spree/products/large/DEMO_003_ror_mug.jpeg +0 -0
  122. data/public/spree/products/mini/DEMO_001_ror_bag.jpeg +0 -0
  123. data/public/spree/products/mini/DEMO_002_Powerstation.jpg +0 -0
  124. data/public/spree/products/mini/DEMO_003_ror_mug.jpeg +0 -0
  125. data/public/spree/products/original/DEMO_001_ror_bag.jpeg +0 -0
  126. data/public/spree/products/original/DEMO_002_Powerstation.jpg +0 -0
  127. data/public/spree/products/original/DEMO_003_ror_mug.jpeg +0 -0
  128. data/public/spree/products/product/DEMO_001_ror_bag.jpeg +0 -0
  129. data/public/spree/products/product/DEMO_002_Powerstation.jpg +0 -0
  130. data/public/spree/products/product/DEMO_003_ror_mug.jpeg +0 -0
  131. data/public/spree/products/small/DEMO_001_ror_bag.jpeg +0 -0
  132. data/public/spree/products/small/DEMO_002_Powerstation.jpg +0 -0
  133. data/public/spree/products/small/DEMO_003_ror_mug.jpeg +0 -0
  134. data/spec/fixtures/datashift_Spree_db.sqlite +0 -0
  135. data/spec/fixtures/datashift_test_models_db.sqlite +0 -0
  136. data/spec/fixtures/negative/SpreeProdMiss1Mandatory.csv +0 -4
  137. data/spec/fixtures/negative/SpreeProdMiss1Mandatory.xls +0 -0
  138. data/spec/fixtures/negative/SpreeProdMissManyMandatory.csv +0 -4
  139. data/spec/fixtures/negative/SpreeProdMissManyMandatory.xls +0 -0
  140. data/spec/fixtures/spree/SpreeImages.xls +0 -0
  141. data/spec/fixtures/spree/SpreeMultiVariant.csv +0 -4
  142. data/spec/fixtures/spree/SpreeProducts.csv +0 -4
  143. data/spec/fixtures/spree/SpreeProducts.xls +0 -0
  144. data/spec/fixtures/spree/SpreeProductsDefaults.yml +0 -15
  145. data/spec/fixtures/spree/SpreeProductsMandatoryOnly.xls +0 -0
  146. data/spec/fixtures/spree/SpreeProductsMultiColumn.csv +0 -4
  147. data/spec/fixtures/spree/SpreeProductsMultiColumn.xls +0 -0
  148. data/spec/fixtures/spree/SpreeProductsSimple.csv +0 -4
  149. data/spec/fixtures/spree/SpreeProductsSimple.xls +0 -0
  150. data/spec/fixtures/spree/SpreeProductsWithImages.csv +0 -4
  151. data/spec/fixtures/spree/SpreeProductsWithImages.xls +0 -0
  152. data/spec/fixtures/spree/SpreeZoneExample.csv +0 -5
  153. data/spec/fixtures/spree/SpreeZoneExample.xls +0 -0
  154. data/spec/spree_exporter_spec.rb +0 -72
  155. data/spec/spree_generator_spec.rb +0 -96
  156. data/spec/spree_images_loader_spec.rb +0 -107
  157. data/spec/spree_loader_spec.rb +0 -375
  158. data/spec/spree_method_mapping_spec.rb +0 -226
  159. data/spec/spree_variants_loader_spec.rb +0 -189
  160. data/tasks/export/excel_generator.rake +0 -102
  161. data/tasks/import/excel.rake +0 -75
  162. data/test/helper.rb +0 -18
  163. 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
@@ -15,149 +15,149 @@ require 'datashift/exceptions'
15
15
 
16
16
  module DataShift
17
17
 
18
- if(Guards::jruby?)
18
+ require 'loaders/loader_base'
19
19
 
20
- require 'loaders/loader_base'
20
+ require 'excel'
21
21
 
22
- require 'java'
23
- require 'jexcel_file'
22
+ module ExcelLoading
24
23
 
25
- module ExcelLoading
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
- # Options:
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
- def perform_excel_load( file_name, options = {} )
36
-
37
- @excel = JExcelFile.new
38
-
39
- @excel.open(file_name)
37
+ @excel.open(file_name)
40
38
 
41
- #if(options[:verbose])
42
- puts "\n\n\nLoading from Excel file: #{file_name}"
39
+ #if(options[:verbose])
40
+ puts "\n\n\nLoading from Excel file: #{file_name}"
43
41
 
44
- sheet_number = options[:sheet_number] || 0
42
+ sheet_number = options[:sheet_number] || 0
45
43
 
46
- @sheet = @excel.sheet( sheet_number )
44
+
45
+ @sheet = @excel.worksheet( sheet_number )
47
46
 
48
- header_row_index = options[:header_row] || 0
49
- @header_row = @sheet.getRow(header_row_index)
47
+ header_row_index = options[:header_row] || 0
48
+ @header_row = @sheet.row(header_row_index)
50
49
 
51
- raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" unless(@header_row)
50
+ raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" unless(@header_row)
52
51
 
53
- @headers = []
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
- raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" if(@headers.empty?)
64
-
65
- # Create a method_mapper which maps list of headers into suitable calls on the Active Record class
66
- # For example if model has an attribute 'price' will map columns called Price, price, PRICE etc to this attribute
67
- map_headers_to_operators( @headers, options )
68
-
69
- logger.info "Excel Loader processing #{@excel.num_rows} rows"
70
- load_object_class.transaction do
71
- @loaded_objects = []
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
- (1..@excel.num_rows).collect do |row|
64
+ raise MissingHeadersError, "No headers found - Check Sheet #{@sheet} is complete and Row #{header_row_index} contains headers" if(@headers.empty?)
74
65
 
75
- # Excel num_rows seems to return all 'visible' rows, which appears to be greater than the actual data rows
76
- # (TODO - write spec to process .xls with a huge number of rows)
77
- #
78
- # This is rubbish but currently manually detect when actual data ends, this isn't very smart but
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
- contains_data = false
71
+ logger.info "Excel Loader processing #{@sheet.num_rows} rows"
72
+
73
+ loaded_objects.clear
83
74
 
84
- # First assign any default values for columns not included in parsed_file
85
- process_missing_columns_with_defaults
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
- # TODO - Smart sorting of column processing order ....
89
- # Does not currently ensure mandatory columns (for valid?) processed first but model needs saving
90
- # before associations can be processed so user should ensure mandatory columns are prior to associations
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
- # as part of this we also attempt to save early, for example before assigning to
93
- # has_and_belongs_to associations which require the load_object has an id for the join table
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
- # Iterate over the columns method_mapper found in Excel,
96
- # pulling data out of associated column
97
- @method_mapper.method_details.each_with_index do |method_detail, col|
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
- value = value_at(row, col)
104
+ value = row[col]
100
105
 
101
- contains_data = true unless(value.nil? || value.to_s.empty?)
106
+ contains_data = true unless(value.nil? || value.to_s.empty?)
102
107
 
103
- prepare_data(method_detail, value)
108
+ prepare_data(method_detail, value)
104
109
 
105
- process()
106
- end
110
+ process()
111
+ end
107
112
 
108
- break unless(contains_data == true)
109
-
110
- # TODO - requirements to handle not valid ?
111
- # all or nothing or carry on and dump out the exception list at end
112
- #puts "DEBUG: FINAL SAVE #{load_object.inspect}"
113
- unless(save)
114
- failure
115
- logger.error "Failed to save row [#{row}]"
116
- logger.error load_object.errors.inspect
117
- else
118
- logger.info "Row #{row} succesfully SAVED : ID #{load_object.id}"
119
- end
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
- # don't forget to reset the object or we'll update rather than create
122
- new_load_object
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
- def value_at(row, column)
133
- @excel.get_cell_value( @excel.sheet.getRow(row), column)
134
- end
140
+ def value_at(row, column)
141
+ @excel[row, column]
135
142
  end
143
+ end
136
144
 
137
145
 
138
- class ExcelLoader < LoaderBase
146
+ class ExcelLoader < LoaderBase
139
147
 
140
- include ExcelLoading
148
+ include ExcelLoading
141
149
 
142
- def initialize(klass, object = nil, options = {})
143
- super( klass, object, options )
144
- raise "Cannot load - failed to create a #{klass}" unless @load_object
145
- end
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
- puts "Excel loading stage complete - #{loaded_objects.size} rows added."
152
- end
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
@@ -28,8 +28,10 @@ module DataShift
28
28
 
29
29
  attr_accessor :loaded_objects, :failed_objects
30
30
 
31
- attr_accessor :options, :verbose
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
- @options = options.dup # clone can cause issues like 'can't modify frozen hash'
115
+ @config = options.dup # clone can cause issues like 'can't modify frozen hash'
114
116
 
115
- @verbose = @options[: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 for x
233
+ # Find a record for model klazz, looking up on field containing search_terms
231
234
  # Responds to global Options :
232
- # :case_sensitive : Default is a case insensitive lookup.
233
- # :use_like : Attempts a lookup using ike and x% ratehr than equality
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, x)
238
+ def get_record_by(klazz, field, search_terms, split_on = ' ', split_on_prefix = nil)
236
239
 
237
240
  begin
238
- if(@options[:case_sensitive])
239
- return klazz.send("find_by_#{field}", x)
240
- elsif(@options[:use_like])
241
- return klazz.where("#{field} like ?", "#{x}%").first
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
- return klazz.where("lower(#{field}) = ?", x.downcase).first
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 [#{x}] on #{klazz}.#{field}")
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
- @options.merge!(data['LoaderBase'])
336
+ @config.merge!(data['LoaderBase'])
315
337
  end
316
338
 
317
339
  if(data[self.class.name])
318
- @options.merge!(data[self.class.name])
340
+ @config.merge!(data[self.class.name])
319
341
  end
320
342
 
321
- logger.info("Loader Options : #{@options.inspect}")
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 @options['verboose_logging']
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) #{(lookups - found).inspect} NOT found - Not added."
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(@options[:strict])
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
- @options[:abort_on_failure] == 'true'
547
+ @config[:abort_on_failure] == 'true'
526
548
  end
527
549
 
528
550
  def loaded_count