cloudfuji_paperclip 2.4.6 → 3.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.travis.yml +9 -6
- data/Appraisals +6 -6
- data/CONTRIBUTING.md +34 -2
- data/Gemfile +2 -0
- data/NEWS +90 -0
- data/README.md +62 -29
- data/RUNNING_TESTS.md +4 -0
- data/Rakefile +7 -2
- data/UPGRADING +14 -0
- data/features/basic_integration.feature +11 -7
- data/features/rake_tasks.feature +1 -1
- data/features/step_definitions/attachment_steps.rb +11 -2
- data/features/step_definitions/rails_steps.rb +17 -79
- data/features/support/env.rb +3 -0
- data/features/support/fakeweb.rb +7 -0
- data/features/support/file_helpers.rb +24 -0
- data/features/support/rails.rb +3 -3
- data/gemfiles/{rails3_1.gemfile → 3.0.gemfile} +3 -1
- data/gemfiles/{rails2.gemfile → 3.1.gemfile} +3 -1
- data/gemfiles/{rails3.gemfile → 3.2.gemfile} +3 -1
- data/images.rake +21 -0
- data/lib/cloudfuji_paperclip.rb +1 -0
- data/lib/generators/paperclip/paperclip_generator.rb +1 -2
- data/lib/paperclip.rb +54 -319
- data/lib/paperclip/attachment.rb +86 -107
- data/lib/paperclip/attachment_options.rb +9 -0
- data/lib/paperclip/callbacks.rb +30 -0
- data/lib/paperclip/errors.rb +27 -0
- data/lib/paperclip/geometry.rb +6 -4
- data/lib/paperclip/glue.rb +23 -0
- data/lib/paperclip/helpers.rb +71 -0
- data/lib/paperclip/instance_methods.rb +35 -0
- data/lib/paperclip/interpolations.rb +4 -4
- data/lib/paperclip/io_adapters/attachment_adapter.rb +69 -0
- data/lib/paperclip/io_adapters/file_adapter.rb +81 -0
- data/lib/paperclip/io_adapters/identity_adapter.rb +12 -0
- data/lib/paperclip/io_adapters/nil_adapter.rb +34 -0
- data/lib/paperclip/io_adapters/registry.rb +32 -0
- data/lib/paperclip/io_adapters/stringio_adapter.rb +64 -0
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +63 -0
- data/lib/paperclip/locales/en.yml +17 -0
- data/lib/paperclip/logger.rb +21 -0
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +5 -5
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +7 -7
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +11 -11
- data/lib/paperclip/missing_attachment_styles.rb +6 -9
- data/lib/paperclip/processor.rb +32 -17
- data/lib/paperclip/railtie.rb +13 -17
- data/lib/paperclip/storage/filesystem.rb +4 -13
- data/lib/paperclip/storage/fog.rb +33 -24
- data/lib/paperclip/storage/s3.rb +36 -28
- data/lib/paperclip/tempfile.rb +41 -0
- data/lib/paperclip/thumbnail.rb +2 -3
- data/lib/paperclip/validators.rb +45 -0
- data/lib/paperclip/validators/attachment_content_type_validator.rb +54 -0
- data/lib/paperclip/validators/attachment_presence_validator.rb +26 -0
- data/lib/paperclip/validators/attachment_size_validator.rb +102 -0
- data/lib/paperclip/version.rb +1 -1
- data/lib/tasks/paperclip.rake +4 -12
- data/paperclip.gemspec +15 -5
- data/test/adapter_registry_test.rb +32 -0
- data/test/attachment_adapter_test.rb +51 -0
- data/test/attachment_options_test.rb +27 -0
- data/test/attachment_test.rb +130 -46
- data/test/file_adapter_test.rb +88 -0
- data/test/generator_test.rb +78 -0
- data/test/geometry_test.rb +5 -5
- data/test/helper.rb +21 -22
- data/test/identity_adapter_test.rb +8 -0
- data/test/integration_test.rb +55 -102
- data/test/interpolations_test.rb +15 -5
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +23 -0
- data/test/matchers/validate_attachment_presence_matcher_test.rb +21 -0
- data/test/matchers/validate_attachment_size_matcher_test.rb +37 -2
- data/test/nil_adapter_test.rb +25 -0
- data/test/paperclip_missing_attachment_styles_test.rb +16 -0
- data/test/paperclip_test.rb +34 -183
- data/test/storage/filesystem_test.rb +27 -27
- data/test/storage/fog_test.rb +68 -12
- data/test/storage/s3_live_test.rb +79 -38
- data/test/storage/s3_test.rb +204 -34
- data/test/stringio_adapter_test.rb +42 -0
- data/test/thumbnail_test.rb +29 -8
- data/test/uploaded_file_adapter_test.rb +98 -0
- data/test/url_generator_test.rb +8 -8
- data/test/validators/attachment_content_type_validator_test.rb +192 -0
- data/test/validators/attachment_presence_validator_test.rb +85 -0
- data/test/validators/attachment_size_validator_test.rb +207 -0
- data/test/validators_test.rb +25 -0
- metadata +166 -59
- data/generators/paperclip/USAGE +0 -5
- data/generators/paperclip/paperclip_generator.rb +0 -27
- data/generators/paperclip/templates/paperclip_migration.rb.erb +0 -19
- data/init.rb +0 -4
- data/lib/paperclip/callback_compatibility.rb +0 -61
- data/lib/paperclip/iostream.rb +0 -45
- data/lib/paperclip/upfile.rb +0 -62
- data/rails/init.rb +0 -2
- data/test/.gitignore +0 -1
- data/test/fixtures/question?mark.png +0 -0
- data/test/iostream_test.rb +0 -71
- data/test/upfile_test.rb +0 -53
data/lib/paperclip/attachment.rb
CHANGED
@@ -7,33 +7,32 @@ module Paperclip
|
|
7
7
|
# when the model saves, deletes when the model is destroyed, and processes
|
8
8
|
# the file upon assignment.
|
9
9
|
class Attachment
|
10
|
-
include IOStream
|
11
|
-
|
12
10
|
def self.default_options
|
13
11
|
@default_options ||= {
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
12
|
+
:convert_options => {},
|
13
|
+
:default_style => :original,
|
14
|
+
:default_url => "/:attachment/:style/missing.png",
|
15
|
+
:restricted_characters => /[&$+,\/:;=?@<>\[\]\{\}\|\\\^~%# ]/,
|
16
|
+
:hash_data => ":class/:attachment/:id/:style/:updated_at",
|
17
|
+
:hash_digest => "SHA1",
|
18
|
+
:interpolator => Paperclip::Interpolations,
|
17
19
|
:only_process => [],
|
20
|
+
:path => ":rails_root/public:url",
|
21
|
+
:preserve_files => false,
|
18
22
|
:processors => [:thumbnail],
|
19
|
-
:convert_options => {},
|
20
23
|
:source_file_options => {},
|
21
|
-
:default_url => "/:attachment/:style/missing.png",
|
22
|
-
:default_style => :original,
|
23
24
|
:storage => :filesystem,
|
24
|
-
:
|
25
|
-
:
|
25
|
+
:styles => {},
|
26
|
+
:url => "/system/:class/:attachment/:id_partition/:style/:filename",
|
27
|
+
:url_generator => Paperclip::UrlGenerator,
|
26
28
|
:use_default_time_zone => true,
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:preserve_files => false,
|
30
|
-
:interpolator => Paperclip::Interpolations,
|
31
|
-
:url_generator => Paperclip::UrlGenerator
|
29
|
+
:use_timestamp => true,
|
30
|
+
:whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails]
|
32
31
|
}
|
33
32
|
end
|
34
33
|
|
35
|
-
attr_reader :name, :instance, :default_style, :convert_options, :queued_for_write, :whiny,
|
36
|
-
|
34
|
+
attr_reader :name, :instance, :default_style, :convert_options, :queued_for_write, :whiny,
|
35
|
+
:options, :interpolator, :source_file_options, :whiny
|
37
36
|
attr_accessor :post_processing
|
38
37
|
|
39
38
|
# Creates an Attachment object. +name+ is the name of the attachment,
|
@@ -89,28 +88,16 @@ module Paperclip
|
|
89
88
|
# new_user.avatar = old_user.avatar
|
90
89
|
def assign uploaded_file
|
91
90
|
ensure_required_accessors!
|
91
|
+
file = Paperclip.io_adapters.for(uploaded_file)
|
92
92
|
|
93
|
-
|
94
|
-
|
95
|
-
uploaded_file = uploaded_file.to_file(:original)
|
96
|
-
close_uploaded_file = uploaded_file.respond_to?(:close)
|
97
|
-
else
|
98
|
-
instance_write(:uploaded_file, uploaded_file) if uploaded_file
|
99
|
-
end
|
100
|
-
|
101
|
-
return nil unless valid_assignment?(uploaded_file)
|
93
|
+
self.clear(*@options[:only_process])
|
94
|
+
return nil if file.nil?
|
102
95
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
uploaded_filename ||= uploaded_file.original_filename
|
109
|
-
@queued_for_write[:original] = to_tempfile(uploaded_file)
|
110
|
-
instance_write(:file_name, uploaded_filename.strip)
|
111
|
-
instance_write(:content_type, uploaded_file.content_type.to_s.strip)
|
112
|
-
instance_write(:file_size, uploaded_file.size.to_i)
|
113
|
-
instance_write(:fingerprint, generate_fingerprint(uploaded_file))
|
96
|
+
@queued_for_write[:original] = file
|
97
|
+
instance_write(:file_name, cleanup_filename(file.original_filename))
|
98
|
+
instance_write(:content_type, file.content_type.to_s.strip)
|
99
|
+
instance_write(:file_size, file.size)
|
100
|
+
instance_write(:fingerprint, file.fingerprint) if instance_respond_to?(:fingerprint)
|
114
101
|
instance_write(:updated_at, Time.now)
|
115
102
|
|
116
103
|
@dirty = true
|
@@ -118,10 +105,8 @@ module Paperclip
|
|
118
105
|
post_process(*@options[:only_process]) if post_processing
|
119
106
|
|
120
107
|
# Reset the file size if the original file was reprocessed.
|
121
|
-
instance_write(:file_size, @queued_for_write[:original].size
|
122
|
-
instance_write(:fingerprint,
|
123
|
-
ensure
|
124
|
-
uploaded_file.close if close_uploaded_file
|
108
|
+
instance_write(:file_size, @queued_for_write[:original].size)
|
109
|
+
instance_write(:fingerprint, @queued_for_write[:original].fingerprint) if instance_respond_to?(:fingerprint)
|
125
110
|
end
|
126
111
|
|
127
112
|
# Returns the public URL of the attachment with a given style. This does
|
@@ -217,10 +202,14 @@ module Paperclip
|
|
217
202
|
# Clears out the attachment. Has the same effect as previously assigning
|
218
203
|
# nil to the attachment. Does NOT save. If you wish to clear AND save,
|
219
204
|
# use #destroy.
|
220
|
-
def clear
|
221
|
-
|
222
|
-
|
223
|
-
|
205
|
+
def clear(*styles_to_clear)
|
206
|
+
if styles_to_clear.any?
|
207
|
+
queue_some_for_delete(*styles_to_clear)
|
208
|
+
else
|
209
|
+
queue_all_for_delete
|
210
|
+
@queued_for_write = {}
|
211
|
+
@errors = {}
|
212
|
+
end
|
224
213
|
end
|
225
214
|
|
226
215
|
# Destroys the attachment. Has the same effect as previously assigning
|
@@ -250,10 +239,10 @@ module Paperclip
|
|
250
239
|
instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size)
|
251
240
|
end
|
252
241
|
|
253
|
-
# Returns the
|
254
|
-
# <attachment>
|
242
|
+
# Returns the fingerprint of the file, if one's defined. The fingerprint is
|
243
|
+
# stored in the <attachment>_fingerpring attribute of the model.
|
255
244
|
def fingerprint
|
256
|
-
instance_read(:fingerprint)
|
245
|
+
instance_read(:fingerprint)
|
257
246
|
end
|
258
247
|
|
259
248
|
# Returns the content_type of the file as originally assigned, and lives
|
@@ -277,60 +266,28 @@ module Paperclip
|
|
277
266
|
|
278
267
|
# Returns a unique hash suitable for obfuscating the URL of an otherwise
|
279
268
|
# publicly viewable attachment.
|
280
|
-
def
|
269
|
+
def hash_key(style_name = default_style)
|
281
270
|
raise ArgumentError, "Unable to generate hash without :hash_secret" unless @options[:hash_secret]
|
282
271
|
require 'openssl' unless defined?(OpenSSL)
|
283
272
|
data = interpolate(@options[:hash_data], style_name)
|
284
273
|
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@options[:hash_digest]).new, @options[:hash_secret], data)
|
285
274
|
end
|
286
275
|
|
287
|
-
def generate_fingerprint(source)
|
288
|
-
if source.respond_to?(:path) && source.path && !source.path.blank?
|
289
|
-
Digest::MD5.file(source.path).to_s
|
290
|
-
else
|
291
|
-
data = source.read
|
292
|
-
source.rewind if source.respond_to?(:rewind)
|
293
|
-
Digest::MD5.hexdigest(data)
|
294
|
-
end
|
295
|
-
end
|
296
|
-
|
297
|
-
# Paths and URLs can have a number of variables interpolated into them
|
298
|
-
# to vary the storage location based on name, id, style, class, etc.
|
299
|
-
# This method is a deprecated access into supplying and retrieving these
|
300
|
-
# interpolations. Future access should use either Paperclip.interpolates
|
301
|
-
# or extend the Paperclip::Interpolations module directly.
|
302
|
-
def self.interpolations
|
303
|
-
warn('[DEPRECATION] Paperclip::Attachment.interpolations is deprecated ' +
|
304
|
-
'and will be removed from future versions. ' +
|
305
|
-
'Use Paperclip.interpolates instead')
|
306
|
-
Paperclip::Interpolations
|
307
|
-
end
|
308
|
-
|
309
276
|
# This method really shouldn't be called that often. It's expected use is
|
310
277
|
# in the paperclip:refresh rake task and that's it. It will regenerate all
|
311
278
|
# thumbnails forcefully, by reobtaining the original file and going through
|
312
279
|
# the post-process again.
|
313
280
|
def reprocess!(*style_args)
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
new_original.write( old_original.respond_to?(:get) ? old_original.get : old_original.read )
|
318
|
-
new_original.rewind
|
319
|
-
|
320
|
-
@queued_for_write = { :original => new_original }
|
321
|
-
instance_write(:updated_at, Time.now)
|
322
|
-
post_process(*style_args)
|
323
|
-
|
324
|
-
old_original.close if old_original.respond_to?(:close)
|
325
|
-
old_original.unlink if old_original.respond_to?(:unlink)
|
326
|
-
|
281
|
+
saved_only_process, @options[:only_process] = @options[:only_process], style_args
|
282
|
+
begin
|
283
|
+
assign(self)
|
327
284
|
save
|
328
|
-
|
329
|
-
|
285
|
+
rescue Errno::EACCES => e
|
286
|
+
warn "#{e} - skipping file."
|
287
|
+
false
|
288
|
+
ensure
|
289
|
+
@options[:only_process] = saved_only_process
|
330
290
|
end
|
331
|
-
rescue Errno::EACCES => e
|
332
|
-
warn "#{e} - skipping file"
|
333
|
-
false
|
334
291
|
end
|
335
292
|
|
336
293
|
# Returns true if a file has been assigned.
|
@@ -340,6 +297,12 @@ module Paperclip
|
|
340
297
|
|
341
298
|
alias :present? :file?
|
342
299
|
|
300
|
+
# Determines whether the instance responds to this attribute. Used to prevent
|
301
|
+
# calculations on fields we won't even store.
|
302
|
+
def instance_respond_to?(attr)
|
303
|
+
instance.respond_to?(:"#{name}_#{attr}")
|
304
|
+
end
|
305
|
+
|
343
306
|
# Writes the attachment-specific attribute on the instance. For example,
|
344
307
|
# instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's
|
345
308
|
# "avatar_file_name" field (assuming the attachment is called avatar).
|
@@ -369,7 +332,7 @@ module Paperclip
|
|
369
332
|
def ensure_required_accessors! #:nodoc:
|
370
333
|
%w(file_name).each do |field|
|
371
334
|
unless @instance.respond_to?("#{name}_#{field}") && @instance.respond_to?("#{name}_#{field}=")
|
372
|
-
raise
|
335
|
+
raise Paperclip::Error.new("#{@instance.class} model missing required attr_accessor for '#{name}_#{field}'")
|
373
336
|
end
|
374
337
|
end
|
375
338
|
end
|
@@ -387,7 +350,7 @@ module Paperclip
|
|
387
350
|
begin
|
388
351
|
storage_module = Paperclip::Storage.const_get(storage_class_name)
|
389
352
|
rescue NameError
|
390
|
-
raise StorageMethodNotFound, "Cannot load storage module '#{storage_class_name}'"
|
353
|
+
raise Errors::StorageMethodNotFound, "Cannot load storage module '#{storage_class_name}'"
|
391
354
|
end
|
392
355
|
self.extend(storage_module)
|
393
356
|
end
|
@@ -420,26 +383,40 @@ module Paperclip
|
|
420
383
|
end
|
421
384
|
|
422
385
|
def post_process_styles(*style_args) #:nodoc:
|
423
|
-
styles.
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
(
|
386
|
+
post_process_style(:original, styles[:original]) if styles.include?(:original) && process_style?(:original, style_args)
|
387
|
+
styles.reject{ |name, style| name == :original }.each do |name, style|
|
388
|
+
post_process_style(name, style) if process_style?(name, style_args)
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
def post_process_style(name, style) #:nodoc:
|
393
|
+
begin
|
394
|
+
raise RuntimeError.new("Style #{name} has no processors defined.") if style.processors.blank?
|
395
|
+
@queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
|
396
|
+
Paperclip.processor(processor).make(file, style.processor_options, self)
|
434
397
|
end
|
398
|
+
@queued_for_write[name] = Paperclip.io_adapters.for(@queued_for_write[name])
|
399
|
+
rescue Paperclip::Error => e
|
400
|
+
log("An error was received while processing: #{e.inspect}")
|
401
|
+
(@errors[:processing] ||= []) << e.message if @options[:whiny]
|
435
402
|
end
|
436
403
|
end
|
437
404
|
|
405
|
+
def process_style?(style_name, style_args) #:nodoc:
|
406
|
+
style_args.empty? || style_args.include?(style_name)
|
407
|
+
end
|
408
|
+
|
438
409
|
def interpolate(pattern, style_name = default_style) #:nodoc:
|
439
410
|
interpolator.interpolate(pattern, self, style_name)
|
440
411
|
end
|
441
412
|
|
442
|
-
def
|
413
|
+
def queue_some_for_delete(*styles)
|
414
|
+
@queued_for_delete += styles.uniq.map do |style|
|
415
|
+
path(style) if exists?(style)
|
416
|
+
end.compact
|
417
|
+
end
|
418
|
+
|
419
|
+
def queue_all_for_delete #:nodoc:
|
443
420
|
return if @options[:preserve_files] || !file?
|
444
421
|
@queued_for_delete += [:original, *styles.keys].uniq.map do |style|
|
445
422
|
path(style) if exists?(style)
|
@@ -447,6 +424,7 @@ module Paperclip
|
|
447
424
|
instance_write(:file_name, nil)
|
448
425
|
instance_write(:content_type, nil)
|
449
426
|
instance_write(:file_size, nil)
|
427
|
+
instance_write(:fingerprint, nil)
|
450
428
|
instance_write(:updated_at, nil)
|
451
429
|
end
|
452
430
|
|
@@ -458,11 +436,12 @@ module Paperclip
|
|
458
436
|
|
459
437
|
# called by storage after the writes are flushed and before @queued_for_writes is cleared
|
460
438
|
def after_flush_writes
|
461
|
-
@queued_for_write.each do |style, file|
|
462
|
-
file.close unless file.closed?
|
463
|
-
file.unlink if file.respond_to?(:unlink) && file.path.present? && File.exist?(file.path)
|
464
|
-
end
|
465
439
|
end
|
466
440
|
|
441
|
+
def cleanup_filename(filename)
|
442
|
+
if @options[:restricted_characters]
|
443
|
+
filename.gsub(@options[:restricted_characters], '_')
|
444
|
+
end
|
445
|
+
end
|
467
446
|
end
|
468
447
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module Callbacks
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(Defining)
|
5
|
+
base.send(:include, Running)
|
6
|
+
end
|
7
|
+
|
8
|
+
module Defining
|
9
|
+
def define_paperclip_callbacks(*callbacks)
|
10
|
+
define_callbacks *[callbacks, {:terminator => "result == false"}].flatten
|
11
|
+
callbacks.each do |callback|
|
12
|
+
eval <<-end_callbacks
|
13
|
+
def before_#{callback}(*args, &blk)
|
14
|
+
set_callback(:#{callback}, :before, *args, &blk)
|
15
|
+
end
|
16
|
+
def after_#{callback}(*args, &blk)
|
17
|
+
set_callback(:#{callback}, :after, *args, &blk)
|
18
|
+
end
|
19
|
+
end_callbacks
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module Running
|
25
|
+
def run_paperclip_callbacks(callback, opts = nil, &block)
|
26
|
+
run_callbacks(callback, opts, &block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Paperclip
|
2
|
+
# A base error class for Paperclip. Most of the error that will be thrown
|
3
|
+
# from Paperclip will inherits from this class.
|
4
|
+
class Error < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
module Errors
|
8
|
+
# Will be thrown when a storage method is not found.
|
9
|
+
class StorageMethodNotFound < Paperclip::Error
|
10
|
+
end
|
11
|
+
|
12
|
+
# Will be thrown when a command or executable is not found.
|
13
|
+
class CommandNotFoundError < Paperclip::Error
|
14
|
+
end
|
15
|
+
|
16
|
+
# Will be thrown when ImageMagic cannot determine the uploaded file's
|
17
|
+
# metadata, usually this would mean the file is not an image.
|
18
|
+
class NotIdentifiedByImageMagickError < Paperclip::Error
|
19
|
+
end
|
20
|
+
|
21
|
+
# Will be thrown if the interpolation is creating an infinite loop. If you
|
22
|
+
# are creating an interpolator which might cause an infinite loop, you
|
23
|
+
# should be throwing this error upon the infinite loop as well.
|
24
|
+
class InfiniteInterpolationError < Paperclip::Error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/paperclip/geometry.rb
CHANGED
@@ -17,16 +17,18 @@ module Paperclip
|
|
17
17
|
# a Tempfile object, which would be eligible for file deletion when no longer referenced.
|
18
18
|
def self.from_file file
|
19
19
|
file_path = file.respond_to?(:path) ? file.path : file
|
20
|
-
raise(
|
20
|
+
raise(Errors::NotIdentifiedByImageMagickError.new("Cannot find the geometry of a file with a blank name")) if file_path.blank?
|
21
21
|
geometry = begin
|
22
|
-
|
22
|
+
silence_stream(STDERR) do
|
23
|
+
Paperclip.run("identify", "-format %wx%h :file", :file => "#{file_path}[0]")
|
24
|
+
end
|
23
25
|
rescue Cocaine::ExitStatusError
|
24
26
|
""
|
25
27
|
rescue Cocaine::CommandNotFoundError => e
|
26
|
-
raise
|
28
|
+
raise Errors::CommandNotFoundError.new("Could not run the `identify` command. Please install ImageMagick.")
|
27
29
|
end
|
28
30
|
parse(geometry) ||
|
29
|
-
raise(NotIdentifiedByImageMagickError.new("#{file_path} is not recognized by the 'identify' command."))
|
31
|
+
raise(Errors::NotIdentifiedByImageMagickError.new("#{file_path} is not recognized by the 'identify' command."))
|
30
32
|
end
|
31
33
|
|
32
34
|
# Parses a "WxH" formatted string, where W is the width and H is the height.
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'paperclip/callbacks'
|
2
|
+
require 'paperclip/validators'
|
3
|
+
require 'paperclip/schema'
|
4
|
+
|
5
|
+
module Paperclip
|
6
|
+
module Glue
|
7
|
+
def self.included base #:nodoc:
|
8
|
+
base.extend ClassMethods
|
9
|
+
base.send :include, Callbacks
|
10
|
+
base.send :include, Validators
|
11
|
+
base.class_attribute :attachment_definitions
|
12
|
+
|
13
|
+
if defined?(ActiveRecord)
|
14
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, Paperclip::Schema)
|
15
|
+
ActiveRecord::ConnectionAdapters::Table.send(:include, Paperclip::Schema)
|
16
|
+
ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Paperclip::Schema)
|
17
|
+
end
|
18
|
+
|
19
|
+
locale_path = Dir.glob(File.dirname(__FILE__) + "/locales/*.{rb,yml}")
|
20
|
+
I18n.load_path += locale_path unless I18n.load_path.include?(locale_path)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module Helpers
|
3
|
+
def configure
|
4
|
+
yield(self) if block_given?
|
5
|
+
end
|
6
|
+
|
7
|
+
def interpolates key, &block
|
8
|
+
Paperclip::Interpolations[key] = block
|
9
|
+
end
|
10
|
+
|
11
|
+
# The run method takes the name of a binary to run, the arguments to that binary
|
12
|
+
# and some options:
|
13
|
+
#
|
14
|
+
# :command_path -> A $PATH-like variable that defines where to look for the binary
|
15
|
+
# on the filesystem. Colon-separated, just like $PATH.
|
16
|
+
#
|
17
|
+
# :expected_outcodes -> An array of integers that defines the expected exit codes
|
18
|
+
# of the binary. Defaults to [0].
|
19
|
+
#
|
20
|
+
# :log_command -> Log the command being run when set to true (defaults to false).
|
21
|
+
# This will only log if logging in general is set to true as well.
|
22
|
+
#
|
23
|
+
# :swallow_stderr -> Set to true if you don't care what happens on STDERR.
|
24
|
+
#
|
25
|
+
def run(cmd, arguments = "", local_options = {})
|
26
|
+
command_path = options[:command_path]
|
27
|
+
Cocaine::CommandLine.path = ( Cocaine::CommandLine.path ? [Cocaine::CommandLine.path].flatten | [command_path] : command_path )
|
28
|
+
local_options = local_options.merge(:logger => logger) if logging? && (options[:log_command] || local_options[:log_command])
|
29
|
+
Cocaine::CommandLine.new(cmd, arguments, local_options).run
|
30
|
+
end
|
31
|
+
|
32
|
+
# Find all instances of the given Active Record model +klass+ with attachment +name+.
|
33
|
+
# This method is used by the refresh rake tasks.
|
34
|
+
def each_instance_with_attachment(klass, name)
|
35
|
+
unscope_method = class_for(klass).respond_to?(:unscoped) ? :unscoped : :with_exclusive_scope
|
36
|
+
class_for(klass).send(unscope_method) do
|
37
|
+
class_for(klass).find_each(:conditions => "#{name}_file_name is not null") do |instance|
|
38
|
+
yield(instance)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def class_for(class_name)
|
44
|
+
# Ruby 1.9 introduces an inherit argument for Module#const_get and
|
45
|
+
# #const_defined? and changes their default behavior.
|
46
|
+
# https://github.com/rails/rails/blob/v3.0.9/activesupport/lib/active_support/inflector/methods.rb#L89
|
47
|
+
if Module.method(:const_get).arity == 1
|
48
|
+
class_name.split('::').inject(Object) do |klass, partial_class_name|
|
49
|
+
klass.const_defined?(partial_class_name) ? klass.const_get(partial_class_name) : klass.const_missing(partial_class_name)
|
50
|
+
end
|
51
|
+
else
|
52
|
+
class_name.split('::').inject(Object) do |klass, partial_class_name|
|
53
|
+
klass.const_defined?(partial_class_name) ? klass.const_get(partial_class_name, false) : klass.const_missing(partial_class_name)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_for_url_clash(name,url,klass)
|
59
|
+
@names_url ||= {}
|
60
|
+
default_url = url || Attachment.default_options[:url]
|
61
|
+
if @names_url[name] && @names_url[name][:url] == default_url && @names_url[name][:class] != klass && @names_url[name][:url] !~ /:class/
|
62
|
+
log("Duplicate URL for #{name} with #{default_url}. This will clash with attachment defined in #{@names_url[name][:class]} class")
|
63
|
+
end
|
64
|
+
@names_url[name] = {:url => default_url, :class => klass}
|
65
|
+
end
|
66
|
+
|
67
|
+
def reset_duplicate_clash_check!
|
68
|
+
@names_url = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|