carrierwave 0.9.0 → 0.10.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 (34) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +69 -9
  3. data/lib/carrierwave.rb +7 -0
  4. data/lib/carrierwave/compatibility/paperclip.rb +29 -19
  5. data/lib/carrierwave/locale/el.yml +11 -0
  6. data/lib/carrierwave/locale/es.yml +11 -0
  7. data/lib/carrierwave/locale/fr.yml +11 -0
  8. data/lib/carrierwave/locale/ja.yml +11 -0
  9. data/lib/carrierwave/locale/nb.yml +11 -0
  10. data/lib/carrierwave/locale/pl.yml +11 -0
  11. data/lib/carrierwave/locale/pt-BR.yml +11 -0
  12. data/lib/carrierwave/locale/pt-PT.yml +11 -0
  13. data/lib/carrierwave/locale/ru.yml +11 -0
  14. data/lib/carrierwave/locale/tr.yml +11 -0
  15. data/lib/carrierwave/mount.rb +39 -36
  16. data/lib/carrierwave/orm/activerecord.rb +1 -0
  17. data/lib/carrierwave/processing/mime_types.rb +1 -0
  18. data/lib/carrierwave/processing/mini_magick.rb +12 -5
  19. data/lib/carrierwave/processing/rmagick.rb +6 -18
  20. data/lib/carrierwave/sanitized_file.rb +6 -1
  21. data/lib/carrierwave/storage/fog.rb +6 -5
  22. data/lib/carrierwave/uploader/configuration.rb +8 -0
  23. data/lib/carrierwave/uploader/download.rb +16 -10
  24. data/lib/carrierwave/uploader/processing.rb +15 -17
  25. data/lib/carrierwave/uploader/proxy.rb +11 -0
  26. data/lib/carrierwave/uploader/serialization.rb +1 -1
  27. data/lib/carrierwave/uploader/versions.rb +45 -44
  28. data/lib/carrierwave/utilities.rb +2 -1
  29. data/lib/carrierwave/utilities/deprecation.rb +18 -0
  30. data/lib/carrierwave/validations/active_model.rb +0 -2
  31. data/lib/carrierwave/version.rb +1 -1
  32. data/lib/generators/templates/uploader.rb +1 -1
  33. data/lib/generators/uploader_generator.rb +1 -1
  34. metadata +100 -72
@@ -28,6 +28,7 @@ module CarrierWave
28
28
  after_save :"store_#{column}!"
29
29
  before_save :"write_#{column}_identifier"
30
30
  after_commit :"remove_#{column}!", :on => :destroy
31
+ after_commit :"mark_remove_#{column}_false", :on => :update
31
32
  before_update :"store_previous_model_for_#{column}"
32
33
  after_save :"remove_previously_stored_#{column}"
33
34
 
@@ -27,6 +27,7 @@ module CarrierWave
27
27
  extend ActiveSupport::Concern
28
28
 
29
29
  included do
30
+ CarrierWave::Utilities::Deprecation.new "0.11.0", "CarrierWave::MimeTypes is deprecated and will be removed in the future, get the content_type from the SanitizedFile object directly."
30
31
  begin
31
32
  require "mime/types"
32
33
  rescue LoadError => e
@@ -258,12 +258,19 @@ module CarrierWave
258
258
  def manipulate!
259
259
  cache_stored_file! if !cached?
260
260
  image = ::MiniMagick::Image.open(current_path)
261
- image.format(@format.to_s.downcase) if @format
262
- image = yield(image)
263
- image.write(current_path)
264
- ::MiniMagick::Image.open(current_path)
261
+
262
+ begin
263
+ image.format(@format.to_s.downcase) if @format
264
+ image = yield(image)
265
+ image.write(current_path)
266
+ image.run_command("identify", current_path)
267
+ ensure
268
+ image.destroy!
269
+ end
265
270
  rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
266
- raise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.mini_magick_processing_error", :e => e, :default => I18n.translate(:"errors.messages.mini_magick_processing_error", :e => e, :locale => :en))
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)
273
+ raise CarrierWave::ProcessingError, message
267
274
  end
268
275
 
269
276
  end # MiniMagick
@@ -62,8 +62,6 @@ module CarrierWave
62
62
 
63
63
  included do
64
64
  begin
65
- require "rmagick"
66
- rescue LoadError
67
65
  require "RMagick"
68
66
  rescue LoadError => e
69
67
  e.message << " (You may need to install the rmagick gem)"
@@ -215,7 +213,7 @@ module CarrierWave
215
213
  def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
216
214
  manipulate! do |img|
217
215
  img.resize_to_fit!(width, height)
218
- new_img = ::Magick::Image.new(width, height) { self.background_color = 'rgba(255,255,255,0)' }
216
+ new_img = ::Magick::Image.new(width, height) { self.background_color = background == :transparent ? 'rgba(255,255,255,0)' : background.to_s }
219
217
  if background == :transparent
220
218
  filled = new_img.matte_floodfill(1, 1)
221
219
  else
@@ -315,23 +313,13 @@ module CarrierWave
315
313
 
316
314
  read_block = create_info_block(options[:read])
317
315
  image = ::Magick::Image.read(current_path, &read_block)
316
+ frames = ::Magick::ImageList.new
318
317
 
319
- frames = if image.size > 1
320
- list = ::Magick::ImageList.new
321
- image.each_with_index do |frame, index|
322
- processed_frame = if block_given?
323
- yield *[frame, index, options].take(block.arity)
324
- else
325
- frame
326
- end
327
- list << processed_frame if processed_frame
328
- end
329
- block_given? ? list : list.append(true)
330
- else
331
- frame = image.first
332
- frame = yield( *[frame, 0, options].take(block.arity) ) if block_given?
333
- frame
318
+ image.each_with_index do |frame, index|
319
+ frame = yield *[frame, index, options].take(block.arity) if block_given?
320
+ frames << frame if frame
334
321
  end
322
+ frames.append(true) if block_given?
335
323
 
336
324
  write_block = create_info_block(options[:write])
337
325
  if options[:format] || @format
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'active_support/core_ext/string/multibyte'
5
+ require 'mime/types'
5
6
 
6
7
  module CarrierWave
7
8
 
@@ -244,7 +245,11 @@ module CarrierWave
244
245
  #
245
246
  def content_type
246
247
  return @content_type if @content_type
247
- @file.content_type.to_s.chomp if @file.respond_to?(:content_type) and @file.content_type
248
+ if @file.respond_to?(:content_type) and @file.content_type
249
+ @content_type = @file.content_type.to_s.chomp
250
+ elsif path
251
+ @content_type = ::MIME::Types.type_for(path).first.to_s
252
+ end
248
253
  end
249
254
 
250
255
  ##
@@ -137,13 +137,13 @@ module CarrierWave
137
137
  # [NilClass] no authenticated url available
138
138
  #
139
139
  def authenticated_url(options = {})
140
- if ['AWS', 'Google', 'Rackspace'].include?(@uploader.fog_credentials[:provider])
140
+ if ['AWS', 'Google', 'Rackspace', 'OpenStack'].include?(@uploader.fog_credentials[:provider])
141
141
  # avoid a get by using local references
142
142
  local_directory = connection.directories.new(:key => @uploader.fog_directory)
143
143
  local_file = local_directory.files.new(:key => path)
144
144
  if @uploader.fog_credentials[:provider] == "AWS"
145
145
  local_file.url(::Fog::Time.now + @uploader.fog_authenticated_url_expiration, options)
146
- elsif @uploader.fog_credentials[:provider] == "Rackspace"
146
+ elsif ['Rackspace', 'OpenStack'].include?(@uploader.fog_credentials[:provider])
147
147
  connection.get_object_https_url(@uploader.fog_directory, path, ::Fog::Time.now + @uploader.fog_authenticated_url_expiration)
148
148
  else
149
149
  local_file.url(::Fog::Time.now + @uploader.fog_authenticated_url_expiration)
@@ -192,10 +192,11 @@ module CarrierWave
192
192
  #
193
193
  # === Returns
194
194
  #
195
- # [String] extension of file
195
+ # [String] extension of file or nil if the file has no extension
196
196
  #
197
197
  def extension
198
- path.split('.').last
198
+ path_elements = path.split('.')
199
+ path_elements.last if path_elements.size > 1
199
200
  end
200
201
 
201
202
  ##
@@ -338,7 +339,7 @@ module CarrierWave
338
339
  #
339
340
  def filename(options = {})
340
341
  if file_url = url(options)
341
- URI.decode(file_url).gsub(/.*\/(.*?$)/, '\1')
342
+ URI.decode(file_url).gsub(/.*\/(.*?$)/, '\1').split('?').first
342
343
  end
343
344
  end
344
345
 
@@ -78,8 +78,14 @@ module CarrierWave
78
78
 
79
79
  def add_config(name)
80
80
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
81
+ def self.eager_load_fog(fog_credentials)
82
+ # see #1198. This will hopefully no longer be necessary after fog 2.0
83
+ Fog::Storage.new(fog_credentials) if fog_credentials.present?
84
+ end
85
+
81
86
  def self.#{name}(value=nil)
82
87
  @#{name} = value if value
88
+ eager_load_fog(value) if value && '#{name}' == 'fog_credentials'
83
89
  return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
84
90
  name = superclass.#{name}
85
91
  return nil if name.nil? && !instance_variable_defined?("@#{name}")
@@ -87,10 +93,12 @@ module CarrierWave
87
93
  end
88
94
 
89
95
  def self.#{name}=(value)
96
+ eager_load_fog(value) if '#{name}' == 'fog_credentials'
90
97
  @#{name} = value
91
98
  end
92
99
 
93
100
  def #{name}=(value)
101
+ self.class.eager_load_fog(value) if '#{name}' == 'fog_credentials'
94
102
  @#{name} = value
95
103
  end
96
104
 
@@ -17,11 +17,12 @@ module CarrierWave
17
17
  end
18
18
 
19
19
  def original_filename
20
- if file.meta.include? 'content-disposition'
21
- match = file.meta['content-disposition'].match(/filename=(\"?)(.+)\1/)
22
- return match[2] unless match.nil?
20
+ filename = filename_from_header || File.basename(file.base_uri.path)
21
+ mime_type = MIME::Types[file.content_type].first
22
+ unless File.extname(filename).present? || mime_type.blank?
23
+ filename = "#{filename}.#{mime_type.extensions.first}"
23
24
  end
24
- File.basename(file.base_uri.path)
25
+ filename
25
26
  end
26
27
 
27
28
  def respond_to?(*args)
@@ -45,6 +46,13 @@ module CarrierWave
45
46
  raise CarrierWave::DownloadError, "could not download file: #{e.message}"
46
47
  end
47
48
 
49
+ def filename_from_header
50
+ if file.meta.include? 'content-disposition'
51
+ match = file.meta['content-disposition'].match(/filename="?([^"]+)/)
52
+ return match[1] unless match.nil? || match[1].empty?
53
+ end
54
+ end
55
+
48
56
  def method_missing(*args, &block)
49
57
  file.send(*args, &block)
50
58
  end
@@ -58,12 +66,10 @@ module CarrierWave
58
66
  # [url (String)] The URL where the remote file is stored
59
67
  #
60
68
  def download!(uri)
61
- unless uri.blank?
62
- processed_uri = process_uri(uri)
63
- file = RemoteFile.new(processed_uri)
64
- raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
65
- cache!(file)
66
- end
69
+ processed_uri = process_uri(uri)
70
+ file = RemoteFile.new(processed_uri)
71
+ raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
72
+ cache!(file)
67
73
  end
68
74
 
69
75
  ##
@@ -54,20 +54,14 @@ module CarrierWave
54
54
  # end
55
55
  #
56
56
  def process(*args)
57
- if !args.first.is_a?(Hash) && args.last.is_a?(Hash)
58
- conditions = args.pop
59
- args.map!{ |arg| {arg => []}.merge(conditions) }
57
+ new_processors = args.inject({}) do |hash, arg|
58
+ arg = { arg => [] } unless arg.is_a?(Hash)
59
+ hash.merge!(arg)
60
60
  end
61
61
 
62
- args.each do |arg|
63
- if arg.is_a?(Hash)
64
- condition = arg.delete(:if)
65
- arg.each do |method, args|
66
- self.processors += [[method, args, condition]]
67
- end
68
- else
69
- self.processors += [[arg, [], nil]]
70
- end
62
+ condition = new_processors.delete(:if)
63
+ new_processors.each do |processor, processor_args|
64
+ self.processors += [[processor, processor_args, condition]]
71
65
  end
72
66
  end
73
67
 
@@ -77,13 +71,17 @@ module CarrierWave
77
71
  # Apply all process callbacks added through CarrierWave.process
78
72
  #
79
73
  def process!(new_file=nil)
80
- if enable_processing
81
- self.class.processors.each do |method, args, condition|
82
- if(condition)
83
- next if !(condition.respond_to?(:call) ? condition.call(self, :args => args, :method => method, :file => new_file) : self.send(condition, new_file))
74
+ return unless enable_processing
75
+
76
+ self.class.processors.each do |method, args, condition|
77
+ if(condition)
78
+ if condition.respond_to?(:call)
79
+ next unless condition.call(self, :args => args, :method => method, :file => new_file)
80
+ else
81
+ next unless self.send(condition, new_file)
84
82
  end
85
- self.send(method, *args)
86
83
  end
84
+ self.send(method, *args)
87
85
  end
88
86
  end
89
87
 
@@ -72,6 +72,17 @@ module CarrierWave
72
72
  size
73
73
  end
74
74
 
75
+ ##
76
+ # Read the content type of the file
77
+ #
78
+ # === Returns
79
+ #
80
+ # [String] content type of the file
81
+ #
82
+ def content_type
83
+ file.respond_to?(:content_type) ? file.content_type : nil
84
+ end
85
+
75
86
  end # Proxy
76
87
  end # Uploader
77
88
  end # CarrierWave
@@ -8,7 +8,7 @@ module CarrierWave
8
8
  module Serialization
9
9
  extend ActiveSupport::Concern
10
10
 
11
- def serializable_hash
11
+ def serializable_hash(options = nil)
12
12
  {"url" => url}.merge Hash[versions.map { |name, version| [name, { "url" => version.url }] }]
13
13
  end
14
14
 
@@ -50,23 +50,39 @@ module CarrierWave
50
50
  #
51
51
  def version(name, options = {}, &block)
52
52
  name = name.to_sym
53
- unless versions[name]
54
- uploader = Class.new(self)
55
- const_set("Uploader#{uploader.object_id}".gsub('-', '_'), uploader)
56
- uploader.versions = {}
53
+ build_version(name, options) unless versions[name]
57
54
 
55
+ versions[name][:uploader].class_eval(&block) if block
56
+ versions[name]
57
+ end
58
+
59
+ def recursively_apply_block_to_versions(&block)
60
+ versions.each do |name, version|
61
+ version[:uploader].class_eval(&block)
62
+ version[:uploader].recursively_apply_block_to_versions(&block)
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def build_version(name, options)
69
+ uploader = Class.new(self)
70
+ const_set("Uploader#{uploader.object_id}".gsub('-', '_'), uploader)
71
+ uploader.version_names += [name]
72
+ uploader.versions = {}
73
+ uploader.processors = []
74
+
75
+ uploader.class_eval <<-RUBY, __FILE__, __LINE__ + 1
58
76
  # Define the enable_processing method for versions so they get the
59
77
  # value from the parent class unless explicitly overwritten
60
- uploader.class_eval <<-RUBY, __FILE__, __LINE__ + 1
61
- def self.enable_processing(value=nil)
62
- self.enable_processing = value if value
63
- if !@enable_processing.nil?
64
- @enable_processing
65
- else
66
- superclass.enable_processing
67
- end
78
+ def self.enable_processing(value=nil)
79
+ self.enable_processing = value if value
80
+ if !@enable_processing.nil?
81
+ @enable_processing
82
+ else
83
+ superclass.enable_processing
68
84
  end
69
- RUBY
85
+ end
70
86
 
71
87
  # Regardless of what is set in the parent uploader, do not enforce the
72
88
  # move_to_cache config option on versions because it moves the original
@@ -81,42 +97,27 @@ module CarrierWave
81
97
  # end
82
98
  # end
83
99
  #
84
- uploader.class_eval <<-RUBY
85
- def move_to_cache
86
- false
87
- end
88
- RUBY
100
+ def move_to_cache
101
+ false
102
+ end
103
+ RUBY
104
+
105
+ class_eval <<-RUBY
106
+ def #{name}
107
+ versions[:#{name}]
108
+ end
109
+ RUBY
89
110
 
90
- # Add the current version hash to class attribute :versions
91
- current_version = {}
92
- current_version[name] = {
111
+ # Add the current version hash to class attribute :versions
112
+ current_version = {
113
+ name => {
93
114
  :uploader => uploader,
94
115
  :options => options
95
116
  }
96
- self.versions = versions.merge(current_version)
97
-
98
- versions[name][:uploader].version_names += [name]
99
-
100
- class_eval <<-RUBY
101
- def #{name}
102
- versions[:#{name}]
103
- end
104
- RUBY
105
- # as the processors get the output from the previous processors as their
106
- # input we must not stack the processors here
107
- versions[name][:uploader].processors = versions[name][:uploader].processors.dup
108
- versions[name][:uploader].processors.clear
109
- end
110
- versions[name][:uploader].class_eval(&block) if block
111
- versions[name]
117
+ }
118
+ self.versions = versions.merge(current_version)
112
119
  end
113
120
 
114
- def recursively_apply_block_to_versions(&block)
115
- versions.each do |name, version|
116
- version[:uploader].class_eval(&block)
117
- version[:uploader].recursively_apply_block_to_versions(&block)
118
- end
119
- end
120
121
  end # ClassMethods
121
122
 
122
123
  ##
@@ -199,7 +200,7 @@ module CarrierWave
199
200
  if (version = args.first) && version.respond_to?(:to_sym)
200
201
  raise ArgumentError, "Version #{version} doesn't exist!" if versions[version.to_sym].nil?
201
202
  # recursively proxy to version
202
- versions[version.to_sym].url(*args[1..-1]) if version_exists?(version)
203
+ versions[version.to_sym].url(*args[1..-1])
203
204
  elsif args.first
204
205
  super(args.first)
205
206
  else
@@ -1,8 +1,9 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'carrierwave/utilities/uri'
4
+ require 'carrierwave/utilities/deprecation'
4
5
 
5
6
  module CarrierWave
6
7
  module Utilities
7
8
  end
8
- end
9
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+ require 'active_support/deprecation'
3
+
4
+ module CarrierWave
5
+ module Utilities
6
+ module Deprecation
7
+
8
+ def self.new version = '0.11.0', message = 'Carrierwave'
9
+ if ActiveSupport::VERSION::MAJOR < 4
10
+ ActiveSupport::Deprecation.warn("#{message} (will be removed from version #{version})")
11
+ else
12
+ ActiveSupport::Deprecation.new(version, message)
13
+ end
14
+ end
15
+
16
+ end # Deprecation
17
+ end # Utilities
18
+ end # CarrierWave