carrierwave 0.1 → 0.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.

@@ -4,17 +4,68 @@ module CarrierWave
4
4
  module ActiveRecord
5
5
 
6
6
  include CarrierWave::Mount
7
+
8
+ ##
9
+ # See +CarrierWave::Mount#mount_uploader+ for documentation
10
+ #
11
+ def mount_uploader(column, uploader, options={}, &block)
12
+ super
7
13
 
8
- def after_mount(column, uploader)
9
14
  alias_method :read_uploader, :read_attribute
10
15
  alias_method :write_uploader, :write_attribute
11
16
 
17
+ validates_integrity_of column if uploader_options[column.to_sym][:validate_integrity]
18
+ validates_processing_of column if uploader_options[column.to_sym][:validate_processing]
19
+
12
20
  before_save do |record|
13
21
  record.send("store_#{column}!")
14
22
  end
15
23
  end
16
24
 
25
+ ##
26
+ # Makes the record invalid if the file couldn't be uploaded due to an integrity error
27
+ #
28
+ # Accepts the usual parameters for validations in Rails (:if, :unless, etc...)
29
+ #
30
+ # === Note
31
+ #
32
+ # Set this key in your translations file for I18n:
33
+ #
34
+ # carrierwave:
35
+ # errors:
36
+ # integrity: 'Here be an error message'
37
+ #
38
+ def validates_integrity_of(*attrs)
39
+ options = attrs.last.is_a?(Hash) ? attrs.last : {}
40
+ options[:message] ||= I18n.t('carrierwave.errors.integrity', :default => 'is not an allowed type of file.')
41
+ validates_each(*attrs) do |record, attr, value|
42
+ record.errors.add attr, options[:message] if record.send("#{attr}_integrity_error")
43
+ end
44
+ end
45
+
46
+ ##
47
+ # Makes the record invalid if the file couldn't be processed (assuming the process failed
48
+ # with a CarrierWave::ProcessingError)
49
+ #
50
+ # Accepts the usual parameters for validations in Rails (:if, :unless, etc...)
51
+ #
52
+ # === Note
53
+ #
54
+ # Set this key in your translations file for I18n:
55
+ #
56
+ # carrierwave:
57
+ # errors:
58
+ # processing: 'Here be an error message'
59
+ #
60
+ def validates_processing_of(*attrs)
61
+ options = attrs.last.is_a?(Hash) ? attrs.last : {}
62
+ options[:message] ||= I18n.t('carrierwave.errors.processing', :default => 'failed to be processed.')
63
+ validates_each(*attrs) do |record, attr, value|
64
+ record.errors.add attr, options[:message] if record.send("#{attr}_processing_error")
65
+ end
66
+ end
67
+
17
68
  end # ActiveRecord
18
69
  end # CarrierWave
19
70
 
20
- ActiveRecord::Base.send(:extend, CarrierWave::ActiveRecord)
71
+ ActiveRecord::Base.send(:extend, CarrierWave::ActiveRecord)
@@ -5,7 +5,12 @@ module CarrierWave
5
5
 
6
6
  include CarrierWave::Mount
7
7
 
8
- def after_mount(column, uploader)
8
+ ##
9
+ # See +CarrierWave::Mount#mount_uploader+ for documentation
10
+ #
11
+ def mount_uploader(column, uploader, options={}, &block)
12
+ super
13
+
9
14
  alias_method :read_uploader, :attribute_get
10
15
  alias_method :write_uploader, :attribute_set
11
16
 
@@ -17,4 +22,4 @@ module CarrierWave
17
22
  end # DataMapper
18
23
  end # CarrierWave
19
24
 
20
- DataMapper::Model.send(:include, CarrierWave::DataMapper)
25
+ DataMapper::Model.send(:include, CarrierWave::DataMapper)
@@ -0,0 +1,23 @@
1
+ require 'sequel'
2
+
3
+ module CarrierWave
4
+ module Sequel
5
+
6
+ include CarrierWave::Mount
7
+
8
+ def mount_uploader(column, uploader)
9
+ super
10
+
11
+ alias_method :read_uploader, :[]
12
+ alias_method :write_uploader, :[]=
13
+
14
+ before_save do
15
+ send("store_#{column}!")
16
+ end
17
+ end
18
+
19
+ end # Sequel
20
+ end # CarrierWave
21
+
22
+ Sequel::Model.send(:extend, CarrierWave::Sequel)
23
+
@@ -2,7 +2,7 @@ require "image_science"
2
2
 
3
3
  module CarrierWave
4
4
  module ImageScience
5
-
5
+
6
6
  # Resize the image so that it will not exceed the dimensions passed
7
7
  # via geometry, geometry should be a string, formatted like '200x100' where
8
8
  # the first number is the height and the second is the width
@@ -63,8 +63,8 @@ module CarrierWave
63
63
  end
64
64
 
65
65
  def convert_geometry(geometry)
66
- geometry.split('x').map{|i| i.to_f }
66
+ geometry.split('x').map{|i| i.to_f }
67
67
  end
68
68
 
69
69
  end # ImageScience
70
- end # CarrierWave
70
+ end # CarrierWave
@@ -1,37 +1,40 @@
1
1
  require 'rmagick'
2
2
 
3
3
  module CarrierWave
4
-
4
+
5
5
  ##
6
6
  # This module simplifies manipulation with RMagick by providing a set
7
7
  # of convenient helper methods. If you want to use them, you'll need to
8
- # require this file
8
+ # require this file:
9
9
  #
10
10
  # require 'carrierwave/processing/rmagick'
11
11
  #
12
- # And then include it in your uploader
12
+ # And then include it in your uploader:
13
13
  #
14
- # MyUploade < CarrierWave::Uploader
14
+ # class MyUploader
15
+ # include CarrierWave::Uploader
15
16
  # include CarrierWave::RMagick
16
17
  # end
17
18
  #
18
19
  # You can now use the provided helpers:
19
20
  #
20
- # MyUploade < CarrierWave::Uploader
21
+ # class MyUploader
22
+ # include CarrierWave::Uploader
21
23
  # include CarrierWave::RMagick
22
- #
23
- # process :resize_to_fit => [200, 200]
24
+ #
25
+ # process :resize_to_fit => [200, 200]
24
26
  # end
25
27
  #
26
28
  # Or create your own helpers with the powerful manipulate! method. Check
27
29
  # out the RMagick docs at http://www.imagemagick.org/RMagick/doc/ for more
28
30
  # info
29
31
  #
30
- # MyUploade < CarrierWave::Uploader
32
+ # class MyUploader
33
+ # include CarrierWave::Uploader
31
34
  # include CarrierWave::RMagick
32
- #
35
+ #
33
36
  # process :do_stuff => 10.0
34
- #
37
+ #
35
38
  # def do_stuff(blur_factor)
36
39
  # manipulate! do |img|
37
40
  # img = img.sepiatone
@@ -41,17 +44,41 @@ module CarrierWave
41
44
  # end
42
45
  # end
43
46
  #
47
+ # === Note
48
+ #
49
+ # You should be aware how RMagick handles memory. manipulate! takes care
50
+ # of freeing up memory for you, but for optimum memory usage you should
51
+ # use destructive operations as much as possible:
52
+ #
53
+ # DON'T DO THIS:
54
+ # img = img.resize_to_fit
55
+ #
56
+ # DO THIS INSTEAD:
57
+ # img.resize_to_fit!
58
+ #
59
+ # Read this for more information why:
60
+ #
61
+ # http://rubyforge.org/forum/forum.php?thread_id=1374&forum_id=1618
62
+ #
44
63
  module RMagick
45
-
64
+
46
65
  ##
47
66
  # Changes the image encoding format to the given format
48
67
  #
49
- # @see http://www.imagemagick.org/RMagick/doc/magick.html#formats
50
- # @param [#to_s] format an abreviation of the format
51
- # @yieldparam [Magick::Image] img additional manipulations to perform
52
- # @example
68
+ # See even http://www.imagemagick.org/RMagick/doc/magick.html#formats
69
+ #
70
+ # === Parameters
71
+ #
72
+ # [format (#to_s)] an abreviation of the format
73
+ #
74
+ # === Yields
75
+ #
76
+ # [Magick::Image] additional manipulations to perform
77
+ #
78
+ # === Examples
79
+ #
53
80
  # image.convert(:png)
54
- #
81
+ #
55
82
  def convert(format)
56
83
  manipulate! do |img|
57
84
  img.format = format.to_s.upcase
@@ -66,12 +93,17 @@ module CarrierWave
66
93
  # image may be shorter or narrower than specified in the smaller dimension
67
94
  # but will not be larger than the specified values."
68
95
  #
69
- # @see http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fit
96
+ # See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fit
97
+ #
98
+ # === Parameters
99
+ #
100
+ # [width (Integer)] the width to scale the image to
101
+ # [height (Integer)] the height to scale the image to
102
+ #
103
+ # === Yields
104
+ #
105
+ # [Magick::Image] additional manipulations to perform
70
106
  #
71
- # @param [Integer] width the width to scale the image to
72
- # @param [Integer] height the height to scale the image to
73
- # @yieldparam [Magick::Image] img additional manipulations to perform
74
- #
75
107
  def resize_to_fit(width, height)
76
108
  manipulate! do |img|
77
109
  img.resize_to_fit!(width, height)
@@ -79,7 +111,7 @@ module CarrierWave
79
111
  img
80
112
  end
81
113
  end
82
-
114
+
83
115
  alias_method :resize, :resize_to_fit
84
116
 
85
117
  ##
@@ -87,11 +119,16 @@ module CarrierWave
87
119
  # specified dimensions while retaining the aspect ratio of the original
88
120
  # image. If necessary, crop the image in the larger dimension."
89
121
  #
90
- # @see http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fill
122
+ # See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fill
123
+ #
124
+ # === Parameters
91
125
  #
92
- # @param [Integer] width the width to scale the image to
93
- # @param [Integer] height the height to scale the image to
94
- # @yieldparam [Magick::Image] img additional manipulations to perform
126
+ # [width (Integer)] the width to scale the image to
127
+ # [height (Integer)] the height to scale the image to
128
+ #
129
+ # === Yields
130
+ #
131
+ # [Magick::Image] additional manipulations to perform
95
132
  #
96
133
  def resize_to_fill(width, height)
97
134
  manipulate! do |img|
@@ -100,33 +137,40 @@ module CarrierWave
100
137
  img
101
138
  end
102
139
  end
103
-
140
+
104
141
  alias_method :crop_resized, :resize_to_fill
105
-
142
+
106
143
  ##
107
144
  # Resize the image to fit within the specified dimensions while retaining
108
- # the original aspect ratio. If necessary will pad the remaining area
145
+ # the original aspect ratio. If necessary, will pad the remaining area
109
146
  # with the given color, which defaults to transparent (for gif and png,
110
147
  # white for jpeg).
111
148
  #
112
- # @param [Integer] width the width to scale the image to
113
- # @param [Integer] height the height to scale the image to
114
- # @param [String, :transparent] background the color of the background as a hexcode, like "#ff45de"
115
- # @param [Magick::GravityType] gravity how to position the image
116
- # @yieldparam [Magick::Image] img additional manipulations to perform
149
+ # === Parameters
150
+ #
151
+ # [width (Integer)] the width to scale the image to
152
+ # [height (Integer)] the height to scale the image to
153
+ # [background (String, :transparent)] the color of the background as a hexcode, like "#ff45de"
154
+ # [gravity (Magick::GravityType)] how to position the image
155
+ #
156
+ # === Yields
157
+ #
158
+ # [Magick::Image] additional manipulations to perform
117
159
  #
118
160
  def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
119
161
  manipulate! do |img|
120
162
  img.resize_to_fit!(width, height)
121
163
  new_img = ::Magick::Image.new(width, height)
122
164
  if background == :transparent
123
- new_img = new_img.matte_floodfill(1, 1)
165
+ filled = new_img.matte_floodfill(1, 1)
124
166
  else
125
- new_img = new_img.color_floodfill(1, 1, ::Magick::Pixel.from_color(background))
167
+ filled = new_img.color_floodfill(1, 1, ::Magick::Pixel.from_color(background))
126
168
  end
127
- new_img = new_img.composite(img, gravity, ::Magick::OverCompositeOp)
128
- new_img = yield(new_img) if block_given?
129
- new_img
169
+ new_img.destroy!
170
+ filled.composite!(img, gravity, ::Magick::OverCompositeOp)
171
+ img.destroy!
172
+ filled = yield(filled) if block_given?
173
+ filled
130
174
  end
131
175
  end
132
176
 
@@ -135,11 +179,20 @@ module CarrierWave
135
179
  # and then pass each of its frames to the supplied block. It will then
136
180
  # save the image to disk.
137
181
  #
138
- # Note: This method assumes that the object responds to current_path
139
- # any class that this is mixed into must have a current_path method.
182
+ # === Gotcha
183
+ #
184
+ # This method assumes that the object responds to +current_path+.
185
+ # Any class that this module is mixed into must have a +current_path+ method.
186
+ # CarrierWave::Uploader does, so you won't need to worry about this in
187
+ # most cases.
188
+ #
189
+ # === Yields
140
190
  #
141
- # @yieldparam [Magick::Image] img manipulations to perform
142
- # @raise [CarrierWave::ProcessingError] if manipulation failed.
191
+ # [Magick::Image] manipulations to perform
192
+ #
193
+ # === Raises
194
+ #
195
+ # [CarrierWave::ProcessingError] if manipulation failed.
143
196
  #
144
197
  def manipulate!
145
198
  image = ::Magick::Image.read(current_path)
@@ -150,12 +203,15 @@ module CarrierWave
150
203
  list << yield( frame )
151
204
  end
152
205
  list.write(current_path)
206
+ list.destroy!
153
207
  else
154
- yield( image.first ).write(current_path)
208
+ frame = image.first
209
+ yield( frame ).write(current_path)
210
+ frame.destroy!
155
211
  end
156
212
  rescue ::Magick::ImageMagickError => e
157
213
  raise CarrierWave::ProcessingError.new("Failed to manipulate with rmagick, maybe it is not an image? Original Error: #{e}")
158
- end
159
-
214
+ end
215
+
160
216
  end # RMagick
161
- end # CarrierWave
217
+ end # CarrierWave
@@ -10,17 +10,18 @@ module CarrierWave
10
10
  #
11
11
  class SanitizedFile
12
12
 
13
- attr_accessor :file, :options
13
+ attr_accessor :file
14
14
 
15
- def initialize(file, options = {})
15
+ def initialize(file)
16
16
  self.file = file
17
- self.options = options
18
17
  end
19
18
 
20
19
  ##
21
20
  # Returns the filename as is, without sanizting it.
22
21
  #
23
- # @return [String] the unsanitized filename
22
+ # === Returns
23
+ #
24
+ # [String] the unsanitized filename
24
25
  #
25
26
  def original_filename
26
27
  return @original_filename if @original_filename
@@ -30,32 +31,38 @@ module CarrierWave
30
31
  File.basename(path)
31
32
  end
32
33
  end
33
-
34
+
34
35
  ##
35
36
  # Returns the filename, sanitized to strip out any evil characters.
36
37
  #
37
- # @return [String] the sanitized filename
38
+ # === Returns
39
+ #
40
+ # [String] the sanitized filename
38
41
  #
39
42
  def filename
40
43
  sanitize(original_filename) if original_filename
41
44
  end
42
-
45
+
43
46
  alias_method :identifier, :filename
44
-
47
+
45
48
  ##
46
49
  # Returns the part of the filename before the extension. So if a file is called 'test.jpeg'
47
50
  # this would return 'test'
48
51
  #
49
- # @return [String] the first part of the filename
52
+ # === Returns
53
+ #
54
+ # [String] the first part of the filename
50
55
  #
51
56
  def basename
52
57
  split_extension(filename)[0] if filename
53
58
  end
54
-
59
+
55
60
  ##
56
61
  # Returns the file extension
57
62
  #
58
- # @return [String] the extension
63
+ # === Returns
64
+ #
65
+ # [String] the extension
59
66
  #
60
67
  def extension
61
68
  split_extension(filename)[1] if filename
@@ -64,16 +71,18 @@ module CarrierWave
64
71
  ##
65
72
  # Returns the file's size.
66
73
  #
67
- # @return [Integer] the file's size in bytes.
74
+ # === Returns
75
+ #
76
+ # [Integer] the file's size in bytes.
68
77
  #
69
78
  def size
70
- if string?
79
+ if is_path?
71
80
  exists? ? File.size(path) : 0
72
81
  elsif @file.respond_to?(:size)
73
- @file.size
82
+ @file.size
74
83
  elsif path
75
84
  exists? ? File.size(path) : 0
76
- else
85
+ else
77
86
  0
78
87
  end
79
88
  end
@@ -81,53 +90,59 @@ module CarrierWave
81
90
  ##
82
91
  # Returns the full path to the file. If the file has no path, it will return nil.
83
92
  #
84
- # @return [String, nil] the path where the file is located.
93
+ # === Returns
94
+ #
95
+ # [String, nil] the path where the file is located.
85
96
  #
86
97
  def path
87
98
  unless @file.blank?
88
- if string?
99
+ if is_path?
89
100
  File.expand_path(@file)
90
101
  elsif @file.respond_to?(:path) and not @file.path.blank?
91
102
  File.expand_path(@file.path)
92
103
  end
93
104
  end
94
105
  end
95
-
106
+
96
107
  ##
97
- # Returns true if the file is supplied as a pathname or as a string.
108
+ # === Returns
98
109
  #
99
- # @return [Boolean]
110
+ # [Boolean] whether the file is supplied as a pathname or string.
100
111
  #
101
- def string?
112
+ def is_path?
102
113
  !!((@file.is_a?(String) || @file.is_a?(Pathname)) && !@file.blank?)
103
114
  end
104
115
 
105
116
  ##
106
- # Checks if the file is valid and has a non-zero size
117
+ # === Returns
107
118
  #
108
- # @return [Boolean]
119
+ # [Boolean] whether the file is valid and has a non-zero size
109
120
  #
110
121
  def empty?
111
122
  @file.nil? || self.size.nil? || self.size.zero?
112
123
  end
113
124
 
125
+ alias_method :blank?, :empty?
126
+
114
127
  ##
115
- # Checks if the file exists
128
+ # === Returns
116
129
  #
117
- # @return [Boolean]
130
+ # [Boolean] Whether the file exists
118
131
  #
119
132
  def exists?
120
133
  return File.exists?(self.path) if self.path
121
134
  return false
122
135
  end
123
-
136
+
124
137
  ##
125
138
  # Returns the contents of the file.
126
139
  #
127
- # @return [String] contents of the file
140
+ # === Returns
141
+ #
142
+ # [String] contents of the file
128
143
  #
129
144
  def read
130
- if string?
145
+ if is_path?
131
146
  File.read(@file)
132
147
  else
133
148
  @file.rewind if @file.respond_to?(:rewind)
@@ -138,9 +153,12 @@ module CarrierWave
138
153
  ##
139
154
  # Moves the file to the given path
140
155
  #
141
- # @param [String] new_path The path where the file should be moved.
156
+ # === Parameters
142
157
  #
143
- def move_to(new_path)
158
+ # [new_path (String)] The path where the file should be moved.
159
+ # [permissions (Integer)] permissions to set on the file in its new location.
160
+ #
161
+ def move_to(new_path, permissions=nil)
144
162
  return if self.empty?
145
163
  new_path = File.expand_path(new_path)
146
164
 
@@ -150,17 +168,23 @@ module CarrierWave
150
168
  else
151
169
  File.open(new_path, "wb") { |f| f.write(read) }
152
170
  end
153
- chmod!(new_path)
171
+ chmod!(new_path, permissions)
154
172
  self.file = new_path
155
173
  end
156
174
 
157
175
  ##
158
176
  # Creates a copy of this file and moves it to the given path. Returns the copy.
159
177
  #
160
- # @param [String] new_path The path where the file should be copied to.
178
+ # === Parameters
179
+ #
180
+ # [new_path (String)] The path where the file should be copied to.
181
+ # [permissions (Integer)] permissions to set on the copy
182
+ #
183
+ # === Returns
184
+ #
161
185
  # @return [CarrierWave::SanitizedFile] the location where the file will be stored.
162
186
  #
163
- def copy_to(new_path)
187
+ def copy_to(new_path, permissions=nil)
164
188
  return if self.empty?
165
189
  new_path = File.expand_path(new_path)
166
190
 
@@ -170,7 +194,7 @@ module CarrierWave
170
194
  else
171
195
  File.open(new_path, "wb") { |f| f.write(read) }
172
196
  end
173
- chmod!(new_path)
197
+ chmod!(new_path, permissions)
174
198
  self.class.new(new_path)
175
199
  end
176
200
 
@@ -184,7 +208,9 @@ module CarrierWave
184
208
  ##
185
209
  # Returns the content type of the file.
186
210
  #
187
- # @return [String] the content type of the file
211
+ # === Returns
212
+ #
213
+ # [String] the content type of the file
188
214
  #
189
215
  def content_type
190
216
  return @content_type if @content_type
@@ -192,26 +218,26 @@ module CarrierWave
192
218
  end
193
219
 
194
220
  private
195
-
221
+
196
222
  def file=(file)
197
223
  if file.is_a?(Hash)
198
- @file = file["tempfile"]
199
- @original_filename = file["filename"]
200
- @content_type = file["content_type"]
224
+ @file = file["tempfile"] || file[:tempfile]
225
+ @original_filename = file["filename"] || file[:filename]
226
+ @content_type = file["content_type"] || file[:content_type]
201
227
  else
202
228
  @file = file
203
229
  @original_filename = nil
204
230
  @content_type = nil
205
231
  end
206
232
  end
207
-
233
+
208
234
  # create the directory if it doesn't exist
209
235
  def mkdir!(path)
210
236
  FileUtils.mkdir_p(File.dirname(path)) unless File.exists?(File.dirname(path))
211
237
  end
212
-
213
- def chmod!(path)
214
- File.chmod(@options[:permissions], path) if @options[:permissions]
238
+
239
+ def chmod!(path, permissions)
240
+ File.chmod(permissions, path) if permissions
215
241
  end
216
242
 
217
243
  # Sanitize the filename, to prevent hacking
@@ -219,16 +245,16 @@ module CarrierWave
219
245
  name = name.gsub("\\", "/") # work-around for IE
220
246
  name = File.basename(name)
221
247
  name = name.gsub(/[^a-zA-Z0-9\.\-\+_]/,"_")
222
- name = "_#{name}" if name =~ /^\.+$/
248
+ name = "_#{name}" if name =~ /\A\.+\z/
223
249
  name = "unnamed" if name.size == 0
224
250
  return name.downcase
225
251
  end
226
252
 
227
253
  def split_extension(fn)
228
254
  # regular expressions to try for identifying extensions
229
- ext_regexps = [
230
- /^(.+)\.([^\.]{1,3}\.[^\.]{1,4})$/, # matches "something.tar.gz"
231
- /^(.+)\.([^\.]+)$/ # matches "something.jpg"
255
+ ext_regexps = [
256
+ /\A(.+)\.([^\.]{1,3}\.[^\.]{1,4})\z/, # matches "something.tar.gz"
257
+ /\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
232
258
  ]
233
259
  ext_regexps.each do |regexp|
234
260
  if fn =~ regexp
@@ -239,4 +265,4 @@ module CarrierWave
239
265
  end
240
266
 
241
267
  end # SanitizedFile
242
- end # CarrierWave
268
+ end # CarrierWave