durran-carrierwave 0.3.2.3 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/Generators +1 -1
  2. data/History.txt +39 -2
  3. data/Manifest.txt +19 -5
  4. data/README.rdoc +180 -55
  5. data/Rakefile +11 -4
  6. data/features/grid_fs_storage.feature +32 -0
  7. data/features/step_definitions/general_steps.rb +6 -1
  8. data/features/support/activerecord.rb +1 -1
  9. data/features/support/env.rb +3 -16
  10. data/lib/carrierwave.rb +19 -74
  11. data/lib/carrierwave/compatibility/paperclip.rb +2 -2
  12. data/lib/carrierwave/core_ext/inheritable_attributes.rb +3 -3
  13. data/lib/carrierwave/mount.rb +36 -27
  14. data/lib/carrierwave/orm/activerecord.rb +3 -3
  15. data/lib/carrierwave/orm/datamapper.rb +2 -2
  16. data/lib/carrierwave/orm/mongoid.rb +23 -0
  17. data/lib/carrierwave/orm/mongomapper.rb +1 -1
  18. data/lib/carrierwave/orm/sequel.rb +4 -16
  19. data/lib/carrierwave/processing/image_science.rb +54 -25
  20. data/lib/carrierwave/processing/mini_magick.rb +269 -0
  21. data/lib/carrierwave/processing/rmagick.rb +4 -6
  22. data/lib/carrierwave/sanitized_file.rb +7 -6
  23. data/lib/carrierwave/storage/abstract.rb +0 -2
  24. data/lib/carrierwave/storage/file.rb +3 -5
  25. data/lib/carrierwave/storage/grid_fs.rb +92 -0
  26. data/lib/carrierwave/storage/right_s3.rb +183 -0
  27. data/lib/carrierwave/storage/s3.rb +37 -69
  28. data/lib/carrierwave/test/matchers.rb +22 -8
  29. data/lib/carrierwave/uploader.rb +2 -2
  30. data/lib/carrierwave/uploader/cache.rb +21 -18
  31. data/lib/carrierwave/uploader/configuration.rb +122 -0
  32. data/lib/carrierwave/uploader/default_url.rb +19 -0
  33. data/lib/carrierwave/uploader/processing.rb +4 -2
  34. data/lib/carrierwave/uploader/remove.rb +0 -1
  35. data/lib/carrierwave/uploader/store.rb +1 -68
  36. data/lib/carrierwave/uploader/url.rb +1 -1
  37. data/lib/carrierwave/uploader/versions.rb +3 -4
  38. data/{lib/generators → merb_generators}/uploader_generator.rb +0 -0
  39. data/rails_generators/uploader/templates/uploader.rb +4 -4
  40. data/spec/compatibility/paperclip_spec.rb +11 -2
  41. data/spec/fixtures/landscape.jpg +0 -0
  42. data/spec/fixtures/portrait.jpg +0 -0
  43. data/spec/mount_spec.rb +0 -25
  44. data/spec/orm/datamapper_spec.rb +55 -48
  45. data/spec/orm/mongoid_spec.rb +206 -0
  46. data/spec/orm/mongomapper_spec.rb +19 -1
  47. data/spec/orm/sequel_spec.rb +3 -12
  48. data/spec/processing/image_science_spec.rb +56 -0
  49. data/spec/processing/mini_magick_spec.rb +76 -0
  50. data/spec/processing/rmagick_spec.rb +68 -0
  51. data/spec/sanitized_file_spec.rb +84 -74
  52. data/spec/spec_helper.rb +1 -3
  53. data/spec/storage/grid_fs_spec.rb +78 -0
  54. data/spec/storage/right_s3_spec.rb +75 -0
  55. data/spec/storage/s3_spec.rb +83 -0
  56. data/spec/uploader/cache_spec.rb +1 -13
  57. data/spec/uploader/configuration_spec.rb +105 -0
  58. data/spec/uploader/{default_path_spec.rb → default_url_spec.rb} +22 -5
  59. data/spec/uploader/paths_spec.rb +1 -1
  60. data/spec/uploader/processing_spec.rb +11 -0
  61. data/spec/uploader/store_spec.rb +21 -47
  62. data/spec/uploader/versions_spec.rb +0 -8
  63. metadata +105 -17
  64. data/LICENSE +0 -8
  65. data/carrierwave.gemspec +0 -57
  66. data/lib/carrierwave/uploader/default_path.rb +0 -23
  67. data/lib/carrierwave/uploader/paths.rb +0 -27
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'activerecord'
3
+ require 'active_record'
4
4
 
5
5
  module CarrierWave
6
6
  module ActiveRecord
@@ -16,8 +16,8 @@ module CarrierWave
16
16
  alias_method :read_uploader, :read_attribute
17
17
  alias_method :write_uploader, :write_attribute
18
18
 
19
- validates_integrity_of column if uploader_options[column.to_sym][:validate_integrity]
20
- validates_processing_of column if uploader_options[column.to_sym][:validate_processing]
19
+ validates_integrity_of column if uploader_option(column.to_sym, :validate_integrity)
20
+ validates_processing_of column if uploader_option(column.to_sym, :validate_processing)
21
21
 
22
22
  after_save "store_#{column}!"
23
23
  before_save "write_#{column}_identifier"
@@ -15,9 +15,9 @@ module CarrierWave
15
15
 
16
16
  alias_method :read_uploader, :attribute_get
17
17
  alias_method :write_uploader, :attribute_set
18
-
19
18
  after :save, "store_#{column}!".to_sym
20
- before :save, "write_#{column}_identifier".to_sym
19
+ pre_hook = ::DataMapper.const_defined?(:Validate) ? :valid? : :save
20
+ before pre_hook, "write_#{column}_identifier".to_sym
21
21
  after :destroy, "remove_#{column}!".to_sym
22
22
  end
23
23
 
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ require 'mongoid'
3
+
4
+ module CarrierWave
5
+ module Mongoid
6
+ include CarrierWave::Mount
7
+ ##
8
+ # See +CarrierWave::Mount#mount_uploader+ for documentation
9
+ #
10
+ def mount_uploader(column, uploader, options={}, &block)
11
+ options[:mount_on] ||= "#{column}_filename"
12
+ field options[:mount_on]
13
+ super
14
+ alias_method :read_uploader, :read_attribute
15
+ alias_method :write_uploader, :write_attribute
16
+ after_save "store_#{column}!".to_sym
17
+ before_save "write_#{column}_identifier".to_sym
18
+ after_destroy "remove_#{column}!".to_sym
19
+ end
20
+ end # Mongoid
21
+ end # CarrierWave
22
+
23
+ Mongoid::Document::ClassMethods.send(:include, CarrierWave::Mongoid)
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- require 'mongomapper'
2
+ require 'mongo_mapper'
3
3
 
4
4
  module CarrierWave
5
5
  module MongoMapper
@@ -7,28 +7,16 @@ module CarrierWave
7
7
  include CarrierWave::Mount
8
8
 
9
9
  def mount_uploader(column, uploader)
10
+ raise "You need to use Sequel 3.0 or higher. Please upgrade." unless ::Sequel::Model.respond_to?(:plugin)
10
11
  super
11
12
 
12
13
  alias_method :read_uploader, :[]
13
14
  alias_method :write_uploader, :[]=
14
15
 
15
- if CarrierWave::Sequel.new_sequel?
16
- include CarrierWave::Sequel::Hooks
17
- include CarrierWave::Sequel::Validations
18
- else
19
- after_save "store_#{column}!"
20
- before_save "write_#{column}_identifier"
21
- before_destroy "remove_#{column}!"
22
- end
23
- end
24
-
25
- # Determine if we're using Sequel > 2.12
26
- #
27
- # ==== Returns
28
- # Bool:: True if Sequel 2.12 or higher False otherwise
29
- def self.new_sequel?
30
- ::Sequel::Model.respond_to?(:plugin)
16
+ include CarrierWave::Sequel::Hooks
17
+ include CarrierWave::Sequel::Validations
31
18
  end
19
+
32
20
  end # Sequel
33
21
  end # CarrierWave
34
22
 
@@ -5,27 +5,44 @@ require "image_science"
5
5
  module CarrierWave
6
6
  module ImageScience
7
7
 
8
- # Resize the image so that it will not exceed the dimensions passed
9
- # via geometry, geometry should be a string, formatted like '200x100' where
10
- # the first number is the height and the second is the width
11
- def resize!( geometry )
8
+ ##
9
+ # Resize the image to fit within the specified dimensions while retaining
10
+ # the original aspect ratio. The image may be shorter or narrower than
11
+ # specified in the smaller dimension but will not be larger than the
12
+ # specified values.
13
+ #
14
+ # See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fit
15
+ #
16
+ # === Parameters
17
+ #
18
+ # [width (Integer)] the width to scale the image to
19
+ # [height (Integer)] the height to scale the image to
20
+ #
21
+ def resize_to_fit(new_width, new_height)
12
22
  ::ImageScience.with_image(self.current_path) do |img|
13
- width, height = extract_dimensions(img.width, img.height, geometry)
23
+ width, height = extract_dimensions(img.width, img.height, new_width, new_height)
14
24
  img.resize( width, height ) do |file|
15
25
  file.save( self.current_path )
16
26
  end
17
27
  end
18
28
  end
19
29
 
20
- # Resize and crop the image so that it will have the exact dimensions passed
21
- # via geometry, geometry should be a string, formatted like '200x100' where
22
- # the first number is the height and the second is the width
23
- def crop_resized!( geometry )
30
+ ##
31
+ # Resize the image to fit within the specified dimensions while retaining
32
+ # the aspect ratio of the original image. If necessary, crop the image in
33
+ # the larger dimension.
34
+ #
35
+ # See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fill
36
+ #
37
+ # === Parameters
38
+ #
39
+ # [width (Integer)] the width to scale the image to
40
+ # [height (Integer)] the height to scale the image to
41
+ #
42
+ def resize_to_fill(new_width, new_height)
24
43
  ::ImageScience.with_image(self.current_path) do |img|
25
- new_width, new_height = geometry.split('x').map{|i| i.to_i }
26
-
27
- width, height = extract_dimensions_for_crop(img.width, img.height, geometry)
28
- x_offset, y_offset = extract_placement_for_crop(width, height, geometry)
44
+ width, height = extract_dimensions_for_crop(img.width, img.height, new_width, new_height)
45
+ x_offset, y_offset = extract_placement_for_crop(width, height, new_width, new_height)
29
46
 
30
47
  img.resize( width, height ) do |i2|
31
48
 
@@ -35,12 +52,29 @@ module CarrierWave
35
52
  end
36
53
  end
37
54
  end
55
+
56
+ ##
57
+ # Resize the image to fit within the specified dimensions while retaining
58
+ # the original aspect ratio. Will only resize the image if it is larger than the
59
+ # specified dimensions. The resulting image may be shorter or narrower than specified
60
+ # in the smaller dimension but will not be larger than the specified values.
61
+ #
62
+ # === Parameters
63
+ #
64
+ # [width (Integer)] the width to scale the image to
65
+ # [height (Integer)] the height to scale the image to
66
+ #
67
+ def resize_to_limit(new_width, new_height)
68
+ ::ImageScience.with_image(self.current_path) do |img|
69
+ if img.width > new_width or img.height > new_height
70
+ resize_to_fit(new_width, new_height)
71
+ end
72
+ end
73
+ end
38
74
 
39
- private
40
-
41
- def extract_dimensions(width, height, new_geometry, type = :resize)
42
- new_width, new_height = convert_geometry(new_geometry)
75
+ private
43
76
 
77
+ def extract_dimensions(width, height, new_width, new_height, type = :resize)
44
78
  aspect_ratio = width.to_f / height.to_f
45
79
  new_aspect_ratio = new_width / new_height
46
80
 
@@ -53,20 +87,15 @@ module CarrierWave
53
87
  [new_width, new_height].collect! { |v| v.round }
54
88
  end
55
89
 
56
- def extract_dimensions_for_crop(width, height, new_geometry)
57
- extract_dimensions(width, height, new_geometry, :crop)
90
+ def extract_dimensions_for_crop(width, height, new_width, new_height)
91
+ extract_dimensions(width, height, new_width, new_height, :crop)
58
92
  end
59
93
 
60
- def extract_placement_for_crop(width, height, new_geometry)
61
- new_width, new_height = convert_geometry(new_geometry)
94
+ def extract_placement_for_crop(width, height, new_width, new_height)
62
95
  x_offset = (width / 2.0) - (new_width / 2.0)
63
96
  y_offset = (height / 2.0) - (new_height / 2.0)
64
97
  [x_offset, y_offset].collect! { |v| v.round }
65
98
  end
66
99
 
67
- def convert_geometry(geometry)
68
- geometry.split('x').map{|i| i.to_f }
69
- end
70
-
71
100
  end # ImageScience
72
101
  end # CarrierWave
@@ -0,0 +1,269 @@
1
+ # encoding: utf-8
2
+
3
+ require 'mini_magick'
4
+
5
+ module CarrierWave
6
+
7
+ ##
8
+ # This module simplifies manipulation with MiniMagick by providing a set
9
+ # of convenient helper methods. If you want to use them, you'll need to
10
+ # require this file:
11
+ #
12
+ # require 'carrierwave/processing/mini_magick'
13
+ #
14
+ # And then include it in your uploader:
15
+ #
16
+ # class MyUploader < CarrierWave::Uploader::Base
17
+ # include CarrierWave::MiniMagick
18
+ # end
19
+ #
20
+ # You can now use the provided helpers:
21
+ #
22
+ # class MyUploader < CarrierWave::Uploader::Base
23
+ # include CarrierWave::MiniMagick
24
+ #
25
+ # process :resize_to_fit => [200, 200]
26
+ # end
27
+ #
28
+ # Or create your own helpers with the powerful manipulate! method. Check
29
+ # out the ImageMagick docs at http://www.imagemagick.org/script/command-line-options.php for more
30
+ # info
31
+ #
32
+ # class MyUploader < CarrierWave::Uploader::Base
33
+ # include CarrierWave::MiniMagick
34
+ #
35
+ # process :do_stuff => 10.0
36
+ #
37
+ # def do_stuff(blur_factor)
38
+ # manipulate! do |img|
39
+ # img = img.sepiatone
40
+ # img = img.auto_orient
41
+ # img = img.radial_blur blur_factor
42
+ # end
43
+ # end
44
+ # end
45
+ #
46
+ # === Note
47
+ #
48
+ # MiniMagick is a mini replacement for RMagick that uses the command line
49
+ # tool "mogrify" for image manipulation.
50
+ #
51
+ # You can find more information here:
52
+ #
53
+ # http://mini_magick.rubyforge.org/
54
+ # and
55
+ # http://github.com/probablycorey/mini_magick/
56
+ #
57
+ #
58
+ module MiniMagick
59
+
60
+ def self.included(base)
61
+ super
62
+ base.extend(ClassMethods)
63
+ end
64
+
65
+ module ClassMethods
66
+ def convert(format)
67
+ process :resize_to_limit => format
68
+ end
69
+
70
+ def resize_to_limit(width, height)
71
+ process :resize_to_limit => [width, height]
72
+ end
73
+
74
+ def resize_to_fit(width, height)
75
+ process :resize_to_fit => [width, height]
76
+ end
77
+
78
+ def resize_to_fill(width, height)
79
+ process :resize_to_fill => [width, height]
80
+ end
81
+
82
+ def resize_and_pad(width, height)
83
+ process :resize_to_fit => [width, height]
84
+ end
85
+
86
+ def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
87
+ process :resize_and_pad => [width, height, background, gravity]
88
+ end
89
+ end
90
+
91
+ ##
92
+ # Changes the image encoding format to the given format
93
+ #
94
+ # See http://www.imagemagick.org/script/command-line-options.php#format
95
+ #
96
+ # === Parameters
97
+ #
98
+ # [format (#to_s)] an abreviation of the format
99
+ #
100
+ # === Yields
101
+ #
102
+ # [MiniMagick::Image] additional manipulations to perform
103
+ #
104
+ # === Examples
105
+ #
106
+ # image.convert(:png)
107
+ #
108
+ def convert(format)
109
+ manipulate! do |img|
110
+ img.format(format.to_s.upcase)
111
+ img = yield(img) if block_given?
112
+ img
113
+ end
114
+ end
115
+
116
+ ##
117
+ # Resize the image to fit within the specified dimensions while retaining
118
+ # the original aspect ratio. Will only resize the image if it is larger than the
119
+ # specified dimensions. The resulting image may be shorter or narrower than specified
120
+ # in the smaller dimension but will not be larger than the specified values.
121
+ #
122
+ # === Parameters
123
+ #
124
+ # [width (Integer)] the width to scale the image to
125
+ # [height (Integer)] the height to scale the image to
126
+ #
127
+ # === Yields
128
+ #
129
+ # [MiniMagick::Image] additional manipulations to perform
130
+ #
131
+ def resize_to_limit(width, height)
132
+ manipulate! do |img|
133
+ img.resize "#{width}x#{height}>"
134
+ img = yield(img) if block_given?
135
+ img
136
+ end
137
+ end
138
+
139
+ ##
140
+ # From the RMagick documentation: "Resize the image to fit within the
141
+ # specified dimensions while retaining the original aspect ratio. The
142
+ # image may be shorter or narrower than specified in the smaller dimension
143
+ # but will not be larger than the specified values."
144
+ #
145
+ # See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fit
146
+ #
147
+ # === Parameters
148
+ #
149
+ # [width (Integer)] the width to scale the image to
150
+ # [height (Integer)] the height to scale the image to
151
+ #
152
+ # === Yields
153
+ #
154
+ # [MiniMagick::Image] additional manipulations to perform
155
+ #
156
+ def resize_to_fit(width, height)
157
+ manipulate! do |img|
158
+ img.resize "#{width}x#{height}"
159
+ img = yield(img) if block_given?
160
+ img
161
+ end
162
+ end
163
+
164
+ ##
165
+ # From the RMagick documentation: "Resize the image to fit within the
166
+ # specified dimensions while retaining the aspect ratio of the original
167
+ # image. If necessary, crop the image in the larger dimension."
168
+ #
169
+ # See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fill
170
+ #
171
+ # and
172
+ #
173
+ # http://www.clipclip.org/clips/detail/4365/jerrett-net-»-crop_resized-in-rmagick
174
+ #
175
+ # === Parameters
176
+ #
177
+ # [width (Integer)] the width to scale the image to
178
+ # [height (Integer)] the height to scale the image to
179
+ #
180
+ # === Yields
181
+ #
182
+ # [MiniMagick::Image] additional manipulations to perform
183
+ #
184
+ def resize_to_fill(width, height, gravity = 'Center')
185
+ manipulate! do |img|
186
+ cols, rows = img[:dimensions]
187
+ img.combine_options do |cmd|
188
+ if width != cols || height != rows
189
+ scale = [width/cols.to_f, height/rows.to_f].max
190
+ cols = (scale * (cols + 0.5)).round
191
+ rows = (scale * (rows + 0.5)).round
192
+ cmd.resize "#{cols}x#{rows}"
193
+ end
194
+ cmd.gravity gravity
195
+ cmd.extent "#{width}x#{height}" if cols != width || rows != height
196
+ end
197
+ img = yield(img) if block_given?
198
+ img
199
+ end
200
+ end
201
+
202
+ ##
203
+ # Resize the image to fit within the specified dimensions while retaining
204
+ # the original aspect ratio. If necessary, will pad the remaining area
205
+ # with the given color, which defaults to transparent (for gif and png,
206
+ # white for jpeg).
207
+ #
208
+ # See http://www.imagemagick.org/script/command-line-options.php#gravity
209
+ # for gravity options.
210
+ #
211
+ # === Parameters
212
+ #
213
+ # [width (Integer)] the width to scale the image to
214
+ # [height (Integer)] the height to scale the image to
215
+ # [background (String, :transparent)] the color of the background as a hexcode, like "#ff45de"
216
+ # [gravity (String)] how to position the image
217
+ #
218
+ # === Yields
219
+ #
220
+ # [MiniMagick::Image] additional manipulations to perform
221
+ #
222
+ def resize_and_pad(width, height, background=:transparent, gravity='Center')
223
+ manipulate! do |img|
224
+ img.combine_options do |cmd|
225
+ cmd.thumbnail "#{width}x#{height}>"
226
+ if background == :transparent
227
+ cmd.background "rgba(0, 0, 0, 0.0)"
228
+ else
229
+ cmd.background background
230
+ end
231
+ cmd.gravity gravity
232
+ cmd.extent "#{width}x#{height}"
233
+ end
234
+ img = yield(img) if block_given?
235
+ img
236
+ end
237
+ end
238
+
239
+ ##
240
+ # Manipulate the image with RMagick. This method will load up an image
241
+ # and then pass each of its frames to the supplied block. It will then
242
+ # save the image to disk.
243
+ #
244
+ # === Gotcha
245
+ #
246
+ # This method assumes that the object responds to +current_path+.
247
+ # Any class that this module is mixed into must have a +current_path+ method.
248
+ # CarrierWave::Uploader does, so you won't need to worry about this in
249
+ # most cases.
250
+ #
251
+ # === Yields
252
+ #
253
+ # [MiniMagick::Image] manipulations to perform
254
+ #
255
+ # === Raises
256
+ #
257
+ # [CarrierWave::ProcessingError] if manipulation failed.
258
+ #
259
+ def manipulate!
260
+ image = ::MiniMagick::Image.from_file(current_path)
261
+ image = yield(image)
262
+ image.write(current_path)
263
+ ::MiniMagick::Image.from_file(current_path)
264
+ rescue ::MiniMagick::MiniMagickError => e
265
+ raise CarrierWave::ProcessingError.new("Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: #{e}")
266
+ end
267
+
268
+ end # MiniMagick
269
+ end # CarrierWave