carrierwave 0.10.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +248 -116
  3. data/lib/carrierwave/compatibility/paperclip.rb +0 -2
  4. data/lib/carrierwave/error.rb +1 -0
  5. data/lib/carrierwave/locale/en.yml +7 -4
  6. data/lib/carrierwave/mount.rb +219 -176
  7. data/lib/carrierwave/mounter.rb +165 -0
  8. data/lib/carrierwave/orm/activerecord.rb +50 -21
  9. data/lib/carrierwave/processing/mini_magick.rb +82 -15
  10. data/lib/carrierwave/processing/rmagick.rb +47 -4
  11. data/lib/carrierwave/processing.rb +0 -1
  12. data/lib/carrierwave/sanitized_file.rb +38 -18
  13. data/lib/carrierwave/storage/abstract.rb +15 -2
  14. data/lib/carrierwave/storage/file.rb +65 -2
  15. data/lib/carrierwave/storage/fog.rb +106 -31
  16. data/lib/carrierwave/storage.rb +0 -7
  17. data/lib/carrierwave/test/matchers.rb +77 -12
  18. data/lib/carrierwave/uploader/cache.rb +58 -30
  19. data/lib/carrierwave/uploader/callbacks.rb +0 -2
  20. data/lib/carrierwave/uploader/configuration.rb +51 -8
  21. data/lib/carrierwave/uploader/content_type_blacklist.rb +48 -0
  22. data/lib/carrierwave/uploader/content_type_whitelist.rb +48 -0
  23. data/lib/carrierwave/uploader/default_url.rb +3 -5
  24. data/lib/carrierwave/uploader/download.rb +15 -8
  25. data/lib/carrierwave/uploader/extension_blacklist.rb +14 -10
  26. data/lib/carrierwave/uploader/extension_whitelist.rb +13 -10
  27. data/lib/carrierwave/uploader/file_size.rb +43 -0
  28. data/lib/carrierwave/uploader/magic_mime_blacklist.rb +94 -0
  29. data/lib/carrierwave/uploader/magic_mime_whitelist.rb +94 -0
  30. data/lib/carrierwave/uploader/mountable.rb +7 -8
  31. data/lib/carrierwave/uploader/processing.rb +10 -10
  32. data/lib/carrierwave/uploader/proxy.rb +5 -7
  33. data/lib/carrierwave/uploader/remove.rb +0 -2
  34. data/lib/carrierwave/uploader/serialization.rb +1 -3
  35. data/lib/carrierwave/uploader/store.rb +5 -23
  36. data/lib/carrierwave/uploader/url.rb +3 -5
  37. data/lib/carrierwave/uploader/versions.rb +75 -82
  38. data/lib/carrierwave/uploader.rb +6 -2
  39. data/lib/carrierwave/utilities/uri.rb +5 -6
  40. data/lib/carrierwave/utilities.rb +0 -3
  41. data/lib/carrierwave/validations/active_model.rb +3 -5
  42. data/lib/carrierwave/version.rb +1 -1
  43. data/lib/carrierwave.rb +12 -10
  44. data/lib/generators/templates/uploader.rb +4 -6
  45. metadata +37 -61
  46. data/lib/carrierwave/locale/cs.yml +0 -11
  47. data/lib/carrierwave/locale/de.yml +0 -11
  48. data/lib/carrierwave/locale/el.yml +0 -11
  49. data/lib/carrierwave/locale/es.yml +0 -11
  50. data/lib/carrierwave/locale/fr.yml +0 -11
  51. data/lib/carrierwave/locale/ja.yml +0 -11
  52. data/lib/carrierwave/locale/nb.yml +0 -11
  53. data/lib/carrierwave/locale/nl.yml +0 -11
  54. data/lib/carrierwave/locale/pl.yml +0 -11
  55. data/lib/carrierwave/locale/pt-BR.yml +0 -11
  56. data/lib/carrierwave/locale/pt-PT.yml +0 -11
  57. data/lib/carrierwave/locale/ru.yml +0 -11
  58. data/lib/carrierwave/locale/sk.yml +0 -11
  59. data/lib/carrierwave/locale/tr.yml +0 -11
  60. data/lib/carrierwave/processing/mime_types.rb +0 -74
  61. data/lib/carrierwave/utilities/deprecation.rb +0 -18
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  require 'active_record'
4
2
  require 'carrierwave/validations/active_model'
5
3
 
@@ -14,6 +12,35 @@ module CarrierWave
14
12
  def mount_uploader(column, uploader=nil, options={}, &block)
15
13
  super
16
14
 
15
+ class_eval <<-RUBY, __FILE__, __LINE__+1
16
+ def remote_#{column}_url=(url)
17
+ column = _mounter(:#{column}).serialization_column
18
+ __send__(:"\#{column}_will_change!")
19
+ super
20
+ end
21
+ RUBY
22
+ end
23
+
24
+ ##
25
+ # See +CarrierWave::Mount#mount_uploaders+ for documentation
26
+ #
27
+ def mount_uploaders(column, uploader=nil, options={}, &block)
28
+ super
29
+
30
+ class_eval <<-RUBY, __FILE__, __LINE__+1
31
+ def remote_#{column}_urls=(url)
32
+ column = _mounter(:#{column}).serialization_column
33
+ __send__(:"\#{column}_will_change!")
34
+ super
35
+ end
36
+ RUBY
37
+ end
38
+
39
+ private
40
+
41
+ def mount_base(column, uploader=nil, options={}, &block)
42
+ super
43
+
17
44
  alias_method :read_uploader, :read_attribute
18
45
  alias_method :write_uploader, :write_attribute
19
46
  public :read_uploader
@@ -29,43 +56,45 @@ module CarrierWave
29
56
  before_save :"write_#{column}_identifier"
30
57
  after_commit :"remove_#{column}!", :on => :destroy
31
58
  after_commit :"mark_remove_#{column}_false", :on => :update
32
- before_update :"store_previous_model_for_#{column}"
33
- after_save :"remove_previously_stored_#{column}"
59
+
60
+ after_save :"store_previous_changes_for_#{column}"
61
+ after_commit :"remove_previously_stored_#{column}", :on => :update
34
62
 
35
63
  class_eval <<-RUBY, __FILE__, __LINE__+1
36
64
  def #{column}=(new_file)
37
65
  column = _mounter(:#{column}).serialization_column
38
- send(:"\#{column}_will_change!")
66
+ if !(new_file.blank? && __send__(:#{column}).blank?)
67
+ __send__(:"\#{column}_will_change!")
68
+ end
69
+
39
70
  super
40
71
  end
41
72
 
42
- def remote_#{column}_url=(url)
73
+ def remove_#{column}=(value)
43
74
  column = _mounter(:#{column}).serialization_column
44
- send(:"\#{column}_will_change!")
75
+ __send__(:"\#{column}_will_change!")
45
76
  super
46
77
  end
47
78
 
48
79
  def remove_#{column}!
80
+ self.remove_#{column} = true
81
+ write_#{column}_identifier
82
+ self.remove_#{column} = false
49
83
  super
50
- _mounter(:#{column}).remove = true
51
- _mounter(:#{column}).write_identifier
52
84
  end
53
85
 
54
- def serializable_hash(options=nil)
55
- hash = {}
56
-
57
- except = options && options[:except] && Array.wrap(options[:except]).map(&:to_s)
58
- only = options && options[:only] && Array.wrap(options[:only]).map(&:to_s)
86
+ # Reset cached mounter on record reload
87
+ def reload(*)
88
+ @_mounters = nil
89
+ super
90
+ end
59
91
 
60
- self.class.uploaders.each do |column, uploader|
61
- if (!only && !except) || (only && only.include?(column.to_s)) || (!only && except && !except.include?(column.to_s))
62
- hash[column.to_s] = _mounter(column).uploader.serializable_hash
63
- end
64
- end
65
- super(options).merge(hash)
92
+ # Reset cached mounter on record dup
93
+ def initialize_dup(other)
94
+ @_mounters = nil
95
+ super
66
96
  end
67
97
  RUBY
68
-
69
98
  end
70
99
 
71
100
  end # ActiveRecord
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
 
5
3
  ##
@@ -39,6 +37,7 @@ module CarrierWave
39
37
  # img
40
38
  # end
41
39
  # end
40
+ # end
42
41
  #
43
42
  # === Note
44
43
  #
@@ -49,7 +48,7 @@ module CarrierWave
49
48
  #
50
49
  # http://mini_magick.rubyforge.org/
51
50
  # and
52
- # https://github.com/minimagic/minimagick/
51
+ # https://github.com/minimagick/minimagick/
53
52
  #
54
53
  #
55
54
  module MiniMagick
@@ -81,7 +80,7 @@ module CarrierWave
81
80
  process :resize_to_fill => [width, height, gravity]
82
81
  end
83
82
 
84
- def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
83
+ def resize_and_pad(width, height, background=:transparent, gravity='Center')
85
84
  process :resize_and_pad => [width, height, background, gravity]
86
85
  end
87
86
  end
@@ -103,10 +102,10 @@ module CarrierWave
103
102
  #
104
103
  # image.convert(:png)
105
104
  #
106
- def convert(format)
105
+ def convert(format, page=nil)
107
106
  @format = format
107
+ @page = page
108
108
  manipulate! do |img|
109
- img.format(format.to_s.downcase)
110
109
  img = yield(img) if block_given?
111
110
  img
112
111
  end
@@ -127,9 +126,14 @@ module CarrierWave
127
126
  #
128
127
  # [MiniMagick::Image] additional manipulations to perform
129
128
  #
130
- def resize_to_limit(width, height)
129
+ def resize_to_limit(width, height, combine_options: {})
130
+ width = dimension_from width
131
+ height = dimension_from height
131
132
  manipulate! do |img|
132
- img.resize "#{width}x#{height}>"
133
+ img.combine_options do |cmd|
134
+ cmd.resize "#{width}x#{height}>"
135
+ append_combine_options cmd, combine_options
136
+ end
133
137
  img = yield(img) if block_given?
134
138
  img
135
139
  end
@@ -149,9 +153,14 @@ module CarrierWave
149
153
  #
150
154
  # [MiniMagick::Image] additional manipulations to perform
151
155
  #
152
- def resize_to_fit(width, height)
156
+ def resize_to_fit(width, height, combine_options: {})
157
+ width = dimension_from width
158
+ height = dimension_from height
153
159
  manipulate! do |img|
154
- img.resize "#{width}x#{height}"
160
+ img.combine_options do |cmd|
161
+ cmd.resize "#{width}x#{height}"
162
+ append_combine_options cmd, combine_options
163
+ end
155
164
  img = yield(img) if block_given?
156
165
  img
157
166
  end
@@ -172,7 +181,9 @@ module CarrierWave
172
181
  #
173
182
  # [MiniMagick::Image] additional manipulations to perform
174
183
  #
175
- def resize_to_fill(width, height, gravity = 'Center')
184
+ def resize_to_fill(width, height, gravity = 'Center', combine_options: {})
185
+ width = dimension_from width
186
+ height = dimension_from height
176
187
  manipulate! do |img|
177
188
  cols, rows = img[:dimensions]
178
189
  img.combine_options do |cmd|
@@ -192,6 +203,7 @@ module CarrierWave
192
203
  cmd.gravity gravity
193
204
  cmd.background "rgba(255,255,255,0.0)"
194
205
  cmd.extent "#{width}x#{height}" if cols != width || rows != height
206
+ append_combine_options cmd, combine_options
195
207
  end
196
208
  img = yield(img) if block_given?
197
209
  img
@@ -218,7 +230,9 @@ module CarrierWave
218
230
  #
219
231
  # [MiniMagick::Image] additional manipulations to perform
220
232
  #
221
- def resize_and_pad(width, height, background=:transparent, gravity='Center')
233
+ def resize_and_pad(width, height, background=:transparent, gravity='Center', combine_options: {})
234
+ width = dimension_from width
235
+ height = dimension_from height
222
236
  manipulate! do |img|
223
237
  img.combine_options do |cmd|
224
238
  cmd.thumbnail "#{width}x#{height}>"
@@ -229,12 +243,35 @@ module CarrierWave
229
243
  end
230
244
  cmd.gravity gravity
231
245
  cmd.extent "#{width}x#{height}"
246
+ append_combine_options cmd, combine_options
232
247
  end
233
248
  img = yield(img) if block_given?
234
249
  img
235
250
  end
236
251
  end
237
252
 
253
+ ##
254
+ # Returns the width of the image in pixels.
255
+ #
256
+ # === Returns
257
+ #
258
+ # [Integer] the image's width in pixels
259
+ #
260
+ def width
261
+ mini_magick_image[:width]
262
+ end
263
+
264
+ ##
265
+ # Returns the height of the image in pixels.
266
+ #
267
+ # === Returns
268
+ #
269
+ # [Integer] the image's height in pixels
270
+ #
271
+ def height
272
+ mini_magick_image[:height]
273
+ end
274
+
238
275
  ##
239
276
  # Manipulate the image with MiniMagick. This method will load up an image
240
277
  # and then pass each of its frames to the supplied block. It will then
@@ -260,18 +297,48 @@ module CarrierWave
260
297
  image = ::MiniMagick::Image.open(current_path)
261
298
 
262
299
  begin
263
- image.format(@format.to_s.downcase) if @format
300
+ image.format(@format.to_s.downcase, @page) if @format
264
301
  image = yield(image)
265
302
  image.write(current_path)
303
+
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
308
+
266
309
  image.run_command("identify", current_path)
267
310
  ensure
268
311
  image.destroy!
269
312
  end
270
313
  rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
271
- default = I18n.translate(:"errors.messages.mini_magick_processing_error", :e => e, :locale => :en)
272
- message = I18n.translate(:"errors.messages.mini_magick_processing_error", :e => e, :default => default)
314
+ message = I18n.translate(:"errors.messages.mini_magick_processing_error", :e => e)
273
315
  raise CarrierWave::ProcessingError, message
274
316
  end
275
317
 
318
+ private
319
+
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
327
+ end
328
+ end
329
+
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
+ def mini_magick_image
336
+ if url
337
+ ::MiniMagick::Image.open(url)
338
+ else
339
+ ::MiniMagick::Image.open(current_path)
340
+ end
341
+ end
342
+
276
343
  end # MiniMagick
277
344
  end # CarrierWave
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
 
5
3
  ##
@@ -62,6 +60,8 @@ module CarrierWave
62
60
 
63
61
  included do
64
62
  begin
63
+ require "rmagick"
64
+ rescue LoadError
65
65
  require "RMagick"
66
66
  rescue LoadError => e
67
67
  e.message << " (You may need to install the rmagick gem)"
@@ -133,6 +133,8 @@ module CarrierWave
133
133
  # [Magick::Image] additional manipulations to perform
134
134
  #
135
135
  def resize_to_limit(width, height)
136
+ width = dimension_from width
137
+ height = dimension_from height
136
138
  manipulate! do |img|
137
139
  geometry = Magick::Geometry.new(width, height, 0, 0, Magick::GreaterGeometry)
138
140
  new_img = img.change_geometry(geometry) do |new_width, new_height|
@@ -162,6 +164,8 @@ module CarrierWave
162
164
  # [Magick::Image] additional manipulations to perform
163
165
  #
164
166
  def resize_to_fit(width, height)
167
+ width = dimension_from width
168
+ height = dimension_from height
165
169
  manipulate! do |img|
166
170
  img.resize_to_fit!(width, height)
167
171
  img = yield(img) if block_given?
@@ -186,6 +190,8 @@ module CarrierWave
186
190
  # [Magick::Image] additional manipulations to perform
187
191
  #
188
192
  def resize_to_fill(width, height, gravity=::Magick::CenterGravity)
193
+ width = dimension_from width
194
+ height = dimension_from height
189
195
  manipulate! do |img|
190
196
  img.crop_resized!(width, height, gravity)
191
197
  img = yield(img) if block_given?
@@ -211,6 +217,8 @@ module CarrierWave
211
217
  # [Magick::Image] additional manipulations to perform
212
218
  #
213
219
  def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
220
+ width = dimension_from width
221
+ height = dimension_from height
214
222
  manipulate! do |img|
215
223
  img.resize_to_fit!(width, height)
216
224
  new_img = ::Magick::Image.new(width, height) { self.background_color = background == :transparent ? 'rgba(255,255,255,0)' : background.to_s }
@@ -249,6 +257,28 @@ module CarrierWave
249
257
  end
250
258
  end
251
259
 
260
+ ##
261
+ # Returns the width of the image.
262
+ #
263
+ # === Returns
264
+ #
265
+ # [Integer] the image's width in pixels
266
+ #
267
+ def width
268
+ rmagick_image.columns
269
+ end
270
+
271
+ ##
272
+ # Returns the height of the image.
273
+ #
274
+ # === Returns
275
+ #
276
+ # [Integer] the image's height in pixels
277
+ #
278
+ def height
279
+ rmagick_image.rows
280
+ end
281
+
252
282
  ##
253
283
  # Manipulate the image with RMagick. This method will load up an image
254
284
  # and then pass each of its frames to the supplied block. It will then
@@ -322,14 +352,18 @@ module CarrierWave
322
352
  frames.append(true) if block_given?
323
353
 
324
354
  write_block = create_info_block(options[:write])
355
+
325
356
  if options[:format] || @format
326
357
  frames.write("#{options[:format] || @format}:#{current_path}", &write_block)
358
+ move_to = current_path.chomp(File.extname(current_path)) + ".#{options[:format] || @format}"
359
+ file.move_to(move_to, permissions, directory_permissions)
327
360
  else
328
361
  frames.write(current_path, &write_block)
329
362
  end
363
+
330
364
  destroy_image(frames)
331
365
  rescue ::Magick::ImageMagickError => e
332
- raise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.rmagick_processing_error", :e => e, :default => I18n.translate(:"errors.messages.rmagick_processing_error", :e => e, :locale => :en))
366
+ raise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.rmagick_processing_error", :e => e)
333
367
  end
334
368
 
335
369
  private
@@ -342,7 +376,16 @@ module CarrierWave
342
376
  end
343
377
 
344
378
  def destroy_image(image)
345
- image.destroy! if image.respond_to?(:destroy!)
379
+ image.try(:destroy!)
380
+ end
381
+
382
+ def dimension_from(value)
383
+ return value unless value.instance_of?(Proc)
384
+ value.arity >= 1 ? value.call(self) : value.call
385
+ end
386
+
387
+ def rmagick_image
388
+ ::Magick::Image.from_blob(self.read).first
346
389
  end
347
390
 
348
391
  end # RMagick
@@ -1,3 +1,2 @@
1
1
  require "carrierwave/processing/rmagick"
2
2
  require "carrierwave/processing/mini_magick"
3
- require "carrierwave/processing/mime_types"
@@ -1,8 +1,12 @@
1
- # encoding: utf-8
2
-
3
1
  require 'pathname'
4
2
  require 'active_support/core_ext/string/multibyte'
5
- require 'mime/types'
3
+
4
+ begin
5
+ # Use mime/types/columnar if available, for reduced memory usage
6
+ require 'mime/types/columnar'
7
+ rescue LoadError
8
+ require 'mime/types'
9
+ end
6
10
 
7
11
  module CarrierWave
8
12
 
@@ -22,7 +26,7 @@ module CarrierWave
22
26
  attr_writer :sanitize_regexp
23
27
 
24
28
  def sanitize_regexp
25
- @sanitize_regexp ||= /[^a-zA-Z0-9\.\-\+_]/
29
+ @sanitize_regexp ||= /[^[:word:]\.\-\+]/
26
30
  end
27
31
  end
28
32
 
@@ -142,8 +146,7 @@ module CarrierWave
142
146
  # [Boolean] Whether the file exists
143
147
  #
144
148
  def exists?
145
- return File.exists?(self.path) if self.path
146
- return false
149
+ self.path.present? && File.exist?(self.path)
147
150
  end
148
151
 
149
152
  ##
@@ -159,9 +162,9 @@ module CarrierWave
159
162
  elsif is_path?
160
163
  File.open(@file, "rb") {|file| file.read}
161
164
  else
162
- @file.rewind if @file.respond_to?(:rewind)
165
+ @file.try(:rewind)
163
166
  @content = @file.read
164
- @file.close if @file.respond_to?(:close) && @file.respond_to?(:closed?) && !@file.closed?
167
+ @file.try(:close) unless @file.try(:closed?)
165
168
  @content
166
169
  end
167
170
  end
@@ -175,19 +178,29 @@ module CarrierWave
175
178
  # [permissions (Integer)] permissions to set on the file in its new location.
176
179
  # [directory_permissions (Integer)] permissions to set on created directories.
177
180
  #
178
- def move_to(new_path, permissions=nil, directory_permissions=nil)
181
+ def move_to(new_path, permissions=nil, directory_permissions=nil, keep_filename=false)
179
182
  return if self.empty?
180
183
  new_path = File.expand_path(new_path)
181
184
 
182
185
  mkdir!(new_path, directory_permissions)
186
+ move!(new_path)
187
+ chmod!(new_path, permissions)
188
+ if keep_filename
189
+ self.file = {:tempfile => new_path, :filename => original_filename, :content_type => content_type}
190
+ else
191
+ self.file = {:tempfile => new_path, :content_type => content_type}
192
+ end
193
+ self
194
+ end
195
+ ##
196
+ # Helper to move file to new path.
197
+ #
198
+ def move!(new_path)
183
199
  if exists?
184
- FileUtils.mv(path, new_path) unless new_path == path
200
+ FileUtils.mv(path, new_path) unless File.identical?(new_path, path)
185
201
  else
186
202
  File.open(new_path, "wb") { |f| f.write(read) }
187
203
  end
188
- chmod!(new_path, permissions)
189
- self.file = new_path
190
- self
191
204
  end
192
205
 
193
206
  ##
@@ -208,13 +221,20 @@ module CarrierWave
208
221
  new_path = File.expand_path(new_path)
209
222
 
210
223
  mkdir!(new_path, directory_permissions)
224
+ copy!(new_path)
225
+ chmod!(new_path, permissions)
226
+ self.class.new({:tempfile => new_path, :content_type => content_type})
227
+ end
228
+
229
+ ##
230
+ # Helper to create copy of file in new path.
231
+ #
232
+ def copy!(new_path)
211
233
  if exists?
212
234
  FileUtils.cp(path, new_path) unless new_path == path
213
235
  else
214
236
  File.open(new_path, "wb") { |f| f.write(read) }
215
237
  end
216
- chmod!(new_path, permissions)
217
- self.class.new({:tempfile => new_path, :content_type => content_type})
218
238
  end
219
239
 
220
240
  ##
@@ -280,7 +300,7 @@ module CarrierWave
280
300
  if file.is_a?(Hash)
281
301
  @file = file["tempfile"] || file[:tempfile]
282
302
  @original_filename = file["filename"] || file[:filename]
283
- @content_type = file["content_type"] || file[:content_type]
303
+ @content_type = file["content_type"] || file[:content_type] || file["type"] || file[:type]
284
304
  else
285
305
  @file = file
286
306
  @original_filename = nil
@@ -292,7 +312,7 @@ module CarrierWave
292
312
  def mkdir!(path, directory_permissions)
293
313
  options = {}
294
314
  options[:mode] = directory_permissions if directory_permissions
295
- FileUtils.mkdir_p(File.dirname(path), options) unless File.exists?(File.dirname(path))
315
+ FileUtils.mkdir_p(File.dirname(path), options) unless File.exist?(File.dirname(path))
296
316
  end
297
317
 
298
318
  def chmod!(path, permissions)
@@ -301,7 +321,7 @@ module CarrierWave
301
321
 
302
322
  # Sanitize the filename, to prevent hacking
303
323
  def sanitize(name)
304
- name = name.gsub("\\", "/") # work-around for IE
324
+ name = name.tr("\\", "/") # work-around for IE
305
325
  name = File.basename(name)
306
326
  name = name.gsub(sanitize_regexp,"_")
307
327
  name = "_#{name}" if name =~ /\A\.+\z/
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Storage
5
3
 
@@ -25,6 +23,21 @@ module CarrierWave
25
23
  def retrieve!(identifier)
26
24
  end
27
25
 
26
+ def cache!(new_file)
27
+ raise NotImplementedError.new("Need to implement #cache! if you want to use #{self.class.name} as a cache storage.")
28
+ end
29
+
30
+ def retrieve_from_cache!(identifier)
31
+ raise NotImplementedError.new("Need to implement #retrieve_from_cache! if you want to use #{self.class.name} as a cache storage.")
32
+ end
33
+
34
+ def delete_dir!(path)
35
+ raise NotImplementedError.new("Need to implement #delete_dir! if you want to use #{self.class.name} as a cache storage.")
36
+ end
37
+
38
+ def clean_cache!(seconds)
39
+ raise NotImplementedError.new("Need to implement #clean_cache! if you want to use #{self.class.name} as a cache storage.")
40
+ end
28
41
  end # Abstract
29
42
  end # Storage
30
43
  end # CarrierWave
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module CarrierWave
4
2
  module Storage
5
3
 
@@ -51,6 +49,71 @@ module CarrierWave
51
49
  CarrierWave::SanitizedFile.new(path)
52
50
  end
53
51
 
52
+ ##
53
+ # Stores given file to cache directory.
54
+ #
55
+ # === Parameters
56
+ #
57
+ # [new_file (File, IOString, Tempfile)] any kind of file object
58
+ #
59
+ # === Returns
60
+ #
61
+ # [CarrierWave::SanitizedFile] a sanitized file
62
+ #
63
+ def cache!(new_file)
64
+ new_file.move_to(::File.expand_path(uploader.cache_path, uploader.root), uploader.permissions, uploader.directory_permissions, true)
65
+ rescue Errno::EMLINK => e
66
+ raise(e) if @cache_called
67
+ @cache_called = true
68
+
69
+ # NOTE: Remove cached files older than 10 minutes
70
+ clean_cache!(600)
71
+
72
+ cache!(new_file)
73
+ end
74
+
75
+ ##
76
+ # Retrieves the file with the given cache_name from the cache.
77
+ #
78
+ # === Parameters
79
+ #
80
+ # [cache_name (String)] uniquely identifies a cache file
81
+ #
82
+ # === Raises
83
+ #
84
+ # [CarrierWave::InvalidParameter] if the cache_name is incorrectly formatted.
85
+ #
86
+ def retrieve_from_cache!(identifier)
87
+ CarrierWave::SanitizedFile.new(::File.expand_path(uploader.cache_path(identifier), uploader.root))
88
+ end
89
+
90
+ ##
91
+ # Deletes a cache dir
92
+ #
93
+ def delete_dir!(path)
94
+ if path
95
+ begin
96
+ Dir.rmdir(::File.expand_path(path, uploader.root))
97
+ rescue Errno::ENOENT
98
+ # Ignore: path does not exist
99
+ rescue Errno::ENOTDIR
100
+ # Ignore: path is not a dir
101
+ rescue Errno::ENOTEMPTY, Errno::EEXIST
102
+ # Ignore: dir is not empty
103
+ end
104
+ end
105
+ end
106
+
107
+ def clean_cache!(seconds)
108
+ Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'), CarrierWave.root)).each do |dir|
109
+ # generate_cache_id returns key formated TIMEINT-PID-COUNTER-RND
110
+ time = dir.scan(/(\d+)-\d+-\d+-\d+/).first.map(&:to_i)
111
+ time = Time.at(*time)
112
+ if time < (Time.now.utc - seconds)
113
+ FileUtils.rm_rf(dir)
114
+ end
115
+ end
116
+ end
54
117
  end # File
55
118
  end # Storage
56
119
  end # CarrierWave