datashift 0.11.1 → 0.12.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.
Files changed (110) hide show
  1. data/Rakefile +3 -2
  2. data/VERSION +1 -1
  3. data/datashift.gemspec +11 -174
  4. data/lib/datashift/column_packer.rb +64 -0
  5. data/lib/datashift/delimiters.rb +17 -1
  6. data/lib/datashift/exceptions.rb +7 -0
  7. data/lib/datashift/querying.rb +10 -4
  8. data/lib/loaders/csv_loader.rb +69 -32
  9. data/lib/loaders/excel_loader.rb +86 -53
  10. data/lib/loaders/loader_base.rb +32 -18
  11. data/lib/loaders/paperclip/attachment_loader.rb +11 -8
  12. data/lib/loaders/paperclip/datashift_paperclip.rb +21 -18
  13. data/lib/loaders/reporter.rb +48 -0
  14. data/spec/Gemfile.lock +129 -0
  15. data/spec/csv_exporter_spec.rb +1 -1
  16. metadata +121 -191
  17. data/.document +0 -5
  18. data/lib/java/poi-3.7/._poi-3.7-20101029.jar5645100390082102460.tmp +0 -0
  19. data/spec/MissingAttachmentRecords/DEMO_001_ror_bag.jpeg +0 -0
  20. data/spec/MissingAttachmentRecords/DEMO_002_Powerstation.jpeg +0 -0
  21. data/spec/MissingAttachmentRecords/DEMO_002_Powerstation.jpg +0 -0
  22. data/spec/MissingAttachmentRecords/DEMO_003_ror_mug.jpeg +0 -0
  23. data/spec/MissingAttachmentRecords/DEMO_004_ror_ringer.jpeg +0 -0
  24. data/spec/fixtures/BadAssociationName.xls +0 -0
  25. data/spec/fixtures/DemoNegativeTesting.xls +0 -0
  26. data/spec/fixtures/ProjectsDefaults.yml +0 -29
  27. data/spec/fixtures/ProjectsMultiCategories.xls +0 -0
  28. data/spec/fixtures/ProjectsMultiCategoriesHeaderLookup.xls +0 -0
  29. data/spec/fixtures/ProjectsSingleCategories.xls +0 -0
  30. data/spec/fixtures/SimpleProjects.xls +0 -0
  31. data/spec/fixtures/config/database.yml +0 -28
  32. data/spec/fixtures/db/datashift_test_models_db.sqlite +0 -0
  33. data/spec/fixtures/db/migrate/20110803201325_create_test_bed.rb +0 -96
  34. data/spec/fixtures/db/migrate/20121009161700_add_digitals.rb +0 -24
  35. data/spec/fixtures/images/DEMO_001_ror_bag.jpeg +0 -0
  36. data/spec/fixtures/images/DEMO_002_Powerstation.jpeg +0 -0
  37. data/spec/fixtures/images/DEMO_003_ror_mug.jpeg +0 -0
  38. data/spec/fixtures/images/DEMO_004_ror_ringer.jpeg +0 -0
  39. data/spec/fixtures/load_datashift.thor +0 -3
  40. data/spec/fixtures/models/category.rb +0 -7
  41. data/spec/fixtures/models/digital.rb +0 -14
  42. data/spec/fixtures/models/empty.rb +0 -2
  43. data/spec/fixtures/models/loader_release.rb +0 -10
  44. data/spec/fixtures/models/long_and_complex_table_linked_to_version.rb +0 -6
  45. data/spec/fixtures/models/milestone.rb +0 -8
  46. data/spec/fixtures/models/owner.rb +0 -7
  47. data/spec/fixtures/models/project.rb +0 -26
  48. data/spec/fixtures/models/version.rb +0 -7
  49. data/spec/fixtures/simple_export_spec.xls +0 -0
  50. data/spec/fixtures/simple_template_spec.xls +0 -0
  51. data/spec/fixtures/test_model_defs.rb +0 -9
  52. data/spec/rails_sandbox/.gitignore +0 -15
  53. data/spec/rails_sandbox/Gemfile +0 -40
  54. data/spec/rails_sandbox/README.rdoc +0 -261
  55. data/spec/rails_sandbox/Rakefile +0 -7
  56. data/spec/rails_sandbox/app/assets/images/rails.png +0 -0
  57. data/spec/rails_sandbox/app/assets/javascripts/application.js +0 -15
  58. data/spec/rails_sandbox/app/assets/stylesheets/application.css +0 -13
  59. data/spec/rails_sandbox/app/controllers/application_controller.rb +0 -3
  60. data/spec/rails_sandbox/app/helpers/application_helper.rb +0 -2
  61. data/spec/rails_sandbox/app/mailers/.gitkeep +0 -0
  62. data/spec/rails_sandbox/app/models/.gitkeep +0 -0
  63. data/spec/rails_sandbox/app/models/category.rb +0 -7
  64. data/spec/rails_sandbox/app/models/empty.rb +0 -2
  65. data/spec/rails_sandbox/app/models/loader_release.rb +0 -10
  66. data/spec/rails_sandbox/app/models/long_and_complex_table_linked_to_version.rb +0 -6
  67. data/spec/rails_sandbox/app/models/milestone.rb +0 -8
  68. data/spec/rails_sandbox/app/models/owner.rb +0 -5
  69. data/spec/rails_sandbox/app/models/project.rb +0 -26
  70. data/spec/rails_sandbox/app/models/test_model_defs.rb +0 -67
  71. data/spec/rails_sandbox/app/models/version.rb +0 -7
  72. data/spec/rails_sandbox/app/views/layouts/application.html.erb +0 -14
  73. data/spec/rails_sandbox/config.ru +0 -4
  74. data/spec/rails_sandbox/config/application.rb +0 -62
  75. data/spec/rails_sandbox/config/boot.rb +0 -6
  76. data/spec/rails_sandbox/config/database.yml +0 -20
  77. data/spec/rails_sandbox/config/environment.rb +0 -5
  78. data/spec/rails_sandbox/config/environments/development.rb +0 -37
  79. data/spec/rails_sandbox/config/environments/production.rb +0 -67
  80. data/spec/rails_sandbox/config/environments/test.rb +0 -37
  81. data/spec/rails_sandbox/config/initializers/backtrace_silencers.rb +0 -7
  82. data/spec/rails_sandbox/config/initializers/inflections.rb +0 -15
  83. data/spec/rails_sandbox/config/initializers/mime_types.rb +0 -5
  84. data/spec/rails_sandbox/config/initializers/secret_token.rb +0 -7
  85. data/spec/rails_sandbox/config/initializers/session_store.rb +0 -8
  86. data/spec/rails_sandbox/config/initializers/wrap_parameters.rb +0 -14
  87. data/spec/rails_sandbox/config/locales/en.yml +0 -5
  88. data/spec/rails_sandbox/config/routes.rb +0 -58
  89. data/spec/rails_sandbox/db/migrate/20110803201325_create_test_bed.rb +0 -96
  90. data/spec/rails_sandbox/db/schema.rb +0 -81
  91. data/spec/rails_sandbox/db/seeds.rb +0 -7
  92. data/spec/rails_sandbox/lib/assets/.gitkeep +0 -0
  93. data/spec/rails_sandbox/lib/tasks/.gitkeep +0 -0
  94. data/spec/rails_sandbox/log/.gitkeep +0 -0
  95. data/spec/rails_sandbox/public/404.html +0 -26
  96. data/spec/rails_sandbox/public/422.html +0 -26
  97. data/spec/rails_sandbox/public/500.html +0 -25
  98. data/spec/rails_sandbox/public/favicon.ico +0 -0
  99. data/spec/rails_sandbox/public/index.html +0 -241
  100. data/spec/rails_sandbox/public/robots.txt +0 -5
  101. data/spec/rails_sandbox/script/rails +0 -6
  102. data/spec/rails_sandbox/test/fixtures/.gitkeep +0 -0
  103. data/spec/rails_sandbox/test/functional/.gitkeep +0 -0
  104. data/spec/rails_sandbox/test/integration/.gitkeep +0 -0
  105. data/spec/rails_sandbox/test/performance/browsing_test.rb +0 -12
  106. data/spec/rails_sandbox/test/test_helper.rb +0 -13
  107. data/spec/rails_sandbox/test/unit/.gitkeep +0 -0
  108. data/spec/rails_sandbox/vendor/assets/javascripts/.gitkeep +0 -0
  109. data/spec/rails_sandbox/vendor/assets/stylesheets/.gitkeep +0 -0
  110. data/spec/rails_sandbox/vendor/plugins/.gitkeep +0 -0
@@ -22,6 +22,8 @@ module DataShift
22
22
  module ExcelLoading
23
23
 
24
24
  # Options:
25
+ # [:dummy] : Perform a dummy run - attempt to load everything but then roll back
26
+ #
25
27
  # [:sheet_number] : Default is 0. The index of the Excel Worksheet to use.
26
28
  # [:header_row] : Default is 0. Use alternative row as header definition.
27
29
  #
@@ -72,77 +74,108 @@ module DataShift
72
74
 
73
75
  logger.info "Excel Loader processing #{@sheet.num_rows} rows"
74
76
 
75
- loaded_objects.clear
76
-
77
- load_object_class.transaction do
77
+ @reporter.reset
78
+
79
+ begin
80
+ puts "Dummy Run - Changes will be rolled back" if options[:dummy]
81
+
82
+ load_object_class.transaction do
78
83
 
79
- @sheet.each_with_index do |row, i|
80
-
81
- next if(i == header_row_index)
84
+ @sheet.each_with_index do |row, i|
85
+
86
+ @current_row = row
87
+
88
+ next if(i == header_row_index)
82
89
 
83
- # Excel num_rows seems to return all 'visible' rows, which appears to be greater than the actual data rows
84
- # (TODO - write spec to process .xls with a huge number of rows)
85
- #
86
- # This is rubbish but currently manually detect when actual data ends, this isn't very smart but
87
- # got no better idea than ending once we hit the first completely empty row
88
- break if row.nil?
89
-
90
- contains_data = false
90
+ # Excel num_rows seems to return all 'visible' rows, which appears to be greater than the actual data rows
91
+ # (TODO - write spec to process .xls with a huge number of rows)
92
+ #
93
+ # This is rubbish but currently manually detect when actual data ends, this isn't very smart but
94
+ # got no better idea than ending once we hit the first completely empty row
95
+ break if @current_row.nil?
91
96
 
92
- # First assign any default values for columns not included in parsed_file
93
- process_missing_columns_with_defaults
97
+ logger.info "Processing Row #{i} : #{@current_row}"
98
+
99
+ contains_data = false
100
+
101
+ begin
102
+ # First assign any default values for columns not included in parsed_file
103
+ process_missing_columns_with_defaults
94
104
 
95
- # TODO - Smart sorting of column processing order ....
96
- # Does not currently ensure mandatory columns (for valid?) processed first but model needs saving
97
- # before associations can be processed so user should ensure mandatory columns are prior to associations
105
+ # TODO - Smart sorting of column processing order ....
106
+ # Does not currently ensure mandatory columns (for valid?) processed first but model needs saving
107
+ # before associations can be processed so user should ensure mandatory columns are prior to associations
98
108
 
99
- # as part of this we also attempt to save early, for example before assigning to
100
- # has_and_belongs_to associations which require the load_object has an id for the join table
109
+ # as part of this we also attempt to save early, for example before assigning to
110
+ # has_and_belongs_to associations which require the load_object has an id for the join table
101
111
 
102
- # Iterate over method_details, working on data out of associated Excel column
103
- @method_mapper.method_details.each do |method_detail|
104
-
105
- next unless method_detail # TODO populate unmapped with a real MethodDetail that is 'null' and create is_nil
112
+ # Iterate over method_details, working on data out of associated Excel column
113
+ @method_mapper.method_details.each do |method_detail|
114
+
115
+ next unless method_detail # TODO populate unmapped with a real MethodDetail that is 'null' and create is_nil
106
116
 
107
- value = row[method_detail.column_index]
117
+ logger.info "Processing Column #{method_detail.column_index}"
118
+
119
+ value = @current_row[method_detail.column_index]
108
120
 
109
- contains_data = true unless(value.nil? || value.to_s.empty?)
121
+ contains_data = true unless(value.nil? || value.to_s.empty?)
110
122
 
111
- prepare_data(method_detail, value)
123
+ prepare_data(method_detail, value)
112
124
 
113
- process()
114
- end
115
-
116
- break unless(contains_data == true)
117
-
118
- # TODO - requirements to handle not valid ?
119
- # all or nothing or carry on and dump out the exception list at end
120
- #puts "DEBUG: FINAL SAVE #{load_object.inspect}"
121
- unless(save)
122
- failure
123
- logger.error "Failed to save row [#{row}]"
124
- logger.error load_object.errors.inspect if(load_object)
125
- else
126
- logger.info "Row #{row} succesfully SAVED : ID #{load_object.id}"
127
- end
125
+ process()
126
+ end
127
+
128
+ rescue => e
129
+ @reporter.processed_object_count += 1
130
+
131
+ failure(@current_row, true)
132
+ logger.error "Failed to process row [#{i}] (#{@current_row})"
133
+ # don't forget to reset the load object
134
+ new_load_object
135
+ next
136
+ end
137
+
138
+ break unless(contains_data == true)
139
+
140
+ # currently here as we can only identify the end of a speadsheet by first empty row
141
+ @reporter.processed_object_count += 1
142
+
143
+ # TODO - make optional - all or nothing or carry on and dump out the exception list at end
128
144
 
129
- # don't forget to reset the object or we'll update rather than create
130
- new_load_object
145
+ unless(save)
146
+ failure
147
+ logger.error "Failed to save row [#{@current_row}]"
148
+ logger.error load_object.errors.inspect if(load_object)
149
+ else
150
+ logger.info "Row #{@current_row} succesfully SAVED : ID #{load_object.id}"
151
+ @reporter.add_loaded_object(@load_object)
152
+ end
153
+
154
+ # don't forget to reset the object or we'll update rather than create
155
+ new_load_object
131
156
 
157
+ end
158
+
159
+ raise ActiveRecord::Rollback if(options[:dummy]) # Don't actually create/upload to DB if we are doing dummy run
132
160
  end
133
- end
134
-
135
- loaded_objects.compact! if(loaded_objects)
136
161
 
137
- puts "Excel loading stage complete - #{loaded_objects.size} rows added."
138
- puts "There were NO failures." if failed_objects.empty?
162
+ rescue => e
139
163
 
140
- puts "WARNING : Check logs : #{failed_objects.size} rows contained errors and #{failed_objects.size} records NOT created." unless failed_objects.empty?
164
+ if e.is_a?(ActiveRecord::Rollback) && options[:dummy]
165
+ puts "Excel loading stage complete - Dummy run so Rolling Back."
166
+ else
167
+ raise e
168
+ end
169
+ ensure
170
+ report
171
+ end
172
+
141
173
  end
142
-
174
+
143
175
  def value_at(row, column)
144
176
  @excel[row, column]
145
177
  end
178
+
146
179
  end
147
180
 
148
181
 
@@ -159,7 +192,7 @@ module DataShift
159
192
  def perform_load( file_name, options = {} )
160
193
  perform_excel_load( file_name, options )
161
194
 
162
- puts "Excel loading stage complete - #{loaded_objects.size} rows added."
195
+ puts "Excel loading stage complete - #{loaded_count} rows added."
163
196
  end
164
197
 
165
198
  end
@@ -28,7 +28,7 @@ module DataShift
28
28
  attr_accessor :load_object_class, :load_object
29
29
  attr_accessor :current_value, :current_method_detail
30
30
 
31
- attr_accessor :loaded_objects, :failed_objects
31
+ attr_accessor :reporter
32
32
 
33
33
  attr_accessor :config, :verbose
34
34
 
@@ -51,7 +51,7 @@ module DataShift
51
51
 
52
52
  # Gather names of all possible 'setter' methods on AR class (instance variables and associations)
53
53
  if((find_operators && !MethodDictionary::for?(object_class)) || options[:reload])
54
- puts "Building Method Dictionary for class #{object_class}"
54
+ #puts "DEBUG Building Method Dictionary for class #{object_class}"
55
55
  DataShift::MethodDictionary.find_operators( @load_object_class, :reload => options[:reload], :instance_methods => options[:instance_methods] )
56
56
 
57
57
  # Create dictionary of data on all possible 'setter' methods which can be used to
@@ -73,9 +73,7 @@ module DataShift
73
73
  @prefixes = {}
74
74
  @postfixes = {}
75
75
 
76
- # TODO - move to own LoadStats or LoadReport class
77
- @loaded_objects = []
78
- @failed_objects = []
76
+ @reporter = DataShift::Reporter.new
79
77
 
80
78
  reset(object)
81
79
  end
@@ -88,6 +86,8 @@ module DataShift
88
86
  #
89
87
  # OPTIONS :
90
88
  #
89
+ # [:dummy] : Perform a dummy run - attempt to load everything but then roll back
90
+ #
91
91
  # strict : Raise an exception of any headers can't be mapped to an attribute/association
92
92
  # ignore : List of column headers to ignore when building operator map
93
93
  # mandatory : List of columns that must be present in headers
@@ -100,8 +100,12 @@ module DataShift
100
100
 
101
101
  raise DataShift::BadFile, "Cannot load #{file_name} file not found." unless(File.exists?(file_name))
102
102
 
103
+ logger.info("Perform Load Options:\n#{options.inspect}")
104
+
103
105
  ext = File.extname(file_name)
104
-
106
+
107
+ # TODO - make more modular - these methods doing too much, for example move the object creation/reset
108
+ # out of these perform... methods to make it easier to over ride that behaviour
105
109
  if(ext.casecmp('.xls') == 0)
106
110
  perform_excel_load(file_name, options)
107
111
  elsif(ext.casecmp('.csv') == 0)
@@ -111,7 +115,9 @@ module DataShift
111
115
  end
112
116
  end
113
117
 
114
-
118
+ def report
119
+ @reporter.report
120
+ end
115
121
 
116
122
  # Core API
117
123
  #
@@ -166,6 +172,7 @@ module DataShift
166
172
  def process_missing_columns_with_defaults()
167
173
  inbound_ops = @method_mapper.operator_names
168
174
  @default_values.each do |dn, dv|
175
+ logger.debug "Processing default value #{dn} : #{dv}"
169
176
  assignment(dn, @load_object, dv) unless(inbound_ops.include?(dn))
170
177
  end
171
178
  end
@@ -382,20 +389,27 @@ module DataShift
382
389
  end
383
390
  end
384
391
 
385
- def failure
386
- @failed_objects << @load_object unless( @load_object.nil? || @load_object.new_record? || @failed_objects.include?(@load_object))
392
+
393
+ # Loading failed. Store a failed object and if requested roll back (destroy) the current load object
394
+ # For use case where object saved early but subsequent required columns fail to process
395
+ # so the load object is invalid
396
+
397
+ def failure( object = @load_object, rollback = false)
398
+ if(object)
399
+ @reporter.add_failed_object(object)
400
+
401
+ @load_object.destroy if(rollback && ! @load_object.new_record?)
402
+
403
+ new_load_object # don't forget to reset the load object
404
+ end
387
405
  end
388
406
 
389
407
  def save
390
408
  return unless( @load_object )
391
409
 
392
- puts "DEBUG: SAVING #{@load_object.class} : #{@load_object.inspect}" if(@verbose)
410
+ #puts "DEBUG: SAVING #{@load_object.class} : #{@load_object.inspect}" if(@verbose)
393
411
  begin
394
- result = @load_object.save
395
-
396
- @loaded_objects << @load_object unless(@loaded_objects.include?(@load_object))
397
-
398
- return result
412
+ return @load_object.save
399
413
  rescue => e
400
414
  failure
401
415
  puts "Error saving #{@load_object.class} : #{e.inspect}"
@@ -447,7 +461,7 @@ module DataShift
447
461
  #
448
462
  def reset(object = nil)
449
463
  @load_object = object || new_load_object
450
- @loaded_objects, @failed_objects = [],[]
464
+ @reporter.reset
451
465
  @current_value = nil
452
466
  end
453
467
 
@@ -462,11 +476,11 @@ module DataShift
462
476
  end
463
477
 
464
478
  def loaded_count
465
- @loaded_objects.size
479
+ reporter.loaded_objects.size
466
480
  end
467
481
 
468
482
  def failed_count
469
- @failed_objects.size
483
+ reporter.failed_objects.size
470
484
  end
471
485
 
472
486
 
@@ -98,10 +98,14 @@ module DataShift
98
98
 
99
99
  # This version creates attachments and also attaches them to instances of :attach_to_klazz
100
100
  #
101
+ # Each file found in PATH will be processed - it's filename being used to scan for
102
+ # a matching record to attach the file to.
103
+ #
101
104
  # Options
102
105
  # :split_file_name_on Used in scan process to progresivly split filename to find
103
106
  # :attach_to_klass with matching :attach_to_find_by_field
104
107
  #
108
+ # :add_prefix
105
109
  #
106
110
  def process_from_filesystem(path, options = {} )
107
111
 
@@ -135,12 +139,11 @@ module DataShift
135
139
 
136
140
  record = nil
137
141
 
138
- puts "Attempting to find matching record where #{attach_to_find_by_field} ~= #{base_name}"
142
+ puts "Attempting fo find Record for file name : #{base_name}"
139
143
  record = get_record_by(attach_to_klass, attach_to_find_by_field, base_name, split_on, options)
140
144
 
141
145
  if(record)
142
- puts "Found record for attachment :\n#{record.inspect}"
143
- logger.info "Found record for attachment : #{record.inspect}"
146
+ puts "Found #{record.class} where : #{attach_to_find_by_field} = #{record.send(attach_to_find_by_field)}(id : #{record.id})"
144
147
  else
145
148
  missing_records << file_name
146
149
  end
@@ -162,15 +165,15 @@ module DataShift
162
165
  FileUtils.mkdir_p('MissingAttachmentRecords') unless File.directory?('MissingAttachmentRecords')
163
166
 
164
167
  puts "WARNING : #{missing_records.size} of #{loading_files_cache.size} files could not be attached to a #{@load_object_class}"
165
- puts "For your convenience files with MISSING #{attach_to_klass} have been copied to : MissingAttachmentRecords"
166
- missing_records.each do |i|
167
- puts "Copying #{i} to MissingAttachmentRecords folder" if(options[:verbose])
168
+ puts "For your convenience copying files with MISSING #{attach_to_klass} to : MissingAttachmentRecords"
169
+ missing_records.each do |i|
168
170
  FileUtils.cp( i, 'MissingAttachmentRecords') unless(options[:dummy] == 'true')
171
+ puts "Copyied #{i} to MissingAttachmentRecords folder" if(options[:verbose])
169
172
  end
170
- else
171
- puts "Created #{loading_files_cache.size} #{@load_object_class} attachments and succesfully attached to a #{@attach_to_klass}"
172
173
  end
173
174
 
175
+ puts "Created #{loading_files_cache.size - missing_records.size} of #{loading_files_cache.size} #{@load_object_class} attachments and succesfully attached to a #{@attach_to_klass}"
176
+
174
177
  puts "Dummy Run Complete- if happy run without -d" if(options[:dummy])
175
178
 
176
179
  end
@@ -13,7 +13,7 @@ module DataShift
13
13
  module Paperclip
14
14
 
15
15
  include DataShift::Logging
16
- include DataShift::Logging
16
+
17
17
  require 'paperclip/attachment_loader'
18
18
 
19
19
  attr_accessor :attachment
@@ -34,14 +34,14 @@ module DataShift
34
34
 
35
35
  unless File.exists?(attachment_path) && File.readable?(attachment_path)
36
36
  logger.error("Cannot process Image from #{Dir.pwd}: Invalid Path #{attachment_path}")
37
- raise "Cannot process Image : Invalid Path #{attachment_path}"
37
+ raise PathError.new("Cannot process Image : Invalid Path #{attachment_path}")
38
38
  end
39
39
 
40
40
  file = begin
41
41
  File.new(attachment_path, "rb")
42
42
  rescue => e
43
43
  puts e.inspect
44
- raise "ERROR : Failed to read image #{attachment_path}"
44
+ raise PathError.new("ERROR : Failed to read image from #{attachment_path}")
45
45
  end
46
46
 
47
47
  file
@@ -54,11 +54,13 @@ module DataShift
54
54
  #
55
55
  # :attributes
56
56
  #
57
- # Pass through hash of attributes to klass initializer
57
+ # Pass through a hash of attributes to the Paperclip klass's initializer
58
58
  #
59
59
  # :has_attached_file_name
60
60
  #
61
61
  # Paperclip attachment name defined with macro 'has_attached_file :name'
62
+ #
63
+ # This is usually called/defaults :attachment
62
64
  #
63
65
  # e.g
64
66
  # When : has_attached_file :avatar
@@ -73,19 +75,21 @@ module DataShift
73
75
 
74
76
  has_attached_file_attribute = options[:has_attached_file_name] ? options[:has_attached_file_name].to_sym : :attachment
75
77
 
76
- attributes = { has_attached_file_attribute => get_file(attachment_path) }
77
-
78
- attributes.merge!(options[:attributes]) if(options[:attributes])
78
+ # e.g (:attachment => File.read)
79
+ paperclip_attributes = { has_attached_file_attribute => get_file(attachment_path) }
80
+
81
+ paperclip_attributes.merge!(options[:attributes]) if(options[:attributes])
79
82
 
80
- # e.g (:viewable => some_product) = Icon
83
+ begin
84
+ @attachment = klass.new(paperclip_attributes, :without_protection => true)
85
+ rescue => e
86
+ puts e.inspect
87
+ logger.error("Failed to create PaperClip Attachment : #{e.inspect}")
88
+ raise CreateAttachmentFailed.new("Failed to create PaperClip Attachment from : #{attachment_path}")
89
+ end
81
90
 
82
- #attributes.merge!(attach_to_record_field.to_sym => record) if(record && attach_to_record_field)
83
-
84
- puts attributes.inspect
85
91
  begin
86
92
 
87
- @attachment = klass.new(attributes, :without_protection => true)
88
-
89
93
  if(@attachment.save)
90
94
  puts "Success: Created Attachment #{@attachment.id} : #{@attachment.attachment_file_name}"
91
95
 
@@ -103,12 +107,11 @@ module DataShift
103
107
 
104
108
  @attachment
105
109
  rescue => e
106
- puts "PaperClip error - Problem creating Attachment from : #{attachment_path}"
107
- puts e.inspect, e.backtrace
110
+ logger.error("Problem saving Paperclip Attachment: #{e.inspect}")
111
+ puts e.inspect
112
+ raise CreateAttachmentFailed.new("PaperClip error - Problem saving Attachment")
108
113
  end
109
- end
110
-
114
+ end
111
115
  end
112
116
 
113
-
114
117
  end
@@ -0,0 +1,48 @@
1
+ # Copyright:: (c) Autotelik Media Ltd 2011
2
+ # Author :: Tom Statter
3
+ # Date :: Dec 2012
4
+ # License:: MIT
5
+ #
6
+ # Details:: Store and report stats
7
+ #
8
+ module DataShift
9
+
10
+
11
+ class Reporter
12
+
13
+ include DataShift::Logging
14
+
15
+ attr_accessor :processed_object_count, :loaded_objects, :failed_objects
16
+
17
+
18
+ def initialize()
19
+ reset
20
+ end
21
+
22
+ def reset()
23
+ @processed_object_count = 0
24
+ @loaded_objects, @failed_objects = [], []
25
+ end
26
+
27
+ def add_loaded_object(object)
28
+ @loaded_objects << object unless(object.nil? || @loaded_objects.include?(object))
29
+ end
30
+
31
+ def add_failed_object(object)
32
+ @failed_objects << object unless( object.nil? || @failed_objects.include?(object))
33
+ end
34
+
35
+ def report
36
+ loaded_objects.compact! if(loaded_objects)
37
+
38
+ puts "Processing complete:"
39
+ puts "Processed total of #{processed_object_count} entries"
40
+ puts "#{loaded_objects.size} objects were succesfully processed."
41
+
42
+ puts "There were NO failures." if failed_objects.empty?
43
+
44
+ puts "WARNING : Check logs : #{failed_objects.size} rows contained errors and #{failed_objects.size} records NOT created." unless failed_objects.empty?
45
+ end
46
+
47
+ end
48
+ end