carrierwave 1.2.1 → 2.1.1

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.

Potentially problematic release.


This version of carrierwave might be problematic. Click here for more details.

@@ -3,14 +3,17 @@ module CarrierWave
3
3
  # this is an internal class, used by CarrierWave::Mount so that
4
4
  # we don't pollute the model with a lot of methods.
5
5
  class Mounter #:nodoc:
6
- attr_reader :column, :record, :remote_urls, :integrity_error,
7
- :processing_error, :download_error
6
+ attr_reader :column, :record, :remote_urls, :integrity_errors,
7
+ :processing_errors, :download_errors
8
8
  attr_accessor :remove, :remote_request_headers
9
9
 
10
10
  def initialize(record, column, options={})
11
11
  @record = record
12
12
  @column = column
13
13
  @options = record.class.uploader_options[column]
14
+ @download_errors = []
15
+ @processing_errors = []
16
+ @integrity_errors = []
14
17
  end
15
18
 
16
19
  def uploader_class
@@ -38,21 +41,30 @@ module CarrierWave
38
41
  end
39
42
 
40
43
  def cache(new_files)
41
- return if not new_files or new_files == ""
44
+ return if !new_files.is_a?(Array) && new_files.blank?
45
+ old_uploaders = uploaders
42
46
  @uploaders = new_files.map do |new_file|
43
- uploader = blank_uploader
44
- uploader.cache!(new_file)
45
- uploader
46
- end
47
-
48
- @integrity_error = nil
49
- @processing_error = nil
50
- rescue CarrierWave::IntegrityError => e
51
- @integrity_error = e
52
- raise e unless option(:ignore_integrity_errors)
53
- rescue CarrierWave::ProcessingError => e
54
- @processing_error = e
55
- raise e unless option(:ignore_processing_errors)
47
+ handle_error do
48
+ if new_file.is_a?(String)
49
+ if (uploader = old_uploaders.detect { |uploader| uploader.identifier == new_file })
50
+ uploader.staged = true
51
+ uploader
52
+ else
53
+ begin
54
+ uploader = blank_uploader
55
+ uploader.retrieve_from_cache!(new_file)
56
+ uploader
57
+ rescue CarrierWave::InvalidParameter
58
+ nil
59
+ end
60
+ end
61
+ else
62
+ uploader = blank_uploader
63
+ uploader.cache!(new_file)
64
+ uploader
65
+ end
66
+ end
67
+ end.compact
56
68
  end
57
69
 
58
70
  def cache_names
@@ -60,45 +72,37 @@ module CarrierWave
60
72
  end
61
73
 
62
74
  def cache_names=(cache_names)
63
- return if not cache_names or cache_names == "" or uploaders.any?(&:cached?)
64
- @uploaders = cache_names.map do |cache_name|
65
- uploader = blank_uploader
66
- uploader.retrieve_from_cache!(cache_name)
67
- uploader
75
+ cache_names = cache_names.reject(&:blank?)
76
+ return if cache_names.blank?
77
+ clear_unstaged
78
+ cache_names.each do |cache_name|
79
+ begin
80
+ uploader = blank_uploader
81
+ uploader.retrieve_from_cache!(cache_name)
82
+ @uploaders << uploader
83
+ rescue CarrierWave::InvalidParameter
84
+ # ignore
85
+ end
68
86
  end
69
- rescue CarrierWave::InvalidParameter
70
87
  end
71
88
 
72
89
  def remote_urls=(urls)
73
- return if not urls or urls == "" or urls.all?(&:blank?)
90
+ return if urls.blank? || urls.all?(&:blank?)
74
91
 
75
92
  @remote_urls = urls
76
- @download_error = nil
77
- @integrity_error = nil
78
93
 
79
- @uploaders = urls.zip(remote_request_headers || []).map do |url, header|
80
- uploader = blank_uploader
81
- uploader.download!(url, header || {})
82
- uploader
94
+ clear_unstaged
95
+ urls.zip(remote_request_headers || []).each do |url, header|
96
+ handle_error do
97
+ uploader = blank_uploader
98
+ uploader.download!(url, header || {})
99
+ @uploaders << uploader
100
+ end
83
101
  end
84
-
85
- rescue CarrierWave::DownloadError => e
86
- @download_error = e
87
- raise e unless option(:ignore_download_errors)
88
- rescue CarrierWave::ProcessingError => e
89
- @processing_error = e
90
- raise e unless option(:ignore_processing_errors)
91
- rescue CarrierWave::IntegrityError => e
92
- @integrity_error = e
93
- raise e unless option(:ignore_integrity_errors)
94
102
  end
95
103
 
96
104
  def store!
97
- if remove?
98
- remove!
99
- else
100
- uploaders.reject(&:blank?).each(&:store!)
101
- end
105
+ uploaders.reject(&:blank?).each(&:store!)
102
106
  end
103
107
 
104
108
  def urls(*args)
@@ -110,7 +114,7 @@ module CarrierWave
110
114
  end
111
115
 
112
116
  def remove?
113
- remove.present? && remove !~ /\A0|false$\z/
117
+ remove.present? && (remove == true || remove !~ /\A0|false$\z/)
114
118
  end
115
119
 
116
120
  def remove!
@@ -118,6 +122,10 @@ module CarrierWave
118
122
  @uploaders = []
119
123
  end
120
124
 
125
+ def clear!
126
+ @uploaders = []
127
+ end
128
+
121
129
  def serialization_column
122
130
  option(:mount_on) || column
123
131
  end
@@ -146,9 +154,7 @@ module CarrierWave
146
154
  end.path
147
155
  end
148
156
  before.each do |uploader|
149
- if uploader.remove_previously_stored_files_after_update and not after_paths.include?(uploader.path)
150
- uploader.remove!
151
- end
157
+ uploader.remove! if uploader.remove_previously_stored_files_after_update && !after_paths.include?(uploader.path)
152
158
  end
153
159
  end
154
160
 
@@ -161,5 +167,22 @@ module CarrierWave
161
167
  self.uploader_options[name] ||= record.class.uploader_option(column, name)
162
168
  end
163
169
 
170
+ def clear_unstaged
171
+ @uploaders ||= []
172
+ @uploaders.keep_if(&:staged)
173
+ end
174
+
175
+ def handle_error
176
+ yield
177
+ rescue CarrierWave::DownloadError => e
178
+ @download_errors << e
179
+ raise e unless option(:ignore_download_errors)
180
+ rescue CarrierWave::ProcessingError => e
181
+ @processing_errors << e
182
+ raise e unless option(:ignore_processing_errors)
183
+ rescue CarrierWave::IntegrityError => e
184
+ @integrity_errors << e
185
+ raise e unless option(:ignore_integrity_errors)
186
+ end
164
187
  end # Mounter
165
188
  end # CarrierWave
@@ -12,7 +12,9 @@ module CarrierWave
12
12
  def mount_uploader(column, uploader=nil, options={}, &block)
13
13
  super
14
14
 
15
- class_eval <<-RUBY, __FILE__, __LINE__+1
15
+ mod = Module.new
16
+ prepend mod
17
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
16
18
  def remote_#{column}_url=(url)
17
19
  column = _mounter(:#{column}).serialization_column
18
20
  __send__(:"\#{column}_will_change!")
@@ -27,7 +29,9 @@ module CarrierWave
27
29
  def mount_uploaders(column, uploader=nil, options={}, &block)
28
30
  super
29
31
 
30
- class_eval <<-RUBY, __FILE__, __LINE__+1
32
+ mod = Module.new
33
+ prepend mod
34
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
31
35
  def remote_#{column}_urls=(url)
32
36
  column = _mounter(:#{column}).serialization_column
33
37
  __send__(:"\#{column}_will_change!")
@@ -52,15 +56,16 @@ module CarrierWave
52
56
  validates_processing_of column if uploader_option(column.to_sym, :validate_processing)
53
57
  validates_download_of column if uploader_option(column.to_sym, :validate_download)
54
58
 
55
- after_save :"store_#{column}!"
56
59
  before_save :"write_#{column}_identifier"
60
+ after_save :"store_previous_changes_for_#{column}"
57
61
  after_commit :"remove_#{column}!", :on => :destroy
58
62
  after_commit :"mark_remove_#{column}_false", :on => :update
59
-
60
- after_save :"store_previous_changes_for_#{column}"
61
63
  after_commit :"remove_previously_stored_#{column}", :on => :update
64
+ after_commit :"store_#{column}!", :on => [:create, :update]
62
65
 
63
- class_eval <<-RUBY, __FILE__, __LINE__+1
66
+ mod = Module.new
67
+ prepend mod
68
+ mod.class_eval <<-RUBY, __FILE__, __LINE__+1
64
69
  def #{column}=(new_file)
65
70
  column = _mounter(:#{column}).serialization_column
66
71
  if !(new_file.blank? && __send__(:#{column}).blank?)
@@ -72,8 +77,9 @@ module CarrierWave
72
77
 
73
78
  def remove_#{column}=(value)
74
79
  column = _mounter(:#{column}).serialization_column
75
- __send__(:"\#{column}_will_change!")
76
- super
80
+ result = super
81
+ __send__(:"\#{column}_will_change!") if _mounter(:#{column}).remove?
82
+ result
77
83
  end
78
84
 
79
85
  def remove_#{column}!
@@ -21,9 +21,11 @@ module CarrierWave
21
21
  # process :resize_to_fit => [200, 200]
22
22
  # end
23
23
  #
24
- # Or create your own helpers with the powerful manipulate! method. Check
25
- # out the ImageMagick docs at http://www.imagemagick.org/script/command-line-options.php for more
26
- # info
24
+ # Or create your own helpers with the powerful minimagick! method, which
25
+ # yields an ImageProcessing::Builder object. Check out the ImageProcessing
26
+ # docs at http://github.com/janko-m/image_processing and the list of all
27
+ # available ImageMagick options at
28
+ # http://www.imagemagick.org/script/command-line-options.php for more info.
27
29
  #
28
30
  # class MyUploader < CarrierWave::Uploader::Base
29
31
  # include CarrierWave::MiniMagick
@@ -31,23 +33,22 @@ module CarrierWave
31
33
  # process :radial_blur => 10
32
34
  #
33
35
  # def radial_blur(amount)
34
- # manipulate! do |img|
35
- # img.radial_blur(amount)
36
- # img = yield(img) if block_given?
37
- # img
36
+ # minimagick! do |builder|
37
+ # builder.radial_blur(amount)
38
+ # builder = yield(builder) if block_given?
39
+ # builder
38
40
  # end
39
41
  # end
40
42
  # end
41
43
  #
42
44
  # === Note
43
45
  #
44
- # MiniMagick is a mini replacement for RMagick that uses the command line
45
- # tool "mogrify" for image manipulation.
46
+ # The ImageProcessing gem uses MiniMagick, a mini replacement for RMagick
47
+ # that uses ImageMagick command-line tools, to build a "convert" command that
48
+ # performs the processing.
46
49
  #
47
50
  # You can find more information here:
48
51
  #
49
- # http://mini_magick.rubyforge.org/
50
- # and
51
52
  # https://github.com/minimagick/minimagick/
52
53
  #
53
54
  #
@@ -55,12 +56,7 @@ module CarrierWave
55
56
  extend ActiveSupport::Concern
56
57
 
57
58
  included do
58
- begin
59
- require "mini_magick"
60
- rescue LoadError => e
61
- e.message << " (You may need to install the mini_magick gem)"
62
- raise e
63
- end
59
+ require "image_processing/mini_magick"
64
60
  end
65
61
 
66
62
  module ClassMethods
@@ -102,12 +98,11 @@ module CarrierWave
102
98
  #
103
99
  # image.convert(:png)
104
100
  #
105
- def convert(format, page=nil)
106
- @format = format
107
- @page = page
108
- manipulate! do |img|
109
- img = yield(img) if block_given?
110
- img
101
+ def convert(format, page=nil, &block)
102
+ minimagick!(block) do |builder|
103
+ builder = builder.convert(format)
104
+ builder = builder.loader(page: page) if page
105
+ builder
111
106
  end
112
107
  end
113
108
 
@@ -121,21 +116,18 @@ module CarrierWave
121
116
  #
122
117
  # [width (Integer)] the width to scale the image to
123
118
  # [height (Integer)] the height to scale the image to
119
+ # [combine_options (Hash)] additional ImageMagick options to apply before resizing
124
120
  #
125
121
  # === Yields
126
122
  #
127
123
  # [MiniMagick::Image] additional manipulations to perform
128
124
  #
129
- def resize_to_limit(width, height, combine_options: {})
130
- width = dimension_from width
131
- height = dimension_from height
132
- manipulate! do |img|
133
- img.combine_options do |cmd|
134
- cmd.resize "#{width}x#{height}>"
135
- append_combine_options cmd, combine_options
136
- end
137
- img = yield(img) if block_given?
138
- img
125
+ def resize_to_limit(width, height, combine_options: {}, &block)
126
+ width, height = resolve_dimensions(width, height)
127
+
128
+ minimagick!(block) do |builder|
129
+ builder.resize_to_limit(width, height)
130
+ .apply(combine_options)
139
131
  end
140
132
  end
141
133
 
@@ -148,21 +140,18 @@ module CarrierWave
148
140
  #
149
141
  # [width (Integer)] the width to scale the image to
150
142
  # [height (Integer)] the height to scale the image to
143
+ # [combine_options (Hash)] additional ImageMagick options to apply before resizing
151
144
  #
152
145
  # === Yields
153
146
  #
154
147
  # [MiniMagick::Image] additional manipulations to perform
155
148
  #
156
- def resize_to_fit(width, height, combine_options: {})
157
- width = dimension_from width
158
- height = dimension_from height
159
- manipulate! do |img|
160
- img.combine_options do |cmd|
161
- cmd.resize "#{width}x#{height}"
162
- append_combine_options cmd, combine_options
163
- end
164
- img = yield(img) if block_given?
165
- img
149
+ def resize_to_fit(width, height, combine_options: {}, &block)
150
+ width, height = resolve_dimensions(width, height)
151
+
152
+ minimagick!(block) do |builder|
153
+ builder.resize_to_fit(width, height)
154
+ .apply(combine_options)
166
155
  end
167
156
  end
168
157
 
@@ -176,37 +165,18 @@ module CarrierWave
176
165
  # [width (Integer)] the width to scale the image to
177
166
  # [height (Integer)] the height to scale the image to
178
167
  # [gravity (String)] the current gravity suggestion (default: 'Center'; options: 'NorthWest', 'North', 'NorthEast', 'West', 'Center', 'East', 'SouthWest', 'South', 'SouthEast')
168
+ # [combine_options (Hash)] additional ImageMagick options to apply before resizing
179
169
  #
180
170
  # === Yields
181
171
  #
182
172
  # [MiniMagick::Image] additional manipulations to perform
183
173
  #
184
- def resize_to_fill(width, height, gravity = 'Center', combine_options: {})
185
- width = dimension_from width
186
- height = dimension_from height
187
- manipulate! do |img|
188
- cols, rows = img[:dimensions]
189
- img.combine_options do |cmd|
190
- if width != cols || height != rows
191
- scale_x = width/cols.to_f
192
- scale_y = height/rows.to_f
193
- if scale_x >= scale_y
194
- cols = (scale_x * (cols + 0.5)).round
195
- rows = (scale_x * (rows + 0.5)).round
196
- cmd.resize "#{cols}"
197
- else
198
- cols = (scale_y * (cols + 0.5)).round
199
- rows = (scale_y * (rows + 0.5)).round
200
- cmd.resize "x#{rows}"
201
- end
202
- end
203
- cmd.gravity gravity
204
- cmd.background "rgba(255,255,255,0.0)"
205
- cmd.extent "#{width}x#{height}" if cols != width || rows != height
206
- append_combine_options cmd, combine_options
207
- end
208
- img = yield(img) if block_given?
209
- img
174
+ def resize_to_fill(width, height, gravity = 'Center', combine_options: {}, &block)
175
+ width, height = resolve_dimensions(width, height)
176
+
177
+ minimagick!(block) do |builder|
178
+ builder.resize_to_fill(width, height, gravity: gravity)
179
+ .apply(combine_options)
210
180
  end
211
181
  end
212
182
 
@@ -225,28 +195,18 @@ module CarrierWave
225
195
  # [height (Integer)] the height to scale the image to
226
196
  # [background (String, :transparent)] the color of the background as a hexcode, like "#ff45de"
227
197
  # [gravity (String)] how to position the image
198
+ # [combine_options (Hash)] additional ImageMagick options to apply before resizing
228
199
  #
229
200
  # === Yields
230
201
  #
231
202
  # [MiniMagick::Image] additional manipulations to perform
232
203
  #
233
- def resize_and_pad(width, height, background=:transparent, gravity='Center', combine_options: {})
234
- width = dimension_from width
235
- height = dimension_from height
236
- manipulate! do |img|
237
- img.combine_options do |cmd|
238
- cmd.thumbnail "#{width}x#{height}>"
239
- if background == :transparent
240
- cmd.background "rgba(255, 255, 255, 0.0)"
241
- else
242
- cmd.background background
243
- end
244
- cmd.gravity gravity
245
- cmd.extent "#{width}x#{height}"
246
- append_combine_options cmd, combine_options
247
- end
248
- img = yield(img) if block_given?
249
- img
204
+ def resize_and_pad(width, height, background=:transparent, gravity='Center', combine_options: {}, &block)
205
+ width, height = resolve_dimensions(width, height)
206
+
207
+ minimagick!(block) do |builder|
208
+ builder.resize_and_pad(width, height, background: background, gravity: gravity)
209
+ .apply(combine_options)
250
210
  end
251
211
  end
252
212
 
@@ -277,6 +237,9 @@ module CarrierWave
277
237
  # and then pass each of its frames to the supplied block. It will then
278
238
  # save the image to disk.
279
239
  #
240
+ # NOTE: This method exists mostly for backwards compatibility, you should
241
+ # probably use #minimagick!.
242
+ #
280
243
  # === Gotcha
281
244
  #
282
245
  # This method assumes that the object responds to +current_path+.
@@ -296,19 +259,55 @@ module CarrierWave
296
259
  cache_stored_file! if !cached?
297
260
  image = ::MiniMagick::Image.open(current_path)
298
261
 
299
- begin
300
- image.format(@format.to_s.downcase, @page) if @format
301
- image = yield(image)
302
- image.write(current_path)
262
+ image = yield(image)
263
+ FileUtils.mv image.path, current_path
303
264
 
304
- if @format
305
- move_to = current_path.chomp(File.extname(current_path)) + ".#{@format}"
306
- file.move_to(move_to, permissions, directory_permissions)
307
- end
265
+ image.run_command("identify", current_path)
266
+ rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
267
+ message = I18n.translate(:"errors.messages.mini_magick_processing_error", :e => e)
268
+ raise CarrierWave::ProcessingError, message
269
+ ensure
270
+ image.destroy! if image
271
+ end
272
+
273
+ # Process the image with MiniMagick, using the ImageProcessing gem. This
274
+ # method will build a "convert" ImageMagick command and execute it on the
275
+ # current image.
276
+ #
277
+ # === Gotcha
278
+ #
279
+ # This method assumes that the object responds to +current_path+.
280
+ # Any class that this module is mixed into must have a +current_path+ method.
281
+ # CarrierWave::Uploader does, so you won't need to worry about this in
282
+ # most cases.
283
+ #
284
+ # === Yields
285
+ #
286
+ # [ImageProcessing::Builder] use it to define processing to be performed
287
+ #
288
+ # === Raises
289
+ #
290
+ # [CarrierWave::ProcessingError] if processing failed.
291
+ def minimagick!(block = nil)
292
+ builder = ImageProcessing::MiniMagick.source(current_path)
293
+ builder = yield(builder)
294
+
295
+ result = builder.call
296
+ result.close
308
297
 
309
- image.run_command("identify", current_path)
310
- ensure
311
- image.destroy!
298
+ # backwards compatibility (we want to eventually move away from MiniMagick::Image)
299
+ if block
300
+ image = ::MiniMagick::Image.new(result.path, result)
301
+ image = block.call(image)
302
+ result = image.instance_variable_get(:@tempfile)
303
+ end
304
+
305
+ FileUtils.mv result.path, current_path
306
+
307
+ if File.extname(result.path) != File.extname(current_path)
308
+ move_to = current_path.chomp(File.extname(current_path)) + File.extname(result.path)
309
+ file.content_type = ::MiniMime.lookup_by_filename(move_to).content_type
310
+ file.move_to(move_to, permissions, directory_permissions)
312
311
  end
313
312
  rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
314
313
  message = I18n.translate(:"errors.messages.mini_magick_processing_error", :e => e)
@@ -317,27 +316,15 @@ module CarrierWave
317
316
 
318
317
  private
319
318
 
320
- def append_combine_options(cmd, combine_options)
321
- combine_options.each do |method, options|
322
- if options.nil?
323
- cmd.send(method)
324
- else
325
- cmd.send(method, options)
326
- end
319
+ def resolve_dimensions(*dimensions)
320
+ dimensions.map do |value|
321
+ next value unless value.instance_of?(Proc)
322
+ value.arity >= 1 ? value.call(self) : value.call
327
323
  end
328
324
  end
329
325
 
330
- def dimension_from(value)
331
- return value unless value.instance_of?(Proc)
332
- value.arity >= 1 ? value.call(self) : value.call
333
- end
334
-
335
326
  def mini_magick_image
336
- if url
337
- ::MiniMagick::Image.open(url)
338
- else
339
- ::MiniMagick::Image.open(current_path)
340
- end
327
+ ::MiniMagick::Image.read(read)
341
328
  end
342
329
 
343
330
  end # MiniMagick
@@ -67,6 +67,13 @@ module CarrierWave
67
67
  e.message << " (You may need to install the rmagick gem)"
68
68
  raise e
69
69
  end
70
+
71
+ prepend Module.new {
72
+ def initialize(*)
73
+ super
74
+ @format = nil
75
+ end
76
+ }
70
77
  end
71
78
 
72
79
  module ClassMethods
@@ -346,7 +353,7 @@ module CarrierWave
346
353
  frames = ::Magick::ImageList.new
347
354
 
348
355
  image.each_with_index do |frame, index|
349
- frame = yield *[frame, index, options].take(block.arity) if block_given?
356
+ frame = yield(*[frame, index, options].take(block.arity)) if block_given?
350
357
  frames << frame if frame
351
358
  end
352
359
  frames.append(true) if block_given?
@@ -356,6 +363,7 @@ module CarrierWave
356
363
  if options[:format] || @format
357
364
  frames.write("#{options[:format] || @format}:#{current_path}", &write_block)
358
365
  move_to = current_path.chomp(File.extname(current_path)) + ".#{options[:format] || @format}"
366
+ file.content_type = ::MiniMime.lookup_by_filename(move_to).content_type
359
367
  file.move_to(move_to, permissions, directory_permissions)
360
368
  else
361
369
  frames.write(current_path, &write_block)
@@ -370,9 +378,15 @@ module CarrierWave
370
378
 
371
379
  def create_info_block(options)
372
380
  return nil unless options
373
- assignments = options.map { |k, v| "self.#{k} = #{v}" }
374
- code = "lambda { |img| " + assignments.join(";") + "}"
375
- eval code
381
+ proc do |img|
382
+ options.each do |k, v|
383
+ if v.is_a?(String) && (matches = v.match(/^["'](.+)["']/))
384
+ ActiveSupport::Deprecation.warn "Passing quoted strings like #{v} to #manipulate! is deprecated, pass them without quoting."
385
+ v = matches[1]
386
+ end
387
+ img.public_send(:"#{k}=", v)
388
+ end
389
+ end
376
390
  end
377
391
 
378
392
  def destroy_image(image)