carrierwave 0.6.2 → 0.7.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.
- data/README.md +21 -9
- data/lib/carrierwave.rb +4 -3
- data/lib/carrierwave/locale/en.yml +3 -1
- data/lib/carrierwave/mount.rb +25 -6
- data/lib/carrierwave/orm/activerecord.rb +9 -2
- data/lib/carrierwave/processing/mime_types.rb +7 -1
- data/lib/carrierwave/processing/mini_magick.rb +11 -4
- data/lib/carrierwave/processing/rmagick.rb +80 -5
- data/lib/carrierwave/sanitized_file.rb +12 -8
- data/lib/carrierwave/storage/file.rb +2 -2
- data/lib/carrierwave/storage/fog.rb +28 -5
- data/lib/carrierwave/test/matchers.rb +88 -0
- data/lib/carrierwave/uploader.rb +1 -0
- data/lib/carrierwave/uploader/cache.rb +11 -4
- data/lib/carrierwave/uploader/configuration.rb +8 -1
- data/lib/carrierwave/uploader/download.rb +4 -1
- data/lib/carrierwave/uploader/extension_blacklist.rb +47 -0
- data/lib/carrierwave/uploader/extension_whitelist.rb +1 -1
- data/lib/carrierwave/uploader/url.rb +12 -2
- data/lib/carrierwave/validations/active_model.rb +19 -0
- data/lib/carrierwave/version.rb +1 -1
- metadata +90 -29
data/README.md
CHANGED
@@ -4,6 +4,7 @@ This gem provides a simple and extremely flexible way to upload files from Ruby
|
|
4
4
|
It works well with Rack based web applications, such as Ruby on Rails.
|
5
5
|
|
6
6
|
[![Build Status](https://secure.travis-ci.org/jnicklas/carrierwave.png)](http://travis-ci.org/jnicklas/carrierwave)
|
7
|
+
[![Code Quality](https://codeclimate.com/badge.png)](https://codeclimate.com/github/jnicklas/carrierwave)
|
7
8
|
|
8
9
|
## Information
|
9
10
|
|
@@ -28,6 +29,8 @@ In Rails, add it to your Gemfile:
|
|
28
29
|
gem 'carrierwave'
|
29
30
|
```
|
30
31
|
|
32
|
+
Finally, restart the server to apply the changes.
|
33
|
+
|
31
34
|
Note that CarrierWave is not compatible with Rails 2 as of version 0.5. If you want to use
|
32
35
|
Rails 2, please use the 0.4-stable branch on GitHub.
|
33
36
|
|
@@ -216,7 +219,7 @@ and cropped to exactly 200 by 200 pixels. The uploader could be used like this:
|
|
216
219
|
uploader = AvatarUploader.new
|
217
220
|
uploader.store!(my_file) # size: 1024x768
|
218
221
|
|
219
|
-
uploader.url # => '/url/to/my_file.png' # size:
|
222
|
+
uploader.url # => '/url/to/my_file.png' # size: 800x800
|
220
223
|
uploader.thumb.url # => '/url/to/thumb_my_file.png' # size: 200x200
|
221
224
|
```
|
222
225
|
|
@@ -297,8 +300,8 @@ of the original version, potentially resulting in faster processing.
|
|
297
300
|
Often you'll notice that uploaded files disappear when a validation fails.
|
298
301
|
CarrierWave has a feature that makes it easy to remember the uploaded file even
|
299
302
|
in that case. Suppose your `user` model has an uploader mounted on `avatar`
|
300
|
-
file, just add a hidden field called `avatar_cache
|
301
|
-
like this:
|
303
|
+
file, just add a hidden field called `avatar_cache` (don't forget to add it to
|
304
|
+
the attr_accessible list as necessary). In Rails, this would look like this:
|
302
305
|
|
303
306
|
```erb
|
304
307
|
<%= form_for @user, :html => {:multipart => true} do |f| %>
|
@@ -406,6 +409,7 @@ both globally and on a per-uploader basis:
|
|
406
409
|
```ruby
|
407
410
|
CarrierWave.configure do |config|
|
408
411
|
config.permissions = 0666
|
412
|
+
config.directory_permissions = 0777
|
409
413
|
config.storage = :file
|
410
414
|
end
|
411
415
|
```
|
@@ -507,9 +511,9 @@ CarrierWave.configure do |config|
|
|
507
511
|
:region => 'eu-west-1' # optional, defaults to 'us-east-1'
|
508
512
|
}
|
509
513
|
config.fog_directory = 'name_of_directory' # required
|
510
|
-
config.fog_host = 'https://assets.example.com' # optional, defaults to nil
|
511
514
|
config.fog_public = false # optional, defaults to true
|
512
515
|
config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
|
516
|
+
config.asset_host = 'https://assets.example.com' # optional, defaults to nil
|
513
517
|
end
|
514
518
|
```
|
515
519
|
|
@@ -550,7 +554,7 @@ This is *highly* recommended, as without it every request requires a lookup
|
|
550
554
|
of this information.
|
551
555
|
|
552
556
|
```ruby
|
553
|
-
config.
|
557
|
+
config.asset_host = "http://c000000.cdn.rackspacecloud.com"
|
554
558
|
```
|
555
559
|
|
556
560
|
In your uploader, set the storage to :fog
|
@@ -597,13 +601,13 @@ end
|
|
597
601
|
That's it! You can still use the `CarrierWave::Uploader#url` method to return
|
598
602
|
the url to the file on Google.
|
599
603
|
|
600
|
-
## Dynamic
|
604
|
+
## Dynamic Asset Host
|
601
605
|
|
602
|
-
The `
|
606
|
+
The `asset_host` config property can be assigned a proc (or anything that responds to `call`) for generating the host dynamically. The proc-compliant object gets an instance of the current `CarrierWave::Storage::Fog::File` or `CarrierWave::SanitizedFile` as its only argument.
|
603
607
|
|
604
608
|
```ruby
|
605
609
|
CarrierWave.configure do |config|
|
606
|
-
config.
|
610
|
+
config.asset_host = proc do |file|
|
607
611
|
identifier = # some logic
|
608
612
|
"http://#{identifier}.cdn.rackspacecloud.com"
|
609
613
|
end
|
@@ -704,6 +708,7 @@ errors:
|
|
704
708
|
messages:
|
705
709
|
carrierwave_processing_error: 'Cannot resize image.'
|
706
710
|
carrierwave_integrity_error: 'Not an image.'
|
711
|
+
carrierwave_download_error: 'Couldn't download image.'
|
707
712
|
```
|
708
713
|
|
709
714
|
## Large files
|
@@ -734,7 +739,9 @@ This has only been tested with the local filesystem store.
|
|
734
739
|
CarrierWave thrives on a large number of [contributors](https://github.com/jnicklas/carrierwave/contributors),
|
735
740
|
and pull requests are very welcome. Before submitting a pull request, please make sure that your changes are well tested.
|
736
741
|
|
737
|
-
|
742
|
+
First, make sure you have `imagemagick` and `ghostscript` installed.
|
743
|
+
|
744
|
+
Then, you'll need to install bundler and the gem dependencies:
|
738
745
|
|
739
746
|
gem install bundler
|
740
747
|
bundle install
|
@@ -761,6 +768,11 @@ You should now be able to run the remote tests:
|
|
761
768
|
|
762
769
|
Please test with the latest Ruby 1.8.x and 1.9.x versions using RVM if possible.
|
763
770
|
|
771
|
+
### Running active record tests
|
772
|
+
|
773
|
+
Make sure you have a local MySQL database named `carrierwave_test` with the username
|
774
|
+
`root` and empty password.
|
775
|
+
|
764
776
|
## License
|
765
777
|
|
766
778
|
Copyright (c) 2008-2012 Jonas Nicklas
|
data/lib/carrierwave.rb
CHANGED
@@ -15,8 +15,8 @@ module CarrierWave
|
|
15
15
|
CarrierWave::Uploader::Base.configure(&block)
|
16
16
|
end
|
17
17
|
|
18
|
-
def clean_cached_files!
|
19
|
-
CarrierWave::Uploader::Base.clean_cached_files!
|
18
|
+
def clean_cached_files!(seconds=60*60*24)
|
19
|
+
CarrierWave::Uploader::Base.clean_cached_files!(seconds)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -50,6 +50,7 @@ module CarrierWave
|
|
50
50
|
autoload :Versions, 'carrierwave/uploader/versions'
|
51
51
|
autoload :Remove, 'carrierwave/uploader/remove'
|
52
52
|
autoload :ExtensionWhitelist, 'carrierwave/uploader/extension_whitelist'
|
53
|
+
autoload :ExtensionBlacklist, 'carrierwave/uploader/extension_blacklist'
|
53
54
|
autoload :DefaultUrl, 'carrierwave/uploader/default_url'
|
54
55
|
autoload :Proxy, 'carrierwave/uploader/proxy'
|
55
56
|
autoload :Url, 'carrierwave/uploader/url'
|
@@ -95,7 +96,7 @@ elsif defined?(Rails)
|
|
95
96
|
end
|
96
97
|
|
97
98
|
elsif defined?(Sinatra)
|
98
|
-
if defined?(Padrino)
|
99
|
+
if defined?(Padrino) && defined?(PADRINO_ROOT)
|
99
100
|
CarrierWave.root = File.join(PADRINO_ROOT, "public")
|
100
101
|
else
|
101
102
|
|
@@ -3,7 +3,9 @@ en:
|
|
3
3
|
messages:
|
4
4
|
carrierwave_processing_error: failed to be processed
|
5
5
|
carrierwave_integrity_error: is not of an allowed file type
|
6
|
+
carrierwave_download_error: could not be downloaded
|
6
7
|
extension_white_list_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
|
8
|
+
extension_black_list_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
|
7
9
|
rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image? Original Error: %{e}"
|
8
10
|
mime_types_processing_error: "Failed to process file with MIME::Types, maybe not valid content-type? Original Error: %{e}"
|
9
|
-
mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
|
11
|
+
mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
|
data/lib/carrierwave/mount.rb
CHANGED
@@ -94,6 +94,7 @@ module CarrierWave
|
|
94
94
|
#
|
95
95
|
# [image_integrity_error] Returns an error object if the last file to be assigned caused an integrity error
|
96
96
|
# [image_processing_error] Returns an error object if the last file to be assigned caused a processing error
|
97
|
+
# [image_download_error] Returns an error object if the last file to be remotely assigned caused a download error
|
97
98
|
#
|
98
99
|
# [write_image_identifier] Uses the write_uploader method to set the identifier.
|
99
100
|
# [image_identifier] Reads out the identifier of the file
|
@@ -225,6 +226,10 @@ module CarrierWave
|
|
225
226
|
_mounter(:#{column}).processing_error
|
226
227
|
end
|
227
228
|
|
229
|
+
def #{column}_download_error
|
230
|
+
_mounter(:#{column}).download_error
|
231
|
+
end
|
232
|
+
|
228
233
|
def write_#{column}_identifier
|
229
234
|
_mounter(:#{column}).write_identifier
|
230
235
|
end
|
@@ -281,7 +286,7 @@ module CarrierWave
|
|
281
286
|
# this is an internal class, used by CarrierWave::Mount so that
|
282
287
|
# we don't pollute the model with a lot of methods.
|
283
288
|
class Mounter #:nodoc:
|
284
|
-
attr_reader :column, :record, :remote_url, :integrity_error, :processing_error
|
289
|
+
attr_reader :column, :record, :remote_url, :integrity_error, :processing_error, :download_error
|
285
290
|
attr_accessor :remove
|
286
291
|
|
287
292
|
def initialize(record, column, options={})
|
@@ -291,11 +296,11 @@ module CarrierWave
|
|
291
296
|
end
|
292
297
|
|
293
298
|
def write_identifier
|
294
|
-
if
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
+
return if record.frozen? || uploader.identifier.blank?
|
300
|
+
|
301
|
+
value = remove? ? '' : uploader.identifier
|
302
|
+
|
303
|
+
record.write_uploader(serialization_column, value)
|
299
304
|
end
|
300
305
|
|
301
306
|
def identifier
|
@@ -333,8 +338,22 @@ module CarrierWave
|
|
333
338
|
end
|
334
339
|
|
335
340
|
def remote_url=(url)
|
341
|
+
@download_error = nil
|
342
|
+
@integrity_error = nil
|
343
|
+
|
336
344
|
@remote_url = url
|
345
|
+
|
337
346
|
uploader.download!(url)
|
347
|
+
|
348
|
+
rescue CarrierWave::DownloadError => e
|
349
|
+
@download_error = e
|
350
|
+
raise e unless option(:ignore_download_errors)
|
351
|
+
rescue CarrierWave::ProcessingError => e
|
352
|
+
@processing_error = e
|
353
|
+
raise e unless option(:ignore_processing_errors)
|
354
|
+
rescue CarrierWave::IntegrityError => e
|
355
|
+
@integrity_error = e
|
356
|
+
raise e unless option(:ignore_integrity_errors)
|
338
357
|
end
|
339
358
|
|
340
359
|
def store!
|
@@ -23,10 +23,11 @@ module CarrierWave
|
|
23
23
|
|
24
24
|
validates_integrity_of column if uploader_option(column.to_sym, :validate_integrity)
|
25
25
|
validates_processing_of column if uploader_option(column.to_sym, :validate_processing)
|
26
|
+
validates_download_of column if uploader_option(column.to_sym, :validate_download)
|
26
27
|
|
27
28
|
after_save :"store_#{column}!"
|
28
29
|
before_save :"write_#{column}_identifier"
|
29
|
-
|
30
|
+
after_commit :"remove_#{column}!", :on => :destroy
|
30
31
|
before_update :"store_previous_model_for_#{column}"
|
31
32
|
after_save :"remove_previously_stored_#{column}"
|
32
33
|
|
@@ -43,6 +44,12 @@ module CarrierWave
|
|
43
44
|
super
|
44
45
|
end
|
45
46
|
|
47
|
+
def remove_#{column}!
|
48
|
+
super
|
49
|
+
_mounter(:#{column}).remove = true
|
50
|
+
_mounter(:#{column}).write_identifier
|
51
|
+
end
|
52
|
+
|
46
53
|
def serializable_hash(options=nil)
|
47
54
|
hash = {}
|
48
55
|
|
@@ -51,7 +58,7 @@ module CarrierWave
|
|
51
58
|
|
52
59
|
self.class.uploaders.each do |column, uploader|
|
53
60
|
if (!only && !except) || (only && only.include?(column.to_s)) || (except && !except.include?(column.to_s))
|
54
|
-
hash[column.to_s] = _mounter(
|
61
|
+
hash[column.to_s] = _mounter(column).uploader.serializable_hash
|
55
62
|
end
|
56
63
|
end
|
57
64
|
super(options).merge(hash)
|
@@ -32,6 +32,12 @@ module CarrierWave
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
GENERIC_CONTENT_TYPES = %w[application/octet-stream binary/octet-stream]
|
36
|
+
|
37
|
+
def generic_content_type?
|
38
|
+
GENERIC_CONTENT_TYPES.include? file.content_type
|
39
|
+
end
|
40
|
+
|
35
41
|
##
|
36
42
|
# Changes the file content_type using the mime-types gem
|
37
43
|
#
|
@@ -42,7 +48,7 @@ module CarrierWave
|
|
42
48
|
# false by default
|
43
49
|
#
|
44
50
|
def set_content_type(override=false)
|
45
|
-
if override || file.content_type.blank? ||
|
51
|
+
if override || file.content_type.blank? || generic_content_type?
|
46
52
|
new_content_type = ::MIME::Types.type_for(file.original_filename).first.to_s
|
47
53
|
if file.respond_to?(:content_type=)
|
48
54
|
file.content_type = new_content_type
|
@@ -169,10 +169,17 @@ module CarrierWave
|
|
169
169
|
cols, rows = img[:dimensions]
|
170
170
|
img.combine_options do |cmd|
|
171
171
|
if width != cols || height != rows
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
172
|
+
scale_x = width/cols.to_f
|
173
|
+
scale_y = height/rows.to_f
|
174
|
+
if scale_x >= scale_y
|
175
|
+
cols = (scale_x * (cols + 0.5)).round
|
176
|
+
rows = (scale_x * (rows + 0.5)).round
|
177
|
+
cmd.resize "#{cols}"
|
178
|
+
else
|
179
|
+
cols = (scale_y * (cols + 0.5)).round
|
180
|
+
rows = (scale_y * (rows + 0.5)).round
|
181
|
+
cmd.resize "x#{rows}"
|
182
|
+
end
|
176
183
|
end
|
177
184
|
cmd.gravity gravity
|
178
185
|
cmd.background "rgba(255,255,255,0.0)"
|
@@ -90,6 +90,10 @@ module CarrierWave
|
|
90
90
|
def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
|
91
91
|
process :resize_and_pad => [width, height, background, gravity]
|
92
92
|
end
|
93
|
+
|
94
|
+
def resize_to_geometry_string(geometry_string)
|
95
|
+
process :resize_to_geometry_string => [geometry_string]
|
96
|
+
end
|
93
97
|
end
|
94
98
|
|
95
99
|
##
|
@@ -223,6 +227,28 @@ module CarrierWave
|
|
223
227
|
end
|
224
228
|
end
|
225
229
|
|
230
|
+
##
|
231
|
+
# Resize the image per the provided geometry string.
|
232
|
+
#
|
233
|
+
# === Parameters
|
234
|
+
#
|
235
|
+
# [geometry_string (String)] the proportions in which to scale image
|
236
|
+
#
|
237
|
+
# === Yields
|
238
|
+
#
|
239
|
+
# [Magick::Image] additional manipulations to perform
|
240
|
+
#
|
241
|
+
def resize_to_geometry_string(geometry_string)
|
242
|
+
manipulate! do |img|
|
243
|
+
new_img = img.change_geometry(geometry_string) do |new_width, new_height|
|
244
|
+
img.resize(new_width, new_height)
|
245
|
+
end
|
246
|
+
destroy_image(img)
|
247
|
+
new_img = yield(new_img) if block_given?
|
248
|
+
new_img
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
226
252
|
##
|
227
253
|
# Manipulate the image with RMagick. This method will load up an image
|
228
254
|
# and then pass each of its frames to the supplied block. It will then
|
@@ -238,6 +264,45 @@ module CarrierWave
|
|
238
264
|
# === Yields
|
239
265
|
#
|
240
266
|
# [Magick::Image] manipulations to perform
|
267
|
+
# [Integer] Frame index if the image contains multiple frames
|
268
|
+
# [Hash] options, see below
|
269
|
+
#
|
270
|
+
# === Options
|
271
|
+
#
|
272
|
+
# The options argument to this method is also yielded as the third
|
273
|
+
# block argument.
|
274
|
+
#
|
275
|
+
# Currently, the following options are defined:
|
276
|
+
#
|
277
|
+
# ==== :write
|
278
|
+
# A hash of assignments to be evaluated in the block given to the RMagick write call.
|
279
|
+
#
|
280
|
+
# An example:
|
281
|
+
#
|
282
|
+
# manipulate! do |img, index, options|
|
283
|
+
# options[:write] = {
|
284
|
+
# :quality => 50,
|
285
|
+
# :depth => 8
|
286
|
+
# }
|
287
|
+
# img
|
288
|
+
# end
|
289
|
+
#
|
290
|
+
# This will translate to the following RMagick::Image#write call:
|
291
|
+
#
|
292
|
+
# image.write do |img|
|
293
|
+
# self.quality = 50
|
294
|
+
# self.depth = 8
|
295
|
+
# end
|
296
|
+
#
|
297
|
+
# ==== :read
|
298
|
+
# A hash of assignments to be given to the RMagick read call.
|
299
|
+
#
|
300
|
+
# The options available are identical to those for write, but are passed in directly, like this:
|
301
|
+
#
|
302
|
+
# manipulate! :read => { :density => 300 }
|
303
|
+
#
|
304
|
+
# ==== :format
|
305
|
+
# Specify the output format. If unset, the filename extension is used to determine the format.
|
241
306
|
#
|
242
307
|
# === Raises
|
243
308
|
#
|
@@ -245,13 +310,15 @@ module CarrierWave
|
|
245
310
|
#
|
246
311
|
def manipulate!(options={}, &block)
|
247
312
|
cache_stored_file! if !cached?
|
248
|
-
|
313
|
+
|
314
|
+
read_block = create_info_block(options[:read])
|
315
|
+
image = ::Magick::Image.read(current_path, &read_block)
|
249
316
|
|
250
317
|
frames = if image.size > 1
|
251
318
|
list = ::Magick::ImageList.new
|
252
319
|
image.each_with_index do |frame, index|
|
253
320
|
processed_frame = if block_given?
|
254
|
-
yield *[frame, index].take(block.arity)
|
321
|
+
yield *[frame, index, options].take(block.arity)
|
255
322
|
else
|
256
323
|
frame
|
257
324
|
end
|
@@ -260,14 +327,15 @@ module CarrierWave
|
|
260
327
|
block_given? ? list : list.append(true)
|
261
328
|
else
|
262
329
|
frame = image.first
|
263
|
-
frame = yield( *[frame, 0].take(block.arity) ) if block_given?
|
330
|
+
frame = yield( *[frame, 0, options].take(block.arity) ) if block_given?
|
264
331
|
frame
|
265
332
|
end
|
266
333
|
|
334
|
+
write_block = create_info_block(options[:write])
|
267
335
|
if options[:format]
|
268
|
-
frames.write("#{options[:format]}:#{current_path}")
|
336
|
+
frames.write("#{options[:format]}:#{current_path}", &write_block)
|
269
337
|
else
|
270
|
-
frames.write(current_path)
|
338
|
+
frames.write(current_path, &write_block)
|
271
339
|
end
|
272
340
|
destroy_image(frames)
|
273
341
|
rescue ::Magick::ImageMagickError => e
|
@@ -276,6 +344,13 @@ module CarrierWave
|
|
276
344
|
|
277
345
|
private
|
278
346
|
|
347
|
+
def create_info_block(options)
|
348
|
+
return nil unless options
|
349
|
+
assignments = options.map { |k, v| "self.#{k} = #{v}" }
|
350
|
+
code = "lambda { |img| " + assignments.join(";") + "}"
|
351
|
+
eval code
|
352
|
+
end
|
353
|
+
|
279
354
|
def destroy_image(image)
|
280
355
|
image.destroy! if image.respond_to?(:destroy!)
|
281
356
|
end
|
@@ -168,12 +168,13 @@ module CarrierWave
|
|
168
168
|
#
|
169
169
|
# [new_path (String)] The path where the file should be moved.
|
170
170
|
# [permissions (Integer)] permissions to set on the file in its new location.
|
171
|
+
# [directory_permissions (Integer)] permissions to set on created directories.
|
171
172
|
#
|
172
|
-
def move_to(new_path, permissions=nil)
|
173
|
+
def move_to(new_path, permissions=nil, directory_permissions=nil)
|
173
174
|
return if self.empty?
|
174
175
|
new_path = File.expand_path(new_path)
|
175
176
|
|
176
|
-
mkdir!(new_path)
|
177
|
+
mkdir!(new_path, directory_permissions)
|
177
178
|
if exists?
|
178
179
|
FileUtils.mv(path, new_path) unless new_path == path
|
179
180
|
else
|
@@ -191,16 +192,17 @@ module CarrierWave
|
|
191
192
|
#
|
192
193
|
# [new_path (String)] The path where the file should be copied to.
|
193
194
|
# [permissions (Integer)] permissions to set on the copy
|
195
|
+
# [directory_permissions (Integer)] permissions to set on created directories.
|
194
196
|
#
|
195
197
|
# === Returns
|
196
198
|
#
|
197
199
|
# @return [CarrierWave::SanitizedFile] the location where the file will be stored.
|
198
200
|
#
|
199
|
-
def copy_to(new_path, permissions=nil)
|
201
|
+
def copy_to(new_path, permissions=nil, directory_permissions=nil)
|
200
202
|
return if self.empty?
|
201
203
|
new_path = File.expand_path(new_path)
|
202
204
|
|
203
|
-
mkdir!(new_path)
|
205
|
+
mkdir!(new_path, directory_permissions)
|
204
206
|
if exists?
|
205
207
|
FileUtils.cp(path, new_path) unless new_path == path
|
206
208
|
else
|
@@ -226,7 +228,7 @@ module CarrierWave
|
|
226
228
|
#
|
227
229
|
def to_file
|
228
230
|
return @file if @file.is_a?(File)
|
229
|
-
File.open(path) if exists?
|
231
|
+
File.open(path, "rb") if exists?
|
230
232
|
end
|
231
233
|
|
232
234
|
##
|
@@ -278,8 +280,10 @@ module CarrierWave
|
|
278
280
|
end
|
279
281
|
|
280
282
|
# create the directory if it doesn't exist
|
281
|
-
def mkdir!(path)
|
282
|
-
|
283
|
+
def mkdir!(path, directory_permissions)
|
284
|
+
options = {}
|
285
|
+
options[:mode] = directory_permissions if directory_permissions
|
286
|
+
FileUtils.mkdir_p(File.dirname(path), options) unless File.exists?(File.dirname(path))
|
283
287
|
end
|
284
288
|
|
285
289
|
def chmod!(path, permissions)
|
@@ -299,7 +303,7 @@ module CarrierWave
|
|
299
303
|
def split_extension(filename)
|
300
304
|
# regular expressions to try for identifying extensions
|
301
305
|
extension_matchers = [
|
302
|
-
/\A(.+)\.(tar\.
|
306
|
+
/\A(.+)\.(tar\.([glx]?z|bz2))\z/, # matches "something.tar.gz"
|
303
307
|
/\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
|
304
308
|
]
|
305
309
|
|
@@ -29,9 +29,9 @@ module CarrierWave
|
|
29
29
|
def store!(file)
|
30
30
|
path = ::File.expand_path(uploader.store_path, uploader.root)
|
31
31
|
if uploader.move_to_store
|
32
|
-
file.move_to(path, uploader.permissions)
|
32
|
+
file.move_to(path, uploader.permissions, uploader.directory_permissions)
|
33
33
|
else
|
34
|
-
file.copy_to(path, uploader.permissions)
|
34
|
+
file.copy_to(path, uploader.permissions, uploader.directory_permissions)
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -20,7 +20,7 @@ module CarrierWave
|
|
20
20
|
# [:fog_directory] specifies name of directory to store data in, assumed to already exist
|
21
21
|
#
|
22
22
|
# [:fog_attributes] (optional) additional attributes to set on files
|
23
|
-
# [:
|
23
|
+
# [:fog_endpoint] (optional) non-default host to connect with
|
24
24
|
# [:fog_public] (optional) public readability, defaults to true
|
25
25
|
# [:fog_authenticated_url_expiration] (optional) time (in seconds) that authenticated urls
|
26
26
|
# will be valid, when fog_public is false and provider is AWS or Google, defaults to 600
|
@@ -102,8 +102,16 @@ module CarrierWave
|
|
102
102
|
|
103
103
|
def connection
|
104
104
|
@connection ||= begin
|
105
|
-
credentials = uploader.fog_credentials
|
106
|
-
|
105
|
+
options = credentials = uploader.fog_credentials
|
106
|
+
endpoint_url = if uploader.fog_endpoint.respond_to? :call
|
107
|
+
URI.parse( uploader.fog_endpoint.call(self) )
|
108
|
+
elsif uploader.fog_endpoint
|
109
|
+
URI.parse( uploader.fog_endpoint )
|
110
|
+
end
|
111
|
+
if host_string = endpoint_url && (endpoint_url.host || endpoint_url.to_s)
|
112
|
+
options.merge!( { :host => host_string } )
|
113
|
+
end
|
114
|
+
self.class.connection_cache[credentials] ||= ::Fog::Storage.new(options)
|
107
115
|
end
|
108
116
|
end
|
109
117
|
|
@@ -267,7 +275,7 @@ module CarrierWave
|
|
267
275
|
# [NilClass] no public url available
|
268
276
|
#
|
269
277
|
def public_url
|
270
|
-
if host = @uploader.
|
278
|
+
if host = @uploader.asset_host
|
271
279
|
if host.respond_to? :call
|
272
280
|
"#{host.call(self)}/#{path}"
|
273
281
|
else
|
@@ -278,7 +286,7 @@ module CarrierWave
|
|
278
286
|
case @uploader.fog_credentials[:provider]
|
279
287
|
when 'AWS'
|
280
288
|
# if directory is a valid subdomain, use that style for access
|
281
|
-
if @uploader.fog_directory.to_s =~ /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
|
289
|
+
if @uploader.fog_directory.to_s =~ /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
|
282
290
|
"https://#{@uploader.fog_directory}.s3.amazonaws.com/#{path}"
|
283
291
|
else
|
284
292
|
# directory is not a valid subdomain, so use path style for access
|
@@ -310,6 +318,21 @@ module CarrierWave
|
|
310
318
|
end
|
311
319
|
end
|
312
320
|
|
321
|
+
##
|
322
|
+
# Return file name, if available
|
323
|
+
#
|
324
|
+
# === Returns
|
325
|
+
#
|
326
|
+
# [String] file name
|
327
|
+
# or
|
328
|
+
# [NilClass] no file name available
|
329
|
+
#
|
330
|
+
def filename(options = {})
|
331
|
+
if file_url = url(options)
|
332
|
+
file_url.gsub(/.*\/(.*?$)/, '\1')
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
313
336
|
private
|
314
337
|
|
315
338
|
##
|
@@ -64,6 +64,34 @@ module CarrierWave
|
|
64
64
|
HavePermissions.new(expected)
|
65
65
|
end
|
66
66
|
|
67
|
+
class HaveDirectoryPermissions # :nodoc:
|
68
|
+
def initialize(expected)
|
69
|
+
@expected = expected
|
70
|
+
end
|
71
|
+
|
72
|
+
def matches?(actual)
|
73
|
+
@actual = actual
|
74
|
+
# Satisfy expectation here. Return false or raise an error if it's not met.
|
75
|
+
(File.stat(File.dirname @actual.path).mode & 0777) == @expected
|
76
|
+
end
|
77
|
+
|
78
|
+
def failure_message
|
79
|
+
"expected #{File.dirname @actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0777).to_s(8)}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def negative_failure_message
|
83
|
+
"expected #{File.dirname @actual.current_path.inspect} not to have permissions #{@expected.to_s(8)}, but it did"
|
84
|
+
end
|
85
|
+
|
86
|
+
def description
|
87
|
+
"have permissions #{@expected.to_s(8)}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def have_directory_permissions(expected)
|
92
|
+
HaveDirectoryPermissions.new(expected)
|
93
|
+
end
|
94
|
+
|
67
95
|
class BeNoLargerThan # :nodoc:
|
68
96
|
def initialize(width, height)
|
69
97
|
@width, @height = width, height
|
@@ -126,6 +154,66 @@ module CarrierWave
|
|
126
154
|
HaveDimensions.new(width, height)
|
127
155
|
end
|
128
156
|
|
157
|
+
class HaveHeight # :nodoc:
|
158
|
+
def initialize(height)
|
159
|
+
@height = height
|
160
|
+
end
|
161
|
+
|
162
|
+
def matches?(actual)
|
163
|
+
@actual = actual
|
164
|
+
# Satisfy expectation here. Return false or raise an error if it's not met.
|
165
|
+
image = ImageLoader.load_image(@actual.current_path)
|
166
|
+
@actual_height = image.height
|
167
|
+
@actual_height == @height
|
168
|
+
end
|
169
|
+
|
170
|
+
def failure_message
|
171
|
+
"expected #{@actual.current_path.inspect} to have an exact size of #{@height}, but it was #{@actual_height}."
|
172
|
+
end
|
173
|
+
|
174
|
+
def negative_failure_message
|
175
|
+
"expected #{@actual.current_path.inspect} not to have an exact size of #{@height}, but it did."
|
176
|
+
end
|
177
|
+
|
178
|
+
def description
|
179
|
+
"have an exact height of #{@height}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def have_height(height)
|
184
|
+
HaveHeight.new(height)
|
185
|
+
end
|
186
|
+
|
187
|
+
class HaveWidth # :nodoc:
|
188
|
+
def initialize(width)
|
189
|
+
@width = width
|
190
|
+
end
|
191
|
+
|
192
|
+
def matches?(actual)
|
193
|
+
@actual = actual
|
194
|
+
# Satisfy expectation here. Return false or raise an error if it's not met.
|
195
|
+
image = ImageLoader.load_image(@actual.current_path)
|
196
|
+
@actual_width = image.width
|
197
|
+
@actual_width == @width
|
198
|
+
end
|
199
|
+
|
200
|
+
def failure_message
|
201
|
+
"expected #{@actual.current_path.inspect} to have an exact size of #{@width}, but it was #{@actual_width}."
|
202
|
+
end
|
203
|
+
|
204
|
+
def negative_failure_message
|
205
|
+
"expected #{@actual.current_path.inspect} not to have an exact size of #{@width}, but it did."
|
206
|
+
end
|
207
|
+
|
208
|
+
def description
|
209
|
+
"have an exact width of #{@width}"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def have_width(width)
|
214
|
+
HaveWidth.new(width)
|
215
|
+
end
|
216
|
+
|
129
217
|
class BeNoWiderThan # :nodoc:
|
130
218
|
def initialize(width)
|
131
219
|
@width = width
|
data/lib/carrierwave/uploader.rb
CHANGED
@@ -34,6 +34,7 @@ module CarrierWave
|
|
34
34
|
include CarrierWave::Uploader::Download
|
35
35
|
include CarrierWave::Uploader::Remove
|
36
36
|
include CarrierWave::Uploader::ExtensionWhitelist
|
37
|
+
include CarrierWave::Uploader::ExtensionBlacklist
|
37
38
|
include CarrierWave::Uploader::Processing
|
38
39
|
include CarrierWave::Uploader::Versions
|
39
40
|
include CarrierWave::Uploader::DefaultUrl
|
@@ -70,8 +70,15 @@ module CarrierWave
|
|
70
70
|
# require the file to be stored on the local filesystem.
|
71
71
|
#
|
72
72
|
def cache_stored_file!
|
73
|
-
|
74
|
-
|
73
|
+
_content = file.read
|
74
|
+
if _content.is_a?(File) # could be if storage is Fog
|
75
|
+
sanitized = CarrierWave::Storage::Fog.new(self).retrieve!(File.basename(_content.path))
|
76
|
+
sanitized.read if sanitized.exists?
|
77
|
+
|
78
|
+
else
|
79
|
+
sanitized = SanitizedFile.new :tempfile => StringIO.new(file.read),
|
80
|
+
:filename => File.basename(path), :content_type => file.content_type
|
81
|
+
end
|
75
82
|
|
76
83
|
cache! sanitized
|
77
84
|
end
|
@@ -116,9 +123,9 @@ module CarrierWave
|
|
116
123
|
self.original_filename = new_file.filename
|
117
124
|
|
118
125
|
if move_to_cache
|
119
|
-
@file = new_file.move_to(cache_path, permissions)
|
126
|
+
@file = new_file.move_to(cache_path, permissions, directory_permissions)
|
120
127
|
else
|
121
|
-
@file = new_file.copy_to(cache_path, permissions)
|
128
|
+
@file = new_file.copy_to(cache_path, permissions, directory_permissions)
|
122
129
|
end
|
123
130
|
end
|
124
131
|
end
|
@@ -9,7 +9,9 @@ module CarrierWave
|
|
9
9
|
|
10
10
|
add_config :root
|
11
11
|
add_config :base_path
|
12
|
+
add_config :asset_host
|
12
13
|
add_config :permissions
|
14
|
+
add_config :directory_permissions
|
13
15
|
add_config :storage_engines
|
14
16
|
add_config :store_dir
|
15
17
|
add_config :cache_dir
|
@@ -24,15 +26,17 @@ module CarrierWave
|
|
24
26
|
add_config :fog_attributes
|
25
27
|
add_config :fog_credentials
|
26
28
|
add_config :fog_directory
|
27
|
-
add_config :
|
29
|
+
add_config :fog_endpoint
|
28
30
|
add_config :fog_public
|
29
31
|
add_config :fog_authenticated_url_expiration
|
30
32
|
|
31
33
|
# Mounting
|
32
34
|
add_config :ignore_integrity_errors
|
33
35
|
add_config :ignore_processing_errors
|
36
|
+
add_config :ignore_download_errors
|
34
37
|
add_config :validate_integrity
|
35
38
|
add_config :validate_processing
|
39
|
+
add_config :validate_download
|
36
40
|
add_config :mount_on
|
37
41
|
|
38
42
|
# set default values
|
@@ -103,6 +107,7 @@ module CarrierWave
|
|
103
107
|
def reset_config
|
104
108
|
configure do |config|
|
105
109
|
config.permissions = 0644
|
110
|
+
config.directory_permissions = 0755
|
106
111
|
config.storage_engines = {
|
107
112
|
:file => "CarrierWave::Storage::File",
|
108
113
|
:fog => "CarrierWave::Storage::Fog"
|
@@ -120,8 +125,10 @@ module CarrierWave
|
|
120
125
|
config.remove_previously_stored_files_after_update = true
|
121
126
|
config.ignore_integrity_errors = true
|
122
127
|
config.ignore_processing_errors = true
|
128
|
+
config.ignore_download_errors = true
|
123
129
|
config.validate_integrity = true
|
124
130
|
config.validate_processing = true
|
131
|
+
config.validate_download = true
|
125
132
|
config.root = lambda { CarrierWave.root }
|
126
133
|
config.base_path = CarrierWave.base_path
|
127
134
|
config.enable_processing = true
|
@@ -36,6 +36,9 @@ module CarrierWave
|
|
36
36
|
@file = @file.is_a?(String) ? StringIO.new(@file) : @file
|
37
37
|
end
|
38
38
|
@file
|
39
|
+
|
40
|
+
rescue
|
41
|
+
raise CarrierWave::DownloadError, "could not download file"
|
39
42
|
end
|
40
43
|
|
41
44
|
def method_missing(*args, &block)
|
@@ -67,7 +70,7 @@ module CarrierWave
|
|
67
70
|
# [url (String)] The URL where the remote file is stored
|
68
71
|
#
|
69
72
|
def process_uri(uri)
|
70
|
-
URI.parse(URI.escape(URI.unescape(uri))
|
73
|
+
URI.parse(URI.escape(URI.unescape(uri)))
|
71
74
|
end
|
72
75
|
|
73
76
|
end # Download
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Uploader
|
3
|
+
module ExtensionBlacklist
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before :cache, :check_blacklist!
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Override this method in your uploader to provide a black list of extensions which
|
12
|
+
# are prohibited to be uploaded. Compares the file's extension case insensitive.
|
13
|
+
# Furthermore, not only strings but Regexp are allowed as well.
|
14
|
+
#
|
15
|
+
# When using a Regexp in the black list, `\A` and `\z` are automatically added to
|
16
|
+
# the Regexp expression, also case insensitive.
|
17
|
+
#
|
18
|
+
# === Returns
|
19
|
+
|
20
|
+
# [NilClass, Array[String,Regexp]] a black list of extensions which are prohibited to be uploaded
|
21
|
+
#
|
22
|
+
# === Examples
|
23
|
+
#
|
24
|
+
# def extension_black_list
|
25
|
+
# %w(swf tiff)
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# Basically the same, but using a Regexp:
|
29
|
+
#
|
30
|
+
# def extension_black_list
|
31
|
+
# [/swf/, 'tiff']
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
|
35
|
+
def extension_black_list; end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def check_blacklist!(new_file)
|
40
|
+
extension = new_file.extension.to_s
|
41
|
+
if extension_black_list and extension_black_list.detect { |item| extension =~ /\A#{item}\z/i }
|
42
|
+
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_black_list_error", :extension => new_file.extension.inspect, :prohibited_types => extension_black_list.join(", "))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -40,7 +40,7 @@ module CarrierWave
|
|
40
40
|
def check_whitelist!(new_file)
|
41
41
|
extension = new_file.extension.to_s
|
42
42
|
if extension_white_list and not extension_white_list.detect { |item| extension =~ /\A#{item}\z/i }
|
43
|
-
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_white_list_error", :extension => new_file.extension.inspect, :allowed_types => extension_white_list.
|
43
|
+
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_white_list_error", :extension => new_file.extension.inspect, :allowed_types => extension_white_list.join(", "))
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -18,8 +18,18 @@ module CarrierWave
|
|
18
18
|
def url(options = {})
|
19
19
|
if file.respond_to?(:url) and not file.url.blank?
|
20
20
|
file.method(:url).arity == 0 ? file.url : file.url(options)
|
21
|
-
elsif
|
22
|
-
|
21
|
+
elsif file.respond_to?(:path)
|
22
|
+
path = file.path.gsub(File.expand_path(root), '')
|
23
|
+
|
24
|
+
if host = asset_host
|
25
|
+
if host.respond_to? :call
|
26
|
+
"#{host.call(file)}#{path}"
|
27
|
+
else
|
28
|
+
"#{host}#{path}"
|
29
|
+
end
|
30
|
+
else
|
31
|
+
(base_path || "") + path
|
32
|
+
end
|
23
33
|
end
|
24
34
|
end
|
25
35
|
|
@@ -30,6 +30,16 @@ module CarrierWave
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
class DownloadValidator < ::ActiveModel::EachValidator
|
34
|
+
|
35
|
+
def validate_each(record, attribute, value)
|
36
|
+
if e = record.send("#{attribute}_download_error")
|
37
|
+
message = (e.message == e.class.to_s) ? :carrierwave_download_error : e.message
|
38
|
+
record.errors.add(attribute, message)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
33
43
|
module HelperMethods
|
34
44
|
|
35
45
|
##
|
@@ -50,6 +60,15 @@ module CarrierWave
|
|
50
60
|
def validates_processing_of(*attr_names)
|
51
61
|
validates_with ProcessingValidator, _merge_attributes(attr_names)
|
52
62
|
end
|
63
|
+
#
|
64
|
+
##
|
65
|
+
# Makes the record invalid if the remote file couldn't be downloaded
|
66
|
+
#
|
67
|
+
# Accepts the usual parameters for validations in Rails (:if, :unless, etc...)
|
68
|
+
#
|
69
|
+
def validates_download_of(*attr_names)
|
70
|
+
validates_with DownloadValidator, _merge_attributes(attr_names)
|
71
|
+
end
|
53
72
|
end
|
54
73
|
|
55
74
|
included do
|
data/lib/carrierwave/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: carrierwave
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: 3.2.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.0
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: activemodel
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: 3.2.0
|
33
38
|
type: :runtime
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.2.0
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: mysql2
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '0'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: rails
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,21 +69,31 @@ dependencies:
|
|
54
69
|
version: 3.2.0
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 3.2.0
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: cucumber
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
|
-
- -
|
83
|
+
- - ~>
|
64
84
|
- !ruby/object:Gem::Version
|
65
85
|
version: 1.1.4
|
66
86
|
type: :development
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.1.4
|
69
94
|
- !ruby/object:Gem::Dependency
|
70
95
|
name: json
|
71
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
99
|
- - ! '>='
|
@@ -76,21 +101,31 @@ dependencies:
|
|
76
101
|
version: '0'
|
77
102
|
type: :development
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
80
110
|
- !ruby/object:Gem::Dependency
|
81
111
|
name: rspec
|
82
|
-
requirement:
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
83
113
|
none: false
|
84
114
|
requirements:
|
85
115
|
- - ~>
|
86
116
|
- !ruby/object:Gem::Version
|
87
|
-
version:
|
117
|
+
version: 2.10.0
|
88
118
|
type: :development
|
89
119
|
prerelease: false
|
90
|
-
version_requirements:
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 2.10.0
|
91
126
|
- !ruby/object:Gem::Dependency
|
92
127
|
name: sham_rack
|
93
|
-
requirement:
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
94
129
|
none: false
|
95
130
|
requirements:
|
96
131
|
- - ! '>='
|
@@ -98,10 +133,15 @@ dependencies:
|
|
98
133
|
version: '0'
|
99
134
|
type: :development
|
100
135
|
prerelease: false
|
101
|
-
version_requirements:
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
102
142
|
- !ruby/object:Gem::Dependency
|
103
143
|
name: timecop
|
104
|
-
requirement:
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
105
145
|
none: false
|
106
146
|
requirements:
|
107
147
|
- - ! '>='
|
@@ -109,10 +149,15 @@ dependencies:
|
|
109
149
|
version: '0'
|
110
150
|
type: :development
|
111
151
|
prerelease: false
|
112
|
-
version_requirements:
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
113
158
|
- !ruby/object:Gem::Dependency
|
114
159
|
name: fog
|
115
|
-
requirement:
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
116
161
|
none: false
|
117
162
|
requirements:
|
118
163
|
- - ! '>='
|
@@ -120,10 +165,15 @@ dependencies:
|
|
120
165
|
version: 1.3.1
|
121
166
|
type: :development
|
122
167
|
prerelease: false
|
123
|
-
version_requirements:
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 1.3.1
|
124
174
|
- !ruby/object:Gem::Dependency
|
125
175
|
name: mini_magick
|
126
|
-
requirement:
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
127
177
|
none: false
|
128
178
|
requirements:
|
129
179
|
- - ! '>='
|
@@ -131,10 +181,15 @@ dependencies:
|
|
131
181
|
version: '0'
|
132
182
|
type: :development
|
133
183
|
prerelease: false
|
134
|
-
version_requirements:
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ! '>='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
135
190
|
- !ruby/object:Gem::Dependency
|
136
191
|
name: rmagick
|
137
|
-
requirement:
|
192
|
+
requirement: !ruby/object:Gem::Requirement
|
138
193
|
none: false
|
139
194
|
requirements:
|
140
195
|
- - ! '>='
|
@@ -142,7 +197,12 @@ dependencies:
|
|
142
197
|
version: '0'
|
143
198
|
type: :development
|
144
199
|
prerelease: false
|
145
|
-
version_requirements:
|
200
|
+
version_requirements: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - ! '>='
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
146
206
|
description: Upload files in your Ruby applications, map them to a range of ORMs,
|
147
207
|
store them on different backends.
|
148
208
|
email:
|
@@ -169,6 +229,7 @@ files:
|
|
169
229
|
- lib/carrierwave/uploader/configuration.rb
|
170
230
|
- lib/carrierwave/uploader/default_url.rb
|
171
231
|
- lib/carrierwave/uploader/download.rb
|
232
|
+
- lib/carrierwave/uploader/extension_blacklist.rb
|
172
233
|
- lib/carrierwave/uploader/extension_whitelist.rb
|
173
234
|
- lib/carrierwave/uploader/mountable.rb
|
174
235
|
- lib/carrierwave/uploader/processing.rb
|
@@ -206,7 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
267
|
version: '0'
|
207
268
|
requirements: []
|
208
269
|
rubyforge_project: carrierwave
|
209
|
-
rubygems_version: 1.8.
|
270
|
+
rubygems_version: 1.8.23
|
210
271
|
signing_key:
|
211
272
|
specification_version: 3
|
212
273
|
summary: Ruby file upload library
|