carrierwave 2.2.1 → 3.0.1
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.
- checksums.yaml +4 -4
- data/README.md +137 -67
- data/lib/carrierwave/compatibility/paperclip.rb +4 -2
- data/lib/carrierwave/downloader/base.rb +27 -13
- data/lib/carrierwave/downloader/remote_file.rb +12 -9
- data/lib/carrierwave/locale/en.yml +5 -3
- data/lib/carrierwave/mount.rb +31 -50
- data/lib/carrierwave/mounter.rb +115 -50
- data/lib/carrierwave/orm/activerecord.rb +14 -60
- data/lib/carrierwave/processing/mini_magick.rb +15 -13
- data/lib/carrierwave/processing/rmagick.rb +11 -15
- data/lib/carrierwave/processing/vips.rb +12 -12
- data/lib/carrierwave/sanitized_file.rb +49 -77
- data/lib/carrierwave/storage/abstract.rb +5 -5
- data/lib/carrierwave/storage/file.rb +6 -5
- data/lib/carrierwave/storage/fog.rb +75 -67
- data/lib/carrierwave/test/matchers.rb +11 -7
- data/lib/carrierwave/uploader/cache.rb +18 -10
- data/lib/carrierwave/uploader/callbacks.rb +1 -1
- data/lib/carrierwave/uploader/configuration.rb +10 -4
- data/lib/carrierwave/uploader/{content_type_whitelist.rb → content_type_allowlist.rb} +17 -15
- data/lib/carrierwave/uploader/{content_type_blacklist.rb → content_type_denylist.rb} +19 -14
- data/lib/carrierwave/uploader/dimension.rb +66 -0
- data/lib/carrierwave/uploader/{extension_whitelist.rb → extension_allowlist.rb} +17 -15
- data/lib/carrierwave/uploader/{extension_blacklist.rb → extension_denylist.rb} +18 -13
- data/lib/carrierwave/uploader/file_size.rb +2 -2
- data/lib/carrierwave/uploader/processing.rb +42 -7
- data/lib/carrierwave/uploader/proxy.rb +16 -3
- data/lib/carrierwave/uploader/store.rb +44 -6
- data/lib/carrierwave/uploader/url.rb +1 -1
- data/lib/carrierwave/uploader/versions.rb +150 -132
- data/lib/carrierwave/uploader.rb +10 -8
- data/lib/carrierwave/utilities/file_name.rb +47 -0
- data/lib/carrierwave/utilities/uri.rb +14 -11
- data/lib/carrierwave/utilities.rb +1 -0
- data/lib/carrierwave/validations/active_model.rb +4 -6
- data/lib/carrierwave/version.rb +1 -1
- data/lib/carrierwave.rb +9 -17
- data/lib/generators/uploader_generator.rb +3 -3
- metadata +31 -43
- /data/lib/generators/templates/{uploader.rb → uploader.rb.erb} +0 -0
@@ -11,7 +11,7 @@ module CarrierWave
|
|
11
11
|
prepend Module.new {
|
12
12
|
def initialize(*)
|
13
13
|
super
|
14
|
-
@file, @filename, @cache_id, @identifier = nil
|
14
|
+
@file, @filename, @cache_id, @identifier, @deduplication_index = nil
|
15
15
|
end
|
16
16
|
}
|
17
17
|
end
|
@@ -34,9 +34,26 @@ module CarrierWave
|
|
34
34
|
@filename
|
35
35
|
end
|
36
36
|
|
37
|
+
##
|
38
|
+
# Returns a filename which doesn't conflict with already-stored files.
|
39
|
+
#
|
40
|
+
# === Returns
|
41
|
+
#
|
42
|
+
# [String] the filename with suffix added for deduplication
|
43
|
+
#
|
44
|
+
def deduplicated_filename
|
45
|
+
return unless filename
|
46
|
+
return filename unless @deduplication_index
|
47
|
+
|
48
|
+
parts = filename.split('.')
|
49
|
+
basename = parts.shift
|
50
|
+
basename.sub!(/ ?\(\d+\)\z/, '')
|
51
|
+
([basename.to_s + (@deduplication_index > 1 ? "(#{@deduplication_index})" : '')] + parts).join('.')
|
52
|
+
end
|
53
|
+
|
37
54
|
##
|
38
55
|
# Calculates the path where the file should be stored. If +for_file+ is given, it will be
|
39
|
-
# used as the
|
56
|
+
# used as the identifier, otherwise +CarrierWave::Uploader#identifier+ is assumed.
|
40
57
|
#
|
41
58
|
# === Parameters
|
42
59
|
#
|
@@ -46,7 +63,7 @@ module CarrierWave
|
|
46
63
|
#
|
47
64
|
# [String] the store path
|
48
65
|
#
|
49
|
-
def store_path(for_file=
|
66
|
+
def store_path(for_file=identifier)
|
50
67
|
File.join([store_dir, full_filename(for_file)].compact)
|
51
68
|
end
|
52
69
|
|
@@ -60,7 +77,7 @@ module CarrierWave
|
|
60
77
|
# [new_file (File, IOString, Tempfile)] any kind of file object
|
61
78
|
#
|
62
79
|
def store!(new_file=nil)
|
63
|
-
cache!(new_file) if new_file &&
|
80
|
+
cache!(new_file) if new_file && !cached?
|
64
81
|
if !cache_only && @file && @cache_id
|
65
82
|
with_callbacks(:store, new_file) do
|
66
83
|
new_file = storage.store!(@file)
|
@@ -69,7 +86,8 @@ module CarrierWave
|
|
69
86
|
cache_storage.delete_dir!(cache_path(nil))
|
70
87
|
end
|
71
88
|
@file = new_file
|
72
|
-
@
|
89
|
+
@identifier = storage.identifier
|
90
|
+
@cache_id = @deduplication_index = nil
|
73
91
|
@staged = false
|
74
92
|
end
|
75
93
|
end
|
@@ -89,10 +107,30 @@ module CarrierWave
|
|
89
107
|
end
|
90
108
|
end
|
91
109
|
|
110
|
+
##
|
111
|
+
# Look for a store path which doesn't collide with the given already-stored paths.
|
112
|
+
# It is done by adding a index number as the suffix.
|
113
|
+
# For example, if there's 'image.jpg' and the @deduplication_index is set to 2,
|
114
|
+
# The stored file will be named as 'image(2).jpg'.
|
115
|
+
#
|
116
|
+
# === Parameters
|
117
|
+
#
|
118
|
+
# [current_paths (Array[String])] List of paths for already-stored files
|
119
|
+
#
|
120
|
+
def deduplicate(current_paths)
|
121
|
+
@deduplication_index = nil
|
122
|
+
return unless current_paths.include?(store_path)
|
123
|
+
|
124
|
+
(1..current_paths.size + 1).each do |i|
|
125
|
+
@deduplication_index = i
|
126
|
+
break unless current_paths.include?(store_path)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
92
130
|
private
|
93
131
|
|
94
132
|
def full_filename(for_file)
|
95
|
-
for_file
|
133
|
+
forcing_extension(for_file)
|
96
134
|
end
|
97
135
|
|
98
136
|
def storage
|
@@ -1,6 +1,89 @@
|
|
1
|
+
require "active_support/core_ext/object/deep_dup"
|
2
|
+
|
1
3
|
module CarrierWave
|
2
4
|
module Uploader
|
3
5
|
module Versions
|
6
|
+
class Builder
|
7
|
+
def initialize(name)
|
8
|
+
@name = name
|
9
|
+
@options = {}
|
10
|
+
@blocks = []
|
11
|
+
@klass = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def configure(options, &block)
|
15
|
+
@options.merge!(options)
|
16
|
+
@blocks << block if block
|
17
|
+
@klass = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def build(superclass)
|
21
|
+
return @klass if @klass
|
22
|
+
@klass = Class.new(superclass)
|
23
|
+
superclass.const_set("#{@name.to_s.camelize}VersionUploader", @klass)
|
24
|
+
|
25
|
+
@klass.version_names += [@name]
|
26
|
+
@klass.versions = {}
|
27
|
+
@klass.processors = []
|
28
|
+
@klass.version_options = @options
|
29
|
+
@klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
30
|
+
# Define the enable_processing method for versions so they get the
|
31
|
+
# value from the parent class unless explicitly overwritten
|
32
|
+
def self.enable_processing(value=nil)
|
33
|
+
self.enable_processing = value if value
|
34
|
+
if defined?(@enable_processing) && !@enable_processing.nil?
|
35
|
+
@enable_processing
|
36
|
+
else
|
37
|
+
superclass.enable_processing
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Regardless of what is set in the parent uploader, do not enforce the
|
42
|
+
# move_to_cache config option on versions because it moves the original
|
43
|
+
# file to the version's target file.
|
44
|
+
#
|
45
|
+
# If you want to enforce this setting on versions, override this method
|
46
|
+
# in each version:
|
47
|
+
#
|
48
|
+
# version :thumb do
|
49
|
+
# def move_to_cache
|
50
|
+
# true
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
def move_to_cache
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
# Need to rely on the parent version's identifier, as versions don't have its own one.
|
59
|
+
def identifier
|
60
|
+
parent_version.identifier
|
61
|
+
end
|
62
|
+
RUBY
|
63
|
+
@blocks.each { |block| @klass.class_eval(&block) }
|
64
|
+
@klass
|
65
|
+
end
|
66
|
+
|
67
|
+
def deep_dup
|
68
|
+
other = dup
|
69
|
+
other.instance_variable_set(:@blocks, @blocks.dup)
|
70
|
+
other
|
71
|
+
end
|
72
|
+
|
73
|
+
def method_missing(name, *args)
|
74
|
+
super
|
75
|
+
rescue NoMethodError => e
|
76
|
+
raise e.exception <<~ERROR
|
77
|
+
#{e.message}
|
78
|
+
If you're trying to configure a version, do it inside a block like `version(:thumb) { self.#{name} #{args.map(&:inspect).join(', ')} }`.
|
79
|
+
ERROR
|
80
|
+
end
|
81
|
+
|
82
|
+
def respond_to_missing?(*)
|
83
|
+
super
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
4
87
|
extend ActiveSupport::Concern
|
5
88
|
|
6
89
|
include CarrierWave::Uploader::Callbacks
|
@@ -11,9 +94,8 @@ module CarrierWave
|
|
11
94
|
self.versions = {}
|
12
95
|
self.version_names = []
|
13
96
|
|
14
|
-
attr_accessor :
|
97
|
+
attr_accessor :parent_version
|
15
98
|
|
16
|
-
after :cache, :assign_parent_cache_id
|
17
99
|
after :cache, :cache_versions!
|
18
100
|
after :store, :store_versions!
|
19
101
|
after :remove, :remove_versions!
|
@@ -23,7 +105,7 @@ module CarrierWave
|
|
23
105
|
prepend Module.new {
|
24
106
|
def initialize(*)
|
25
107
|
super
|
26
|
-
@versions
|
108
|
+
@versions = nil
|
27
109
|
end
|
28
110
|
}
|
29
111
|
end
|
@@ -51,80 +133,33 @@ module CarrierWave
|
|
51
133
|
# process :scale => [200, 200]
|
52
134
|
# end
|
53
135
|
#
|
136
|
+
# version :square, :unless => :invalid_image_type? do
|
137
|
+
# process :scale => [100, 100]
|
138
|
+
# end
|
139
|
+
#
|
54
140
|
# end
|
55
141
|
#
|
56
142
|
def version(name, options = {}, &block)
|
57
143
|
name = name.to_sym
|
58
|
-
|
144
|
+
versions[name] ||= Builder.new(name)
|
145
|
+
versions[name].configure(options, &block)
|
59
146
|
|
60
|
-
|
61
|
-
|
62
|
-
|
147
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
148
|
+
def #{name}
|
149
|
+
versions[:#{name}]
|
150
|
+
end
|
151
|
+
RUBY
|
63
152
|
|
64
|
-
|
65
|
-
versions.each do |name, version|
|
66
|
-
version.class_eval(&block)
|
67
|
-
version.recursively_apply_block_to_versions(&block)
|
68
|
-
end
|
153
|
+
versions[name]
|
69
154
|
end
|
70
155
|
|
71
156
|
private
|
72
157
|
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
uploader.version_names += [name]
|
78
|
-
uploader.versions = {}
|
79
|
-
uploader.processors = []
|
80
|
-
uploader.version_options = options
|
81
|
-
|
82
|
-
uploader.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
83
|
-
# Define the enable_processing method for versions so they get the
|
84
|
-
# value from the parent class unless explicitly overwritten
|
85
|
-
def self.enable_processing(value=nil)
|
86
|
-
self.enable_processing = value if value
|
87
|
-
if defined?(@enable_processing) && !@enable_processing.nil?
|
88
|
-
@enable_processing
|
89
|
-
else
|
90
|
-
superclass.enable_processing
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# Regardless of what is set in the parent uploader, do not enforce the
|
95
|
-
# move_to_cache config option on versions because it moves the original
|
96
|
-
# file to the version's target file.
|
97
|
-
#
|
98
|
-
# If you want to enforce this setting on versions, override this method
|
99
|
-
# in each version:
|
100
|
-
#
|
101
|
-
# version :thumb do
|
102
|
-
# def move_to_cache
|
103
|
-
# true
|
104
|
-
# end
|
105
|
-
# end
|
106
|
-
#
|
107
|
-
def move_to_cache
|
108
|
-
false
|
109
|
-
end
|
110
|
-
RUBY
|
111
|
-
|
112
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
113
|
-
def #{name}
|
114
|
-
versions[:#{name}]
|
115
|
-
end
|
116
|
-
RUBY
|
117
|
-
else
|
118
|
-
uploader = Class.new(versions[name])
|
119
|
-
const_set("Uploader#{uploader.object_id}".tr('-', '_'), uploader)
|
120
|
-
uploader.processors = []
|
121
|
-
uploader.version_options = uploader.version_options.merge(options)
|
122
|
-
end
|
123
|
-
|
124
|
-
# Add the current version hash to class attribute :versions
|
125
|
-
self.versions = versions.merge(name => uploader)
|
158
|
+
def inherited(subclass)
|
159
|
+
# To prevent subclass version changes affecting superclass versions
|
160
|
+
subclass.versions = versions.deep_dup
|
161
|
+
super
|
126
162
|
end
|
127
|
-
|
128
163
|
end # ClassMethods
|
129
164
|
|
130
165
|
##
|
@@ -138,7 +173,7 @@ module CarrierWave
|
|
138
173
|
return @versions if @versions
|
139
174
|
@versions = {}
|
140
175
|
self.class.versions.each do |name, version|
|
141
|
-
@versions[name] = version.new(model, mounted_as)
|
176
|
+
@versions[name] = version.build(self.class).new(model, mounted_as)
|
142
177
|
@versions[name].parent_version = self
|
143
178
|
end
|
144
179
|
@versions
|
@@ -161,25 +196,44 @@ module CarrierWave
|
|
161
196
|
#
|
162
197
|
# === Returns
|
163
198
|
#
|
164
|
-
# [Boolean] True when the version exists according to its :if condition
|
199
|
+
# [Boolean] True when the version exists according to its :if or :unless condition
|
165
200
|
#
|
166
201
|
def version_exists?(name)
|
167
202
|
name = name.to_sym
|
168
203
|
|
169
|
-
return false unless
|
204
|
+
return false unless versions.has_key?(name)
|
170
205
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
206
|
+
if_condition = versions[name].class.version_options[:if]
|
207
|
+
unless_condition = versions[name].class.version_options[:unless]
|
208
|
+
|
209
|
+
if if_condition
|
210
|
+
if if_condition.respond_to?(:call)
|
211
|
+
if_condition.call(self, :version => name, :file => file)
|
212
|
+
else
|
213
|
+
send(if_condition, file)
|
214
|
+
end
|
215
|
+
elsif unless_condition
|
216
|
+
if unless_condition.respond_to?(:call)
|
217
|
+
!unless_condition.call(self, :version => name, :file => file)
|
175
218
|
else
|
176
|
-
send(
|
219
|
+
!send(unless_condition, file)
|
177
220
|
end
|
178
221
|
else
|
179
222
|
true
|
180
223
|
end
|
181
224
|
end
|
182
225
|
|
226
|
+
##
|
227
|
+
# Copies the parent's cache_id when caching a version file.
|
228
|
+
# This behavior is not essential but it makes easier to understand
|
229
|
+
# that the cached files are generated by the single upload attempt.
|
230
|
+
#
|
231
|
+
def cache!(*args)
|
232
|
+
self.cache_id = parent_version.cache_id if parent_version
|
233
|
+
|
234
|
+
super
|
235
|
+
end
|
236
|
+
|
183
237
|
##
|
184
238
|
# When given a version name as a parameter, will return the url for that version
|
185
239
|
# This also works with nested versions.
|
@@ -221,60 +275,25 @@ module CarrierWave
|
|
221
275
|
# versions if their parameters somehow have changed.
|
222
276
|
#
|
223
277
|
def recreate_versions!(*names)
|
224
|
-
#
|
225
|
-
#
|
226
|
-
# processing a cached file
|
227
|
-
#
|
228
|
-
# The call to store! will trigger the necessary callbacks to both
|
229
|
-
# process this version and all sub-versions
|
278
|
+
# As well as specified versions, we need to reprocess versions
|
279
|
+
# that are the source of another version.
|
230
280
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
reset_versions_to_cache_and_store
|
235
|
-
else
|
236
|
-
cache! if !cached?
|
237
|
-
store!
|
281
|
+
self.cache_id = CarrierWave.generate_cache_id
|
282
|
+
derived_versions.each do |name, v|
|
283
|
+
v.cache!(file) if names.empty? || !(v.descendant_version_names & names).empty?
|
238
284
|
end
|
239
|
-
|
240
|
-
|
241
|
-
private
|
242
|
-
|
243
|
-
def set_versions_to_cache_and_store(names)
|
244
|
-
@versions_to_cache = source_versions_of(names)
|
245
|
-
@versions_to_store = active_versions_with_names_in(@versions_to_cache + names)
|
246
|
-
end
|
247
|
-
|
248
|
-
def reset_versions_to_cache_and_store
|
249
|
-
@versions_to_cache, @versions_to_store = nil, nil
|
250
|
-
end
|
251
|
-
|
252
|
-
def versions_to_cache
|
253
|
-
@versions_to_cache || dependent_versions
|
254
|
-
end
|
255
|
-
|
256
|
-
def versions_to_store
|
257
|
-
@versions_to_store || active_versions
|
258
|
-
end
|
259
|
-
|
260
|
-
def source_versions_of(requested_names)
|
261
|
-
versions.inject([]) do |sources, (name, uploader)|
|
262
|
-
next sources unless requested_names.include?(name)
|
263
|
-
next sources unless source_name = uploader.class.version_options[:from_version]
|
264
|
-
|
265
|
-
sources << [source_name, versions[source_name]]
|
266
|
-
end.uniq
|
267
|
-
end
|
268
|
-
|
269
|
-
def active_versions_with_names_in(names)
|
270
|
-
active_versions.select do |pretendent_name, uploader|
|
271
|
-
names.include?(pretendent_name)
|
285
|
+
active_versions.each do |name, v|
|
286
|
+
v.store! if names.empty? || names.include?(name)
|
272
287
|
end
|
288
|
+
ensure
|
289
|
+
@cache_id = nil
|
273
290
|
end
|
274
291
|
|
275
|
-
|
276
|
-
|
277
|
-
|
292
|
+
protected
|
293
|
+
|
294
|
+
def descendant_version_names
|
295
|
+
[version_name] + derived_versions.flat_map do |name, version|
|
296
|
+
version.descendant_version_names
|
278
297
|
end
|
279
298
|
end
|
280
299
|
|
@@ -284,16 +303,18 @@ module CarrierWave
|
|
284
303
|
end
|
285
304
|
end
|
286
305
|
|
287
|
-
|
306
|
+
private
|
307
|
+
|
308
|
+
def derived_versions
|
288
309
|
active_versions.reject do |name, v|
|
289
310
|
v.class.version_options[:from_version]
|
290
|
-
end.to_a +
|
311
|
+
end.to_a + active_sibling_versions.select do |name, v|
|
291
312
|
v.class.version_options[:from_version] == self.class.version_names.last
|
292
313
|
end.to_a
|
293
314
|
end
|
294
315
|
|
295
|
-
def
|
296
|
-
parent_version
|
316
|
+
def active_sibling_versions
|
317
|
+
parent_version&.active_versions || []
|
297
318
|
end
|
298
319
|
|
299
320
|
def full_filename(for_file)
|
@@ -305,14 +326,11 @@ module CarrierWave
|
|
305
326
|
end
|
306
327
|
|
307
328
|
def cache_versions!(new_file)
|
308
|
-
|
309
|
-
v.send(:cache_id=, @cache_id)
|
310
|
-
v.cache!(new_file)
|
311
|
-
end
|
329
|
+
derived_versions.each { |name, v| v.cache!(new_file) }
|
312
330
|
end
|
313
331
|
|
314
332
|
def store_versions!(new_file)
|
315
|
-
|
333
|
+
active_versions.each { |name, v| v.store!(new_file) }
|
316
334
|
end
|
317
335
|
|
318
336
|
def remove_versions!
|
data/lib/carrierwave/uploader.rb
CHANGED
@@ -7,11 +7,12 @@ require "carrierwave/uploader/cache"
|
|
7
7
|
require "carrierwave/uploader/store"
|
8
8
|
require "carrierwave/uploader/download"
|
9
9
|
require "carrierwave/uploader/remove"
|
10
|
-
require "carrierwave/uploader/
|
11
|
-
require "carrierwave/uploader/
|
12
|
-
require "carrierwave/uploader/
|
13
|
-
require "carrierwave/uploader/
|
10
|
+
require "carrierwave/uploader/extension_allowlist"
|
11
|
+
require "carrierwave/uploader/extension_denylist"
|
12
|
+
require "carrierwave/uploader/content_type_allowlist"
|
13
|
+
require "carrierwave/uploader/content_type_denylist"
|
14
14
|
require "carrierwave/uploader/file_size"
|
15
|
+
require "carrierwave/uploader/dimension"
|
15
16
|
require "carrierwave/uploader/processing"
|
16
17
|
require "carrierwave/uploader/versions"
|
17
18
|
require "carrierwave/uploader/default_url"
|
@@ -52,11 +53,12 @@ module CarrierWave
|
|
52
53
|
include CarrierWave::Uploader::Store
|
53
54
|
include CarrierWave::Uploader::Download
|
54
55
|
include CarrierWave::Uploader::Remove
|
55
|
-
include CarrierWave::Uploader::
|
56
|
-
include CarrierWave::Uploader::
|
57
|
-
include CarrierWave::Uploader::
|
58
|
-
include CarrierWave::Uploader::
|
56
|
+
include CarrierWave::Uploader::ExtensionAllowlist
|
57
|
+
include CarrierWave::Uploader::ExtensionDenylist
|
58
|
+
include CarrierWave::Uploader::ContentTypeAllowlist
|
59
|
+
include CarrierWave::Uploader::ContentTypeDenylist
|
59
60
|
include CarrierWave::Uploader::FileSize
|
61
|
+
include CarrierWave::Uploader::Dimension
|
60
62
|
include CarrierWave::Uploader::Processing
|
61
63
|
include CarrierWave::Uploader::Versions
|
62
64
|
include CarrierWave::Uploader::DefaultUrl
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Utilities
|
3
|
+
module FileName
|
4
|
+
|
5
|
+
##
|
6
|
+
# Returns the part of the filename before the extension. So if a file is called 'test.jpeg'
|
7
|
+
# this would return 'test'
|
8
|
+
#
|
9
|
+
# === Returns
|
10
|
+
#
|
11
|
+
# [String] the first part of the filename
|
12
|
+
#
|
13
|
+
def basename
|
14
|
+
split_extension(filename)[0] if filename
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Returns the file extension
|
19
|
+
#
|
20
|
+
# === Returns
|
21
|
+
#
|
22
|
+
# [String] extension of file or "" if the file has no extension
|
23
|
+
#
|
24
|
+
def extension
|
25
|
+
split_extension(filename)[1] if filename
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def split_extension(filename)
|
31
|
+
# regular expressions to try for identifying extensions
|
32
|
+
extension_matchers = [
|
33
|
+
/\A(.+)\.(tar\.([glx]?z|bz2))\z/, # matches "something.tar.gz"
|
34
|
+
/\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
|
35
|
+
]
|
36
|
+
|
37
|
+
extension_matchers.each do |regexp|
|
38
|
+
if filename =~ regexp
|
39
|
+
return $1, $2
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
[filename, ""] # In case we weren't able to split the extension
|
44
|
+
end
|
45
|
+
end # FileName
|
46
|
+
end # Utilities
|
47
|
+
end # CarrierWave
|
@@ -3,20 +3,23 @@ require 'uri'
|
|
3
3
|
module CarrierWave
|
4
4
|
module Utilities
|
5
5
|
module Uri
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
# based on Ruby < 2.0's URI.encode
|
7
|
+
PATH_SAFE = URI::REGEXP::PATTERN::UNRESERVED + '\/'
|
8
|
+
PATH_UNSAFE = Regexp.new("[^#{PATH_SAFE}]", false)
|
9
|
+
NON_ASCII = /[^[:ascii:]]/.freeze
|
9
10
|
|
10
11
|
private
|
12
|
+
|
11
13
|
def encode_path(path)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
URI::DEFAULT_PARSER.escape(path, PATH_UNSAFE)
|
15
|
+
end
|
16
|
+
|
17
|
+
def encode_non_ascii(str)
|
18
|
+
URI::DEFAULT_PARSER.escape(str, NON_ASCII)
|
19
|
+
end
|
20
|
+
|
21
|
+
def decode_uri(str)
|
22
|
+
URI::DEFAULT_PARSER.unescape(str)
|
20
23
|
end
|
21
24
|
end # Uri
|
22
25
|
end # Utilities
|
@@ -12,8 +12,7 @@ module CarrierWave
|
|
12
12
|
|
13
13
|
def validate_each(record, attribute, value)
|
14
14
|
record.__send__("#{attribute}_processing_errors").each do |e|
|
15
|
-
message
|
16
|
-
record.errors.add(attribute, message)
|
15
|
+
record.errors.add(attribute, :carrierwave_processing_error, message: (e.message != e.class.to_s) && e.message)
|
17
16
|
end
|
18
17
|
end
|
19
18
|
end
|
@@ -22,8 +21,7 @@ module CarrierWave
|
|
22
21
|
|
23
22
|
def validate_each(record, attribute, value)
|
24
23
|
record.__send__("#{attribute}_integrity_errors").each do |e|
|
25
|
-
message
|
26
|
-
record.errors.add(attribute, message)
|
24
|
+
record.errors.add(attribute, :carrierwave_integrity_error, message: (e.message != e.class.to_s) && e.message)
|
27
25
|
end
|
28
26
|
end
|
29
27
|
end
|
@@ -32,8 +30,7 @@ module CarrierWave
|
|
32
30
|
|
33
31
|
def validate_each(record, attribute, value)
|
34
32
|
record.__send__("#{attribute}_download_errors").each do |e|
|
35
|
-
message
|
36
|
-
record.errors.add(attribute, message)
|
33
|
+
record.errors.add(attribute, :carrierwave_download_error, message: (e.message != e.class.to_s) && e.message)
|
37
34
|
end
|
38
35
|
end
|
39
36
|
end
|
@@ -58,6 +55,7 @@ module CarrierWave
|
|
58
55
|
def validates_processing_of(*attr_names)
|
59
56
|
validates_with ProcessingValidator, _merge_attributes(attr_names)
|
60
57
|
end
|
58
|
+
|
61
59
|
#
|
62
60
|
##
|
63
61
|
# Makes the record invalid if the remote file couldn't be downloaded
|
data/lib/carrierwave/version.rb
CHANGED