paperclip 5.1.0 → 5.2.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/.codeclimate.yml +17 -0
- data/.hound.yml +5 -16
- data/.travis.yml +14 -15
- data/Appraisals +3 -23
- data/Gemfile +1 -0
- data/NEWS +36 -1
- data/README.md +58 -10
- data/Rakefile +1 -1
- data/UPGRADING +1 -1
- data/features/step_definitions/attachment_steps.rb +6 -6
- data/features/step_definitions/rails_steps.rb +29 -22
- data/features/step_definitions/s3_steps.rb +1 -1
- data/features/support/env.rb +1 -0
- data/features/support/paths.rb +1 -1
- data/features/support/rails.rb +0 -24
- data/gemfiles/{4.2.awsv2.0.gemfile → 4.2.gemfile} +1 -1
- data/gemfiles/{5.0.awsv2.1.gemfile → 5.0.gemfile} +2 -2
- data/lib/paperclip.rb +12 -10
- data/lib/paperclip/attachment.rb +10 -4
- data/lib/paperclip/io_adapters/abstract_adapter.rb +24 -2
- data/lib/paperclip/io_adapters/attachment_adapter.rb +10 -5
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +8 -8
- data/lib/paperclip/io_adapters/empty_string_adapter.rb +5 -4
- data/lib/paperclip/io_adapters/file_adapter.rb +12 -6
- data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +7 -7
- data/lib/paperclip/io_adapters/identity_adapter.rb +12 -6
- data/lib/paperclip/io_adapters/nil_adapter.rb +8 -5
- data/lib/paperclip/io_adapters/registry.rb +6 -2
- data/lib/paperclip/io_adapters/stringio_adapter.rb +9 -6
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +9 -5
- data/lib/paperclip/io_adapters/uri_adapter.rb +13 -11
- data/lib/paperclip/storage/filesystem.rb +13 -2
- data/lib/paperclip/storage/fog.rb +7 -4
- data/lib/paperclip/storage/s3.rb +31 -3
- data/lib/paperclip/thumbnail.rb +14 -4
- data/lib/paperclip/version.rb +1 -1
- data/lib/tasks/paperclip.rake +17 -3
- data/paperclip.gemspec +3 -3
- data/spec/paperclip/attachment_spec.rb +39 -8
- data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +44 -21
- data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +6 -3
- data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +7 -1
- data/spec/paperclip/io_adapters/file_adapter_spec.rb +2 -2
- data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +6 -1
- data/spec/paperclip/io_adapters/identity_adapter_spec.rb +1 -1
- data/spec/paperclip/io_adapters/registry_spec.rb +2 -2
- data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +1 -1
- data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +3 -3
- data/spec/paperclip/io_adapters/uri_adapter_spec.rb +6 -1
- data/spec/paperclip/storage/fog_spec.rb +16 -0
- data/spec/paperclip/storage/s3_live_spec.rb +12 -10
- data/spec/paperclip/storage/s3_spec.rb +85 -4
- data/spec/paperclip/tempfile_spec.rb +35 -0
- data/spec/paperclip/thumbnail_spec.rb +35 -32
- data/spec/spec_helper.rb +3 -1
- data/spec/support/assertions.rb +5 -1
- data/spec/support/conditional_filter_helper.rb +5 -0
- metadata +31 -135
- data/gemfiles/4.2.awsv2.1.gemfile +0 -17
- data/gemfiles/4.2.awsv2.gemfile +0 -20
- data/gemfiles/5.0.awsv2.0.gemfile +0 -17
- data/gemfiles/5.0.awsv2.gemfile +0 -20
@@ -1,6 +1,6 @@
|
|
1
1
|
When /^I attach the file "([^"]*)" to "([^"]*)" on S3$/ do |file_path, field|
|
2
2
|
definition = Paperclip::AttachmentRegistry.definitions_for(User)[field.downcase.to_sym]
|
3
|
-
path = "https://paperclip.s3
|
3
|
+
path = "https://paperclip.s3.us-west-2.amazonaws.com#{definition[:path]}"
|
4
4
|
path.gsub!(':filename', File.basename(file_path))
|
5
5
|
path.gsub!(/:([^\/\.]+)/) do |match|
|
6
6
|
"([^\/\.]+)"
|
data/features/support/env.rb
CHANGED
data/features/support/paths.rb
CHANGED
@@ -17,7 +17,7 @@ module NavigationHelpers
|
|
17
17
|
page_name =~ /the (.*) page/
|
18
18
|
path_components = $1.split(/\s+/)
|
19
19
|
self.send(path_components.push('path').join('_').to_sym)
|
20
|
-
rescue Object
|
20
|
+
rescue Object
|
21
21
|
raise "Can't find mapping from \"#{page_name}\" to a path.\n" +
|
22
22
|
"Now, go and add a mapping in #{__FILE__}"
|
23
23
|
end
|
data/features/support/rails.rb
CHANGED
@@ -35,29 +35,5 @@ module RailsCommandHelpers
|
|
35
35
|
def framework_major_version
|
36
36
|
framework_version.split(".").first.to_i
|
37
37
|
end
|
38
|
-
|
39
|
-
def using_protected_attributes?
|
40
|
-
framework_major_version < 4
|
41
|
-
end
|
42
|
-
|
43
|
-
def new_application_command
|
44
|
-
"rails new"
|
45
|
-
end
|
46
|
-
|
47
|
-
def generator_command
|
48
|
-
if framework_major_version >= 4
|
49
|
-
"rails generate"
|
50
|
-
else
|
51
|
-
"script/rails generate"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def runner_command
|
56
|
-
if framework_major_version >= 4
|
57
|
-
"rails runner"
|
58
|
-
else
|
59
|
-
"script/rails runner"
|
60
|
-
end
|
61
|
-
end
|
62
38
|
end
|
63
39
|
World(RailsCommandHelpers)
|
@@ -5,13 +5,13 @@ source "https://rubygems.org"
|
|
5
5
|
gem "sqlite3", "~> 1.3.8", :platforms => :ruby
|
6
6
|
gem "pry"
|
7
7
|
gem "rails", "~> 4.2.0"
|
8
|
-
gem "aws-sdk", "~> 2.0.0"
|
9
8
|
|
10
9
|
group :development, :test do
|
11
10
|
gem "activerecord-import"
|
12
11
|
gem "mime-types"
|
13
12
|
gem "builder"
|
14
13
|
gem "rubocop", :require => false
|
14
|
+
gem "rspec"
|
15
15
|
end
|
16
16
|
|
17
17
|
gemspec :path => "../"
|
@@ -4,14 +4,14 @@ source "https://rubygems.org"
|
|
4
4
|
|
5
5
|
gem "sqlite3", "~> 1.3.8", :platforms => :ruby
|
6
6
|
gem "pry"
|
7
|
-
gem "rails", "5.0.0"
|
8
|
-
gem "aws-sdk", "~> 2.1.0"
|
7
|
+
gem "rails", "~> 5.0.0"
|
9
8
|
|
10
9
|
group :development, :test do
|
11
10
|
gem "activerecord-import"
|
12
11
|
gem "mime-types"
|
13
12
|
gem "builder"
|
14
13
|
gem "rubocop", :require => false
|
14
|
+
gem "rspec"
|
15
15
|
end
|
16
16
|
|
17
17
|
gemspec :path => "../"
|
data/lib/paperclip.rb
CHANGED
@@ -90,15 +90,14 @@ module Paperclip
|
|
90
90
|
# image's orientation. Defaults to true.
|
91
91
|
def self.options
|
92
92
|
@options ||= {
|
93
|
-
:
|
94
|
-
:
|
95
|
-
:
|
96
|
-
:
|
97
|
-
:
|
98
|
-
:
|
99
|
-
:
|
100
|
-
:
|
101
|
-
:read_timeout => nil
|
93
|
+
command_path: nil,
|
94
|
+
content_type_mappings: {},
|
95
|
+
log: true,
|
96
|
+
log_command: true,
|
97
|
+
read_timeout: nil,
|
98
|
+
swallow_stderr: true,
|
99
|
+
use_exif_orientation: true,
|
100
|
+
whiny: true,
|
102
101
|
}
|
103
102
|
end
|
104
103
|
|
@@ -120,7 +119,7 @@ module Paperclip
|
|
120
119
|
# called on it, the attachment will *not* be deleted until +save+ is called. See the
|
121
120
|
# Paperclip::Attachment documentation for more specifics. There are a number of options
|
122
121
|
# you can set to change the behavior of a Paperclip attachment:
|
123
|
-
# * +url+: The full URL of where the attachment is
|
122
|
+
# * +url+: The full URL of where the attachment is publicly accessible. This can just
|
124
123
|
# as easily point to a directory served directly through Apache as it can to an action
|
125
124
|
# that can control permissions. You can specify the full domain and path, but usually
|
126
125
|
# just an absolute path is sufficient. The leading slash *must* be included manually for
|
@@ -129,6 +128,9 @@ module Paperclip
|
|
129
128
|
# Paperclip::Attachment#interpolate for more information on variable interpolaton.
|
130
129
|
# :url => "/:class/:attachment/:id/:style_:filename"
|
131
130
|
# :url => "http://some.other.host/stuff/:class/:id_:extension"
|
131
|
+
# Note: When using the +s3+ storage option, the +url+ option expects
|
132
|
+
# particular values. See the Paperclip::Storage::S3#url documentation for
|
133
|
+
# specifics.
|
132
134
|
# * +default_url+: The URL that will be returned if there is no attachment assigned.
|
133
135
|
# This field is interpolated just as the url is. The default value is
|
134
136
|
# "/:attachment/:style/missing.png"
|
data/lib/paperclip/attachment.rb
CHANGED
@@ -33,6 +33,7 @@ module Paperclip
|
|
33
33
|
:use_timestamp => true,
|
34
34
|
:whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails],
|
35
35
|
:validate_media_type => true,
|
36
|
+
:adapter_options => { hash_digest: Digest::MD5 },
|
36
37
|
:check_validity_before_processing => true
|
37
38
|
}
|
38
39
|
end
|
@@ -97,7 +98,8 @@ module Paperclip
|
|
97
98
|
# attachment:
|
98
99
|
# new_user.avatar = old_user.avatar
|
99
100
|
def assign(uploaded_file)
|
100
|
-
@file = Paperclip.io_adapters.for(uploaded_file
|
101
|
+
@file = Paperclip.io_adapters.for(uploaded_file,
|
102
|
+
@options[:adapter_options])
|
101
103
|
ensure_required_accessors!
|
102
104
|
ensure_required_validations!
|
103
105
|
|
@@ -238,7 +240,8 @@ module Paperclip
|
|
238
240
|
# the instance's errors and returns false, cancelling the save.
|
239
241
|
def save
|
240
242
|
flush_deletes unless @options[:keep_old_files]
|
241
|
-
|
243
|
+
process = only_process
|
244
|
+
if process.any? && !process.include?(:original)
|
242
245
|
@queued_for_write.except!(:original)
|
243
246
|
end
|
244
247
|
flush_writes
|
@@ -523,15 +526,18 @@ module Paperclip
|
|
523
526
|
begin
|
524
527
|
raise RuntimeError.new("Style #{name} has no processors defined.") if style.processors.blank?
|
525
528
|
intermediate_files = []
|
529
|
+
original = @queued_for_write[:original]
|
526
530
|
|
527
|
-
@queued_for_write[name] = style.processors.
|
531
|
+
@queued_for_write[name] = style.processors.
|
532
|
+
reduce(original) do |file, processor|
|
528
533
|
file = Paperclip.processor(processor).make(file, style.processor_options, self)
|
529
534
|
intermediate_files << file unless file == @queued_for_write[:original]
|
530
535
|
file
|
531
536
|
end
|
532
537
|
|
533
538
|
unadapted_file = @queued_for_write[name]
|
534
|
-
@queued_for_write[name] = Paperclip.io_adapters.
|
539
|
+
@queued_for_write[name] = Paperclip.io_adapters.
|
540
|
+
for(@queued_for_write[name], @options[:adapter_options])
|
535
541
|
unadapted_file.close if unadapted_file.respond_to?(:close)
|
536
542
|
@queued_for_write[name]
|
537
543
|
rescue Paperclip::Errors::NotIdentifiedByImageMagickError => e
|
@@ -8,8 +8,20 @@ module Paperclip
|
|
8
8
|
delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :readbyte, :rewind, :unlink, :to => :@tempfile
|
9
9
|
alias :length :size
|
10
10
|
|
11
|
+
def initialize(target, options = {})
|
12
|
+
@target = target
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
11
16
|
def fingerprint
|
12
|
-
@fingerprint ||=
|
17
|
+
@fingerprint ||= begin
|
18
|
+
digest = @options.fetch(:hash_digest).new
|
19
|
+
File.open(path, "rb") do |f|
|
20
|
+
buf = ""
|
21
|
+
digest.update(buf) while f.read(16384, buf)
|
22
|
+
end
|
23
|
+
digest.hexdigest
|
24
|
+
end
|
13
25
|
end
|
14
26
|
|
15
27
|
def read(length = nil, buffer = nil)
|
@@ -40,8 +52,18 @@ module Paperclip
|
|
40
52
|
end
|
41
53
|
|
42
54
|
def copy_to_tempfile(src)
|
43
|
-
|
55
|
+
link_or_copy_file(src.path, destination.path)
|
44
56
|
destination
|
45
57
|
end
|
58
|
+
|
59
|
+
def link_or_copy_file(src, dest)
|
60
|
+
Paperclip.log("Trying to link #{src} to #{dest}")
|
61
|
+
FileUtils.ln(src, dest, force: true) # overwrite existing
|
62
|
+
@destination.close
|
63
|
+
@destination.open.binmode
|
64
|
+
rescue Errno::EXDEV, Errno::EPERM, Errno::ENOENT => e
|
65
|
+
Paperclip.log("Link failed with #{e.message}; copying link #{src} to #{dest}")
|
66
|
+
FileUtils.cp(src, dest)
|
67
|
+
end
|
46
68
|
end
|
47
69
|
end
|
@@ -1,6 +1,13 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class AttachmentAdapter < AbstractAdapter
|
3
|
-
def
|
3
|
+
def self.register
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
5
|
+
Paperclip::Attachment === target || Paperclip::Style === target
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(target, options = {})
|
10
|
+
super
|
4
11
|
@target, @style = case target
|
5
12
|
when Paperclip::Attachment
|
6
13
|
[target, :original]
|
@@ -22,7 +29,7 @@ module Paperclip
|
|
22
29
|
|
23
30
|
def copy_to_tempfile(source)
|
24
31
|
if source.staged?
|
25
|
-
|
32
|
+
link_or_copy_file(source.staged_path(@style), destination.path)
|
26
33
|
else
|
27
34
|
source.copy_to_local_file(@style, destination.path)
|
28
35
|
end
|
@@ -31,6 +38,4 @@ module Paperclip
|
|
31
38
|
end
|
32
39
|
end
|
33
40
|
|
34
|
-
Paperclip.
|
35
|
-
Paperclip::Attachment === target || Paperclip::Style === target
|
36
|
-
end
|
41
|
+
Paperclip::AttachmentAdapter.register
|
@@ -1,22 +1,22 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class DataUriAdapter < StringioAdapter
|
3
|
+
def self.register
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
5
|
+
String === target && target =~ REGEXP
|
6
|
+
end
|
7
|
+
end
|
3
8
|
|
4
9
|
REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m
|
5
10
|
|
6
|
-
def initialize(target_uri)
|
7
|
-
super(extract_target(target_uri))
|
11
|
+
def initialize(target_uri, options = {})
|
12
|
+
super(extract_target(target_uri), options)
|
8
13
|
end
|
9
14
|
|
10
15
|
private
|
11
16
|
|
12
17
|
def extract_target(uri)
|
13
18
|
data_uri_parts = uri.match(REGEXP) || []
|
14
|
-
StringIO.new(Base64.decode64(data_uri_parts[2] ||
|
19
|
+
StringIO.new(Base64.decode64(data_uri_parts[2] || ""))
|
15
20
|
end
|
16
|
-
|
17
21
|
end
|
18
22
|
end
|
19
|
-
|
20
|
-
Paperclip.io_adapters.register Paperclip::DataUriAdapter do |target|
|
21
|
-
String === target && target =~ Paperclip::DataUriAdapter::REGEXP
|
22
|
-
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class EmptyStringAdapter < AbstractAdapter
|
3
|
-
def
|
3
|
+
def self.register
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
5
|
+
target.is_a?(String) && target.empty?
|
6
|
+
end
|
4
7
|
end
|
5
8
|
|
6
9
|
def nil?
|
@@ -13,6 +16,4 @@ module Paperclip
|
|
13
16
|
end
|
14
17
|
end
|
15
18
|
|
16
|
-
Paperclip.
|
17
|
-
target.is_a?(String) && target.empty?
|
18
|
-
end
|
19
|
+
Paperclip::EmptyStringAdapter.register
|
@@ -1,14 +1,22 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class FileAdapter < AbstractAdapter
|
3
|
-
def
|
4
|
-
|
3
|
+
def self.register
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
5
|
+
File === target || ::Tempfile === target
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(target, options = {})
|
10
|
+
super
|
5
11
|
cache_current_values
|
6
12
|
end
|
7
13
|
|
8
14
|
private
|
9
15
|
|
10
16
|
def cache_current_values
|
11
|
-
|
17
|
+
if @target.respond_to?(:original_filename)
|
18
|
+
self.original_filename = @target.original_filename
|
19
|
+
end
|
12
20
|
self.original_filename ||= File.basename(@target.path)
|
13
21
|
@tempfile = copy_to_tempfile(@target)
|
14
22
|
@content_type = ContentTypeDetector.new(@target.path).detect
|
@@ -17,6 +25,4 @@ module Paperclip
|
|
17
25
|
end
|
18
26
|
end
|
19
27
|
|
20
|
-
Paperclip.
|
21
|
-
File === target || Tempfile === target
|
22
|
-
end
|
28
|
+
Paperclip::FileAdapter.register
|
@@ -1,15 +1,15 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class HttpUrlProxyAdapter < UriAdapter
|
3
|
+
def self.register
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
5
|
+
String === target && target =~ REGEXP
|
6
|
+
end
|
7
|
+
end
|
3
8
|
|
4
9
|
REGEXP = /\Ahttps?:\/\//
|
5
10
|
|
6
|
-
def initialize(target)
|
7
|
-
super(URI(URI.escape(target)))
|
11
|
+
def initialize(target, options = {})
|
12
|
+
super(URI(URI.escape(target)), options)
|
8
13
|
end
|
9
|
-
|
10
14
|
end
|
11
15
|
end
|
12
|
-
|
13
|
-
Paperclip.io_adapters.register Paperclip::HttpUrlProxyAdapter do |target|
|
14
|
-
String === target && target =~ Paperclip::HttpUrlProxyAdapter::REGEXP
|
15
|
-
end
|
@@ -1,12 +1,18 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class IdentityAdapter < AbstractAdapter
|
3
|
-
def
|
4
|
-
|
3
|
+
def self.register
|
4
|
+
Paperclip.io_adapters.register Paperclip::IdentityAdapter.new do |target|
|
5
|
+
Paperclip.io_adapters.registered?(target)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
5
10
|
end
|
6
|
-
end
|
7
|
-
end
|
8
11
|
|
9
|
-
|
10
|
-
|
12
|
+
def new(target, _)
|
13
|
+
target
|
14
|
+
end
|
15
|
+
end
|
11
16
|
end
|
12
17
|
|
18
|
+
Paperclip::IdentityAdapter.register
|
@@ -1,8 +1,13 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class NilAdapter < AbstractAdapter
|
3
|
-
def
|
3
|
+
def self.register
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
5
|
+
target.nil? || ((Paperclip::Attachment === target) && !target.present?)
|
6
|
+
end
|
4
7
|
end
|
5
8
|
|
9
|
+
def initialize(_target, _options = {}); end
|
10
|
+
|
6
11
|
def original_filename
|
7
12
|
""
|
8
13
|
end
|
@@ -19,7 +24,7 @@ module Paperclip
|
|
19
24
|
true
|
20
25
|
end
|
21
26
|
|
22
|
-
def read(*
|
27
|
+
def read(*_args)
|
23
28
|
nil
|
24
29
|
end
|
25
30
|
|
@@ -29,6 +34,4 @@ module Paperclip
|
|
29
34
|
end
|
30
35
|
end
|
31
36
|
|
32
|
-
Paperclip.
|
33
|
-
target.nil? || ( (Paperclip::Attachment === target) && !target.present? )
|
34
|
-
end
|
37
|
+
Paperclip::NilAdapter.register
|
@@ -12,6 +12,10 @@ module Paperclip
|
|
12
12
|
@registered_handlers << [block, handler_class]
|
13
13
|
end
|
14
14
|
|
15
|
+
def unregister(handler_class)
|
16
|
+
@registered_handlers.reject! { |_, klass| klass == handler_class }
|
17
|
+
end
|
18
|
+
|
15
19
|
def handler_for(target)
|
16
20
|
@registered_handlers.each do |tester, handler|
|
17
21
|
return handler if tester.call(target)
|
@@ -25,8 +29,8 @@ module Paperclip
|
|
25
29
|
end
|
26
30
|
end
|
27
31
|
|
28
|
-
def for(target)
|
29
|
-
handler_for(target).new(target)
|
32
|
+
def for(target, options = {})
|
33
|
+
handler_for(target).new(target, options)
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
@@ -1,7 +1,13 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class StringioAdapter < AbstractAdapter
|
3
|
-
def
|
4
|
-
|
3
|
+
def self.register
|
4
|
+
Paperclip.io_adapters.register self do |target|
|
5
|
+
StringIO === target
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(target, options = {})
|
10
|
+
super
|
5
11
|
cache_current_values
|
6
12
|
end
|
7
13
|
|
@@ -24,10 +30,7 @@ module Paperclip
|
|
24
30
|
destination.rewind
|
25
31
|
destination
|
26
32
|
end
|
27
|
-
|
28
33
|
end
|
29
34
|
end
|
30
35
|
|
31
|
-
Paperclip.
|
32
|
-
StringIO === target
|
33
|
-
end
|
36
|
+
Paperclip::StringioAdapter.register
|