durran-carrierwave 0.3.2.3 → 0.4.3

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.
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