paperclip 4.2.2 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.hound.yml +1066 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +18 -15
- data/Appraisals +20 -12
- data/CONTRIBUTING.md +19 -8
- data/Gemfile +4 -9
- data/LICENSE +1 -1
- data/NEWS +101 -31
- data/README.md +243 -159
- data/RELEASING.md +17 -0
- data/Rakefile +1 -1
- data/UPGRADING +12 -9
- data/features/basic_integration.feature +8 -4
- data/features/migration.feature +0 -24
- data/features/step_definitions/attachment_steps.rb +27 -21
- data/features/step_definitions/html_steps.rb +2 -2
- data/features/step_definitions/rails_steps.rb +11 -17
- data/features/step_definitions/s3_steps.rb +2 -2
- data/features/step_definitions/web_steps.rb +1 -103
- data/features/support/file_helpers.rb +2 -2
- data/gemfiles/4.2.awsv2.0.gemfile +17 -0
- data/gemfiles/4.2.awsv2.1.gemfile +17 -0
- data/gemfiles/{4.1.gemfile → 4.2.awsv2.gemfile} +4 -3
- data/gemfiles/5.0.awsv2.0.gemfile +17 -0
- data/gemfiles/5.0.awsv2.1.gemfile +17 -0
- data/gemfiles/{4.2.gemfile → 5.0.awsv2.gemfile} +4 -3
- data/lib/paperclip/attachment.rb +19 -16
- data/lib/paperclip/attachment_registry.rb +3 -2
- data/lib/paperclip/callbacks.rb +8 -6
- data/lib/paperclip/content_type_detector.rb +27 -11
- data/lib/paperclip/errors.rb +3 -1
- data/lib/paperclip/file_command_content_type_detector.rb +6 -8
- data/lib/paperclip/geometry_parser_factory.rb +1 -1
- data/lib/paperclip/glue.rb +1 -1
- data/lib/paperclip/has_attached_file.rb +9 -2
- data/lib/paperclip/helpers.rb +14 -10
- data/lib/paperclip/interpolations/plural_cache.rb +6 -5
- data/lib/paperclip/interpolations.rb +18 -13
- data/lib/paperclip/io_adapters/abstract_adapter.rb +1 -0
- data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/uri_adapter.rb +3 -1
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +4 -4
- data/lib/paperclip/media_type_spoof_detector.rb +2 -2
- data/lib/paperclip/rails_environment.rb +25 -0
- data/lib/paperclip/schema.rb +3 -9
- data/lib/paperclip/storage/fog.rb +21 -12
- data/lib/paperclip/storage/s3.rb +51 -50
- data/lib/paperclip/thumbnail.rb +2 -3
- data/lib/paperclip/validators/attachment_size_validator.rb +1 -7
- data/lib/paperclip/version.rb +3 -1
- data/lib/paperclip.rb +15 -4
- data/lib/tasks/paperclip.rake +17 -1
- data/paperclip.gemspec +18 -15
- data/spec/paperclip/attachment_definitions_spec.rb +1 -1
- data/spec/paperclip/attachment_processing_spec.rb +2 -4
- data/spec/paperclip/attachment_registry_spec.rb +84 -13
- data/spec/paperclip/attachment_spec.rb +91 -31
- data/spec/paperclip/content_type_detector_spec.rb +8 -1
- data/spec/paperclip/file_command_content_type_detector_spec.rb +0 -1
- data/spec/paperclip/geometry_spec.rb +1 -1
- data/spec/paperclip/glue_spec.rb +44 -0
- data/spec/paperclip/has_attached_file_spec.rb +24 -8
- data/spec/paperclip/integration_spec.rb +4 -3
- data/spec/paperclip/interpolations_spec.rb +16 -13
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +2 -1
- data/spec/paperclip/io_adapters/file_adapter_spec.rb +4 -1
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +12 -0
- data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +4 -0
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +27 -0
- data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +10 -0
- data/spec/paperclip/media_type_spoof_detector_spec.rb +34 -11
- data/spec/paperclip/paperclip_spec.rb +4 -29
- data/spec/paperclip/plural_cache_spec.rb +17 -16
- data/spec/paperclip/rails_environment_spec.rb +33 -0
- data/spec/paperclip/storage/fog_spec.rb +42 -3
- data/spec/paperclip/storage/s3_live_spec.rb +8 -4
- data/spec/paperclip/storage/s3_spec.rb +255 -180
- data/spec/paperclip/tempfile_factory_spec.rb +4 -0
- data/spec/paperclip/thumbnail_spec.rb +16 -0
- data/spec/paperclip/url_generator_spec.rb +1 -1
- data/spec/paperclip/validators/attachment_size_validator_spec.rb +26 -20
- data/spec/paperclip/validators_spec.rb +3 -3
- data/spec/spec_helper.rb +6 -1
- data/spec/support/assertions.rb +7 -0
- data/spec/support/fake_model.rb +4 -0
- data/spec/support/fixtures/empty.xlsx +0 -0
- data/spec/support/matchers/have_column.rb +11 -2
- data/spec/support/model_reconstruction.rb +9 -1
- data/spec/support/reporting.rb +11 -0
- metadata +105 -54
- data/RUNNING_TESTS.md +0 -4
- data/cucumber/paperclip_steps.rb +0 -6
- data/gemfiles/3.2.gemfile +0 -19
- data/gemfiles/4.0.gemfile +0 -19
- data/lib/paperclip/locales/de.yml +0 -18
- data/lib/paperclip/locales/es.yml +0 -18
- data/lib/paperclip/locales/ja.yml +0 -18
- data/lib/paperclip/locales/pt-BR.yml +0 -18
- data/lib/paperclip/locales/zh-CN.yml +0 -18
- data/lib/paperclip/locales/zh-HK.yml +0 -18
- data/lib/paperclip/locales/zh-TW.yml +0 -18
- data/spec/support/mock_model.rb +0 -2
- data/spec/support/rails_helpers.rb +0 -7
data/lib/paperclip/attachment.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
require 'uri'
|
|
3
3
|
require 'paperclip/url_generator'
|
|
4
4
|
require 'active_support/deprecation'
|
|
5
|
+
require 'active_support/core_ext/string/inflections'
|
|
5
6
|
|
|
6
7
|
module Paperclip
|
|
7
8
|
# The Attachment class manages the files for a given attachment. It saves
|
|
@@ -49,7 +50,8 @@ module Paperclip
|
|
|
49
50
|
# +url+ - a relative URL of the attachment. This is interpolated using +interpolator+
|
|
50
51
|
# +path+ - where on the filesystem to store the attachment. This is interpolated using +interpolator+
|
|
51
52
|
# +styles+ - a hash of options for processing the attachment. See +has_attached_file+ for the details
|
|
52
|
-
# +only_process+ - style args to be run through the post-processor. This defaults to the empty list
|
|
53
|
+
# +only_process+ - style args to be run through the post-processor. This defaults to the empty list (which is
|
|
54
|
+
# a special case that indicates all styles should be processed)
|
|
53
55
|
# +default_url+ - a URL for the missing image
|
|
54
56
|
# +default_style+ - the style to use when an argument is not specified e.g. #url, #path
|
|
55
57
|
# +storage+ - the storage mechanism. Defaults to :filesystem
|
|
@@ -68,7 +70,8 @@ module Paperclip
|
|
|
68
70
|
# +url_generator+ - the object used to generate URLs, using the interpolator. Defaults to Paperclip::UrlGenerator
|
|
69
71
|
# +escape_url+ - Perform URI escaping to URLs. Defaults to true
|
|
70
72
|
def initialize(name, instance, options = {})
|
|
71
|
-
@name = name
|
|
73
|
+
@name = name.to_sym
|
|
74
|
+
@name_string = name.to_s
|
|
72
75
|
@instance = instance
|
|
73
76
|
|
|
74
77
|
options = self.class.default_options.deep_merge(options)
|
|
@@ -321,7 +324,7 @@ module Paperclip
|
|
|
321
324
|
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@options[:hash_digest]).new, @options[:hash_secret], data)
|
|
322
325
|
end
|
|
323
326
|
|
|
324
|
-
# This method really shouldn't be called that often.
|
|
327
|
+
# This method really shouldn't be called that often. Its expected use is
|
|
325
328
|
# in the paperclip:refresh rake task and that's it. It will regenerate all
|
|
326
329
|
# thumbnails forcefully, by reobtaining the original file and going through
|
|
327
330
|
# the post-process again.
|
|
@@ -346,7 +349,7 @@ module Paperclip
|
|
|
346
349
|
|
|
347
350
|
# Returns true if a file has been assigned.
|
|
348
351
|
def file?
|
|
349
|
-
|
|
352
|
+
original_filename.present?
|
|
350
353
|
end
|
|
351
354
|
|
|
352
355
|
alias :present? :file?
|
|
@@ -365,7 +368,7 @@ module Paperclip
|
|
|
365
368
|
# instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's
|
|
366
369
|
# "avatar_file_name" field (assuming the attachment is called avatar).
|
|
367
370
|
def instance_write(attr, value)
|
|
368
|
-
setter = :"#{
|
|
371
|
+
setter = :"#{@name_string}_#{attr}="
|
|
369
372
|
if instance.respond_to?(setter)
|
|
370
373
|
instance.send(setter, value)
|
|
371
374
|
end
|
|
@@ -374,7 +377,7 @@ module Paperclip
|
|
|
374
377
|
# Reads the attachment-specific attribute on the instance. See instance_write
|
|
375
378
|
# for more details.
|
|
376
379
|
def instance_read(attr)
|
|
377
|
-
getter = :"#{
|
|
380
|
+
getter = :"#{@name_string}_#{attr}"
|
|
378
381
|
if instance.respond_to?(getter)
|
|
379
382
|
instance.send(getter)
|
|
380
383
|
end
|
|
@@ -402,8 +405,8 @@ module Paperclip
|
|
|
402
405
|
|
|
403
406
|
def ensure_required_accessors! #:nodoc:
|
|
404
407
|
%w(file_name).each do |field|
|
|
405
|
-
unless @instance.respond_to?("#{
|
|
406
|
-
raise Paperclip::Error.new("#{@instance.class} model missing required attr_accessor for '#{
|
|
408
|
+
unless @instance.respond_to?("#{@name_string}_#{field}") && @instance.respond_to?("#{@name_string}_#{field}=")
|
|
409
|
+
raise Paperclip::Error.new("#{@instance.class} model missing required attr_accessor for '#{@name_string}_#{field}'")
|
|
407
410
|
end
|
|
408
411
|
end
|
|
409
412
|
end
|
|
@@ -425,7 +428,7 @@ module Paperclip
|
|
|
425
428
|
def assign_attributes
|
|
426
429
|
@queued_for_write[:original] = @file
|
|
427
430
|
assign_file_information
|
|
428
|
-
assign_fingerprint
|
|
431
|
+
assign_fingerprint { @file.fingerprint }
|
|
429
432
|
assign_timestamps
|
|
430
433
|
end
|
|
431
434
|
|
|
@@ -435,9 +438,9 @@ module Paperclip
|
|
|
435
438
|
instance_write(:file_size, @file.size)
|
|
436
439
|
end
|
|
437
440
|
|
|
438
|
-
def assign_fingerprint
|
|
441
|
+
def assign_fingerprint
|
|
439
442
|
if instance_respond_to?(:fingerprint)
|
|
440
|
-
instance_write(:fingerprint,
|
|
443
|
+
instance_write(:fingerprint, yield)
|
|
441
444
|
end
|
|
442
445
|
end
|
|
443
446
|
|
|
@@ -463,7 +466,7 @@ module Paperclip
|
|
|
463
466
|
|
|
464
467
|
def reset_file_if_original_reprocessed
|
|
465
468
|
instance_write(:file_size, @queued_for_write[:original].size)
|
|
466
|
-
assign_fingerprint
|
|
469
|
+
assign_fingerprint { @queued_for_write[:original].fingerprint }
|
|
467
470
|
reset_updater
|
|
468
471
|
end
|
|
469
472
|
|
|
@@ -499,7 +502,7 @@ module Paperclip
|
|
|
499
502
|
|
|
500
503
|
instance.run_paperclip_callbacks(:post_process) do
|
|
501
504
|
instance.run_paperclip_callbacks(:"#{name}_post_process") do
|
|
502
|
-
|
|
505
|
+
if !@options[:check_validity_before_processing] || !instance.errors.any?
|
|
503
506
|
post_process_styles(*style_args)
|
|
504
507
|
end
|
|
505
508
|
end
|
|
@@ -520,7 +523,7 @@ module Paperclip
|
|
|
520
523
|
|
|
521
524
|
@queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
|
|
522
525
|
file = Paperclip.processor(processor).make(file, style.processor_options, self)
|
|
523
|
-
intermediate_files << file
|
|
526
|
+
intermediate_files << file unless file == @queued_for_write[:original]
|
|
524
527
|
file
|
|
525
528
|
end
|
|
526
529
|
|
|
@@ -528,7 +531,7 @@ module Paperclip
|
|
|
528
531
|
@queued_for_write[name] = Paperclip.io_adapters.for(@queued_for_write[name])
|
|
529
532
|
unadapted_file.close if unadapted_file.respond_to?(:close)
|
|
530
533
|
@queued_for_write[name]
|
|
531
|
-
rescue Paperclip::
|
|
534
|
+
rescue Paperclip::Errors::NotIdentifiedByImageMagickError => e
|
|
532
535
|
log("An error was received while processing: #{e.inspect}")
|
|
533
536
|
(@errors[:processing] ||= []) << e.message if @options[:whiny]
|
|
534
537
|
ensure
|
|
@@ -585,7 +588,7 @@ module Paperclip
|
|
|
585
588
|
|
|
586
589
|
# You can either specifiy :restricted_characters or you can define your own
|
|
587
590
|
# :filename_cleaner object. This object needs to respond to #call and takes
|
|
588
|
-
# the filename that will be cleaned. It should return the cleaned
|
|
591
|
+
# the filename that will be cleaned. It should return the cleaned filename.
|
|
589
592
|
def filename_cleaner
|
|
590
593
|
@options[:filename_cleaner] || FilenameCleaner.new(@options[:restricted_characters])
|
|
591
594
|
end
|
|
@@ -51,8 +51,9 @@ module Paperclip
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def definitions_for(klass)
|
|
54
|
-
klass.ancestors.
|
|
55
|
-
|
|
54
|
+
parent_classes = klass.ancestors.reverse
|
|
55
|
+
parent_classes.each_with_object({}) do |ancestor, inherited_definitions|
|
|
56
|
+
inherited_definitions.deep_merge! @attachments[ancestor]
|
|
56
57
|
end
|
|
57
58
|
end
|
|
58
59
|
end
|
data/lib/paperclip/callbacks.rb
CHANGED
|
@@ -7,7 +7,7 @@ module Paperclip
|
|
|
7
7
|
|
|
8
8
|
module Defining
|
|
9
9
|
def define_paperclip_callbacks(*callbacks)
|
|
10
|
-
define_callbacks(*[callbacks, {:
|
|
10
|
+
define_callbacks(*[callbacks, { terminator: hasta_la_vista_baby }].flatten)
|
|
11
11
|
callbacks.each do |callback|
|
|
12
12
|
eval <<-end_callbacks
|
|
13
13
|
def before_#{callback}(*args, &blk)
|
|
@@ -22,11 +22,13 @@ module Paperclip
|
|
|
22
22
|
|
|
23
23
|
private
|
|
24
24
|
|
|
25
|
-
def
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
def hasta_la_vista_baby
|
|
26
|
+
lambda do |_, result|
|
|
27
|
+
if result.respond_to?(:call)
|
|
28
|
+
result.call == false
|
|
29
|
+
else
|
|
30
|
+
result == false
|
|
31
|
+
end
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
end
|
|
@@ -2,7 +2,7 @@ module Paperclip
|
|
|
2
2
|
class ContentTypeDetector
|
|
3
3
|
# The content-type detection strategy is as follows:
|
|
4
4
|
#
|
|
5
|
-
# 1. Blank/Empty files: If there's no
|
|
5
|
+
# 1. Blank/Empty files: If there's no filepath or the file is empty,
|
|
6
6
|
# provide a sensible default (application/octet-stream or inode/x-empty)
|
|
7
7
|
#
|
|
8
8
|
# 2. Calculated match: Return the first result that is found by both the
|
|
@@ -20,8 +20,8 @@ module Paperclip
|
|
|
20
20
|
EMPTY_TYPE = "inode/x-empty"
|
|
21
21
|
SENSIBLE_DEFAULT = "application/octet-stream"
|
|
22
22
|
|
|
23
|
-
def initialize(
|
|
24
|
-
@
|
|
23
|
+
def initialize(filepath)
|
|
24
|
+
@filepath = filepath
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# Returns a String describing the file's content type
|
|
@@ -33,32 +33,48 @@ module Paperclip
|
|
|
33
33
|
elsif calculated_type_matches.any?
|
|
34
34
|
calculated_type_matches.first
|
|
35
35
|
else
|
|
36
|
-
|
|
36
|
+
type_from_file_contents || SENSIBLE_DEFAULT
|
|
37
37
|
end.to_s
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
private
|
|
41
41
|
|
|
42
|
+
def blank_name?
|
|
43
|
+
@filepath.nil? || @filepath.empty?
|
|
44
|
+
end
|
|
45
|
+
|
|
42
46
|
def empty_file?
|
|
43
|
-
File.exist?(@
|
|
47
|
+
File.exist?(@filepath) && File.size(@filepath) == 0
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
alias :empty? :empty_file?
|
|
47
51
|
|
|
48
|
-
def
|
|
49
|
-
|
|
52
|
+
def calculated_type_matches
|
|
53
|
+
possible_types.select do |content_type|
|
|
54
|
+
content_type == type_from_file_contents
|
|
55
|
+
end
|
|
50
56
|
end
|
|
51
57
|
|
|
52
58
|
def possible_types
|
|
53
|
-
MIME::Types.type_for(@
|
|
59
|
+
MIME::Types.type_for(@filepath).collect(&:content_type)
|
|
54
60
|
end
|
|
55
61
|
|
|
56
|
-
def
|
|
57
|
-
|
|
62
|
+
def type_from_file_contents
|
|
63
|
+
type_from_mime_magic || type_from_file_command
|
|
64
|
+
rescue Errno::ENOENT => e
|
|
65
|
+
Paperclip.log("Error while determining content type: #{e}")
|
|
66
|
+
SENSIBLE_DEFAULT
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def type_from_mime_magic
|
|
70
|
+
@type_from_mime_magic ||= File.open(@filepath) do |file|
|
|
71
|
+
MimeMagic.by_magic(file).try(:type)
|
|
72
|
+
end
|
|
58
73
|
end
|
|
59
74
|
|
|
60
75
|
def type_from_file_command
|
|
61
|
-
@type_from_file_command ||=
|
|
76
|
+
@type_from_file_command ||=
|
|
77
|
+
FileCommandContentTypeDetector.new(@filepath).detect
|
|
62
78
|
end
|
|
63
79
|
end
|
|
64
80
|
end
|
data/lib/paperclip/errors.rb
CHANGED
|
@@ -19,7 +19,9 @@ module Paperclip
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
# Will be thrown when ImageMagic cannot determine the uploaded file's
|
|
22
|
-
# metadata, usually this would mean the file is not an image.
|
|
22
|
+
# metadata, usually this would mean the file is not an image. If you are
|
|
23
|
+
# consistently receiving this error on PDFs make sure that you have
|
|
24
|
+
# installed Ghostscript.
|
|
23
25
|
class NotIdentifiedByImageMagickError < Paperclip::Error
|
|
24
26
|
end
|
|
25
27
|
|
|
@@ -13,20 +13,18 @@ module Paperclip
|
|
|
13
13
|
private
|
|
14
14
|
|
|
15
15
|
def type_from_file_command
|
|
16
|
+
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
|
|
16
17
|
type = begin
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
end
|
|
18
|
+
Paperclip.run("file", "-b --mime :file", file: @filename)
|
|
19
|
+
rescue Cocaine::CommandLineError => e
|
|
20
|
+
Paperclip.log("Error while determining content type: #{e}")
|
|
21
|
+
SENSIBLE_DEFAULT
|
|
22
|
+
end
|
|
23
23
|
|
|
24
24
|
if type.nil? || type.match(/\(.*?\)/)
|
|
25
25
|
type = SENSIBLE_DEFAULT
|
|
26
26
|
end
|
|
27
27
|
type.split(/[:;\s]+/)[0]
|
|
28
28
|
end
|
|
29
|
-
|
|
30
29
|
end
|
|
31
30
|
end
|
|
32
|
-
|
data/lib/paperclip/glue.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Paperclip
|
|
|
8
8
|
base.extend ClassMethods
|
|
9
9
|
base.send :include, Callbacks
|
|
10
10
|
base.send :include, Validators
|
|
11
|
-
base.send :include, Schema if defined? ActiveRecord
|
|
11
|
+
base.send :include, Schema if defined? ActiveRecord::Base
|
|
12
12
|
|
|
13
13
|
locale_path = Dir.glob(File.dirname(__FILE__) + "/locales/*.{rb,yml}")
|
|
14
14
|
I18n.load_path += locale_path unless I18n.load_path.include?(locale_path)
|
|
@@ -79,7 +79,8 @@ module Paperclip
|
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
def add_required_validations
|
|
82
|
-
|
|
82
|
+
options = Paperclip::Attachment.default_options.deep_merge(@options)
|
|
83
|
+
if options[:validate_media_type] != false
|
|
83
84
|
name = @name
|
|
84
85
|
@klass.validates_media_type_spoof_detection name,
|
|
85
86
|
:if => ->(instance){ instance.send(name).dirty? }
|
|
@@ -90,7 +91,13 @@ module Paperclip
|
|
|
90
91
|
name = @name
|
|
91
92
|
@klass.send(:after_save) { send(name).send(:save) }
|
|
92
93
|
@klass.send(:before_destroy) { send(name).send(:queue_all_for_delete) }
|
|
93
|
-
@klass.
|
|
94
|
+
if @klass.respond_to?(:after_commit)
|
|
95
|
+
@klass.send(:after_commit, on: :destroy) do
|
|
96
|
+
send(name).send(:flush_deletes)
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
@klass.send(:after_destroy) { send(name).send(:flush_deletes) }
|
|
100
|
+
end
|
|
94
101
|
end
|
|
95
102
|
|
|
96
103
|
def add_paperclip_callbacks
|
data/lib/paperclip/helpers.rb
CHANGED
|
@@ -8,23 +8,27 @@ module Paperclip
|
|
|
8
8
|
Paperclip::Interpolations[key] = block
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
# The run method takes the name of a binary to run, the arguments
|
|
12
|
-
# and some options
|
|
11
|
+
# The run method takes the name of a binary to run, the arguments
|
|
12
|
+
# to that binary, the values to interpolate and some local options.
|
|
13
13
|
#
|
|
14
|
-
#
|
|
15
|
-
# on the filesystem. Colon-separated, just like $PATH.
|
|
14
|
+
# :cmd -> The name of a binary to run.
|
|
16
15
|
#
|
|
17
|
-
#
|
|
18
|
-
# of the binary. Defaults to [0].
|
|
16
|
+
# :arguments -> The command line arguments to that binary.
|
|
19
17
|
#
|
|
20
|
-
#
|
|
21
|
-
# This will only log if logging in general is set to true as well.
|
|
18
|
+
# :interpolation_values -> Values to be interpolated into the arguments.
|
|
22
19
|
#
|
|
23
|
-
#
|
|
20
|
+
# :local_options -> The options to be used by Cocain::CommandLine.
|
|
21
|
+
# These could be: runner
|
|
22
|
+
# logger
|
|
23
|
+
# swallow_stderr
|
|
24
|
+
# expected_outcodes
|
|
25
|
+
# environment
|
|
26
|
+
# runner_options
|
|
24
27
|
#
|
|
25
28
|
def run(cmd, arguments = "", interpolation_values = {}, local_options = {})
|
|
26
29
|
command_path = options[:command_path]
|
|
27
|
-
|
|
30
|
+
cocaine_path_array = Cocaine::CommandLine.path.try(:split, Cocaine::OS.path_separator)
|
|
31
|
+
Cocaine::CommandLine.path = [cocaine_path_array, command_path].flatten.compact.uniq
|
|
28
32
|
if logging? && (options[:log_command] || local_options[:log_command])
|
|
29
33
|
local_options = local_options.merge(:logger => logger)
|
|
30
34
|
end
|
|
@@ -2,15 +2,16 @@ module Paperclip
|
|
|
2
2
|
module Interpolations
|
|
3
3
|
class PluralCache
|
|
4
4
|
def initialize
|
|
5
|
-
@
|
|
5
|
+
@symbol_cache = {}.compare_by_identity
|
|
6
|
+
@klass_cache = {}.compare_by_identity
|
|
6
7
|
end
|
|
7
8
|
|
|
8
|
-
def
|
|
9
|
-
@
|
|
9
|
+
def pluralize_symbol(symbol)
|
|
10
|
+
@symbol_cache[symbol] ||= symbol.to_s.downcase.pluralize
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
def
|
|
13
|
-
@
|
|
13
|
+
def underscore_and_pluralize_class(klass)
|
|
14
|
+
@klass_cache[klass] ||= klass.name.underscore.pluralize
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
17
|
end
|
|
@@ -10,6 +10,7 @@ module Paperclip
|
|
|
10
10
|
# and is not intended for normal use.
|
|
11
11
|
def self.[]= name, block
|
|
12
12
|
define_method(name, &block)
|
|
13
|
+
@interpolators_cache = nil
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
# Hash access of interpolations. Included only for compatibility,
|
|
@@ -20,7 +21,7 @@ module Paperclip
|
|
|
20
21
|
|
|
21
22
|
# Returns a sorted list of all interpolations.
|
|
22
23
|
def self.all
|
|
23
|
-
self.instance_methods(false).sort
|
|
24
|
+
self.instance_methods(false).sort!
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
# Perform the actual interpolation. Takes the pattern to interpolate
|
|
@@ -29,11 +30,15 @@ module Paperclip
|
|
|
29
30
|
# an interpolation pattern for Paperclip to use.
|
|
30
31
|
def self.interpolate pattern, *args
|
|
31
32
|
pattern = args.first.instance.send(pattern) if pattern.kind_of? Symbol
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
end
|
|
33
|
+
result = pattern.dup
|
|
34
|
+
interpolators_cache.each do |method, token|
|
|
35
|
+
result.gsub!(token) { send(method, *args) } if result.include?(token)
|
|
36
36
|
end
|
|
37
|
+
result
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.interpolators_cache
|
|
41
|
+
@interpolators_cache ||= all.reverse!.map! { |method| [method, ":#{method}"] }
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
def self.plural_cache
|
|
@@ -42,7 +47,7 @@ module Paperclip
|
|
|
42
47
|
|
|
43
48
|
# Returns the filename, the same way as ":basename.:extension" would.
|
|
44
49
|
def filename attachment, style_name
|
|
45
|
-
[ basename(attachment, style_name), extension(attachment, style_name) ].
|
|
50
|
+
[ basename(attachment, style_name), extension(attachment, style_name) ].delete_if(&:empty?).join(".".freeze)
|
|
46
51
|
end
|
|
47
52
|
|
|
48
53
|
# Returns the interpolated URL. Will raise an error if the url itself
|
|
@@ -85,12 +90,12 @@ module Paperclip
|
|
|
85
90
|
# all class names. Calling #class will return the expected class.
|
|
86
91
|
def class attachment = nil, style_name = nil
|
|
87
92
|
return super() if attachment.nil? && style_name.nil?
|
|
88
|
-
plural_cache.
|
|
93
|
+
plural_cache.underscore_and_pluralize_class(attachment.instance.class)
|
|
89
94
|
end
|
|
90
95
|
|
|
91
96
|
# Returns the basename of the file. e.g. "file" for "file.jpg"
|
|
92
97
|
def basename attachment, style_name
|
|
93
|
-
|
|
98
|
+
File.basename(attachment.original_filename, ".*".freeze)
|
|
94
99
|
end
|
|
95
100
|
|
|
96
101
|
# Returns the extension of the file. e.g. "jpg" for "file.jpg"
|
|
@@ -98,7 +103,7 @@ module Paperclip
|
|
|
98
103
|
# of the actual extension.
|
|
99
104
|
def extension attachment, style_name
|
|
100
105
|
((style = attachment.styles[style_name.to_s.to_sym]) && style[:format]) ||
|
|
101
|
-
File.extname(attachment.original_filename).
|
|
106
|
+
File.extname(attachment.original_filename).sub(/\A\.+/, "".freeze)
|
|
102
107
|
end
|
|
103
108
|
|
|
104
109
|
# Returns the dot+extension of the file. e.g. ".jpg" for "file.jpg"
|
|
@@ -106,7 +111,7 @@ module Paperclip
|
|
|
106
111
|
# of the actual extension. If the extension is empty, no dot is added.
|
|
107
112
|
def dotextension attachment, style_name
|
|
108
113
|
ext = extension(attachment, style_name)
|
|
109
|
-
ext.empty? ?
|
|
114
|
+
ext.empty? ? ext : ".#{ext}"
|
|
110
115
|
end
|
|
111
116
|
|
|
112
117
|
# Returns an extension based on the content type. e.g. "jpeg" for
|
|
@@ -170,9 +175,9 @@ module Paperclip
|
|
|
170
175
|
def id_partition attachment, style_name
|
|
171
176
|
case id = attachment.instance.id
|
|
172
177
|
when Integer
|
|
173
|
-
("%09d" % id).scan(/\d{3}/).join("/")
|
|
178
|
+
("%09d".freeze % id).scan(/\d{3}/).join("/".freeze)
|
|
174
179
|
when String
|
|
175
|
-
|
|
180
|
+
id.scan(/.{3}/).first(3).join("/".freeze)
|
|
176
181
|
else
|
|
177
182
|
nil
|
|
178
183
|
end
|
|
@@ -181,7 +186,7 @@ module Paperclip
|
|
|
181
186
|
# Returns the pluralized form of the attachment name. e.g.
|
|
182
187
|
# "avatars" for an attachment of :avatar
|
|
183
188
|
def attachment attachment, style_name
|
|
184
|
-
plural_cache.
|
|
189
|
+
plural_cache.pluralize_symbol(attachment.name)
|
|
185
190
|
end
|
|
186
191
|
|
|
187
192
|
# Returns the style, or the default style if nil is supplied.
|
|
@@ -6,6 +6,7 @@ module Paperclip
|
|
|
6
6
|
|
|
7
7
|
attr_reader :content_type, :original_filename, :size
|
|
8
8
|
delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink, :to => :@tempfile
|
|
9
|
+
alias :length :size
|
|
9
10
|
|
|
10
11
|
def fingerprint
|
|
11
12
|
@fingerprint ||= Digest::MD5.file(path).to_s
|
|
@@ -40,9 +40,9 @@ module Paperclip
|
|
|
40
40
|
|
|
41
41
|
def failure_message
|
|
42
42
|
"#{expected_attachment}\n".tap do |message|
|
|
43
|
-
message << accepted_types_and_failures
|
|
43
|
+
message << accepted_types_and_failures.to_s
|
|
44
44
|
message << "\n\n" if @allowed_types.present? && @rejected_types.present?
|
|
45
|
-
message << rejected_types_and_failures
|
|
45
|
+
message << rejected_types_and_failures.to_s
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
@@ -55,7 +55,7 @@ module Paperclip
|
|
|
55
55
|
def accepted_types_and_failures
|
|
56
56
|
if @allowed_types.present?
|
|
57
57
|
"Accept content types: #{@allowed_types.join(", ")}\n".tap do |message|
|
|
58
|
-
if @missing_allowed_types.
|
|
58
|
+
if @missing_allowed_types.present?
|
|
59
59
|
message << " #{@missing_allowed_types.join(", ")} were rejected."
|
|
60
60
|
else
|
|
61
61
|
message << " All were accepted successfully."
|
|
@@ -66,7 +66,7 @@ module Paperclip
|
|
|
66
66
|
def rejected_types_and_failures
|
|
67
67
|
if @rejected_types.present?
|
|
68
68
|
"Reject content types: #{@rejected_types.join(", ")}\n".tap do |message|
|
|
69
|
-
if @missing_rejected_types.
|
|
69
|
+
if @missing_rejected_types.present?
|
|
70
70
|
message << " #{@missing_rejected_types.join(", ")} were accepted."
|
|
71
71
|
else
|
|
72
72
|
message << " All were rejected successfully."
|
|
@@ -12,7 +12,7 @@ module Paperclip
|
|
|
12
12
|
|
|
13
13
|
def spoofed?
|
|
14
14
|
if has_name? && has_extension? && media_type_mismatch? && mapping_override_mismatch?
|
|
15
|
-
Paperclip.log("Content Type Spoof: Filename #{File.basename(@name)} (#{supplied_content_type} from Headers, #{content_types_from_name} from Extension), content type discovered from file command: #{calculated_content_type}. See documentation to allow this combination.")
|
|
15
|
+
Paperclip.log("Content Type Spoof: Filename #{File.basename(@name)} (#{supplied_content_type} from Headers, #{content_types_from_name.map(&:to_s)} from Extension), content type discovered from file command: #{calculated_content_type}. See documentation to allow this combination.")
|
|
16
16
|
true
|
|
17
17
|
else
|
|
18
18
|
false
|
|
@@ -42,7 +42,7 @@ module Paperclip
|
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def mapping_override_mismatch?
|
|
45
|
-
mapped_content_type
|
|
45
|
+
!Array(mapped_content_type).include?(calculated_content_type)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Paperclip
|
|
2
|
+
class RailsEnvironment
|
|
3
|
+
def self.get
|
|
4
|
+
new.get
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def get
|
|
8
|
+
if rails_exists? && rails_environment_exists?
|
|
9
|
+
Rails.env
|
|
10
|
+
else
|
|
11
|
+
nil
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def rails_exists?
|
|
18
|
+
Object.const_defined?(:Rails)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def rails_environment_exists?
|
|
22
|
+
Rails.respond_to?(:env)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/paperclip/schema.rb
CHANGED
|
@@ -12,10 +12,7 @@ module Paperclip
|
|
|
12
12
|
ActiveRecord::ConnectionAdapters::Table.send :include, TableDefinition
|
|
13
13
|
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, TableDefinition
|
|
14
14
|
ActiveRecord::ConnectionAdapters::AbstractAdapter.send :include, Statements
|
|
15
|
-
|
|
16
|
-
if defined?(ActiveRecord::Migration::CommandRecorder) # Rails 3.1+
|
|
17
|
-
ActiveRecord::Migration::CommandRecorder.send :include, CommandRecorder
|
|
18
|
-
end
|
|
15
|
+
ActiveRecord::Migration::CommandRecorder.send :include, CommandRecorder
|
|
19
16
|
end
|
|
20
17
|
|
|
21
18
|
module Statements
|
|
@@ -35,12 +32,9 @@ module Paperclip
|
|
|
35
32
|
def remove_attachment(table_name, *attachment_names)
|
|
36
33
|
raise ArgumentError, "Please specify attachment name in your remove_attachment call in your migration." if attachment_names.empty?
|
|
37
34
|
|
|
38
|
-
options = attachment_names.extract_options!
|
|
39
|
-
|
|
40
35
|
attachment_names.each do |attachment_name|
|
|
41
|
-
COLUMNS.
|
|
42
|
-
|
|
43
|
-
remove_column(table_name, "#{attachment_name}_#{column_name}", column_type, column_options)
|
|
36
|
+
COLUMNS.keys.each do |column_name|
|
|
37
|
+
remove_column(table_name, "#{attachment_name}_#{column_name}")
|
|
44
38
|
end
|
|
45
39
|
end
|
|
46
40
|
end
|