datashift 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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