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
@@ -0,0 +1,35 @@
|
|
1
|
+
module Paperclip
|
2
|
+
module InstanceMethods #:nodoc:
|
3
|
+
def attachment_for name
|
4
|
+
@_paperclip_attachments ||= {}
|
5
|
+
@_paperclip_attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name])
|
6
|
+
end
|
7
|
+
|
8
|
+
def each_attachment
|
9
|
+
self.class.attachment_definitions.each do |name, definition|
|
10
|
+
yield(name, attachment_for(name))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def save_attached_files
|
15
|
+
Paperclip.log("Saving attachments.")
|
16
|
+
each_attachment do |name, attachment|
|
17
|
+
attachment.send(:save)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def destroy_attached_files
|
22
|
+
Paperclip.log("Deleting attachments.")
|
23
|
+
each_attachment do |name, attachment|
|
24
|
+
attachment.send(:flush_deletes)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def prepare_for_destroy
|
29
|
+
Paperclip.log("Scheduling attachments for deletion.")
|
30
|
+
each_attachment do |name, attachment|
|
31
|
+
attachment.send(:queue_all_for_delete)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -46,7 +46,7 @@ module Paperclip
|
|
46
46
|
# is used in the default :path to ease default specifications.
|
47
47
|
RIGHT_HERE = "#{__FILE__.gsub(%r{^\./}, "")}:#{__LINE__ + 3}"
|
48
48
|
def url attachment, style_name
|
49
|
-
raise InfiniteInterpolationError if caller.any?{|b| b.index(RIGHT_HERE) }
|
49
|
+
raise Errors::InfiniteInterpolationError if caller.any?{|b| b.index(RIGHT_HERE) }
|
50
50
|
attachment.url(style_name, :timestamp => false, :escape => false)
|
51
51
|
end
|
52
52
|
|
@@ -93,7 +93,7 @@ module Paperclip
|
|
93
93
|
# If the style has a format defined, it will return the format instead
|
94
94
|
# of the actual extension.
|
95
95
|
def extension attachment, style_name
|
96
|
-
((style = attachment.styles[style_name]) && style[:format]) ||
|
96
|
+
((style = attachment.styles[style_name.to_s.to_sym]) && style[:format]) ||
|
97
97
|
File.extname(attachment.original_filename).gsub(/^\.+/, "")
|
98
98
|
end
|
99
99
|
|
@@ -137,11 +137,11 @@ module Paperclip
|
|
137
137
|
attachment.fingerprint
|
138
138
|
end
|
139
139
|
|
140
|
-
# Returns a the attachment hash. See Paperclip::Attachment#
|
140
|
+
# Returns a the attachment hash. See Paperclip::Attachment#hash_key for
|
141
141
|
# more details.
|
142
142
|
def hash attachment=nil, style_name=nil
|
143
143
|
if attachment && style_name
|
144
|
-
attachment.
|
144
|
+
attachment.hash_key(style_name)
|
145
145
|
else
|
146
146
|
super()
|
147
147
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class AttachmentAdapter
|
3
|
+
def initialize(target)
|
4
|
+
@target = target
|
5
|
+
cache_current_values
|
6
|
+
end
|
7
|
+
|
8
|
+
def original_filename
|
9
|
+
@original_filename
|
10
|
+
end
|
11
|
+
|
12
|
+
def content_type
|
13
|
+
@content_type
|
14
|
+
end
|
15
|
+
|
16
|
+
def size
|
17
|
+
@size
|
18
|
+
end
|
19
|
+
|
20
|
+
def nil?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def fingerprint
|
25
|
+
@fingerprint ||= Digest::MD5.file(path).to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def read(length = nil, buffer = nil)
|
29
|
+
@tempfile.read(length, buffer)
|
30
|
+
end
|
31
|
+
|
32
|
+
# We don't use this directly, but aws/sdk does.
|
33
|
+
def rewind
|
34
|
+
@tempfile.rewind
|
35
|
+
end
|
36
|
+
|
37
|
+
def eof?
|
38
|
+
@tempfile.eof?
|
39
|
+
end
|
40
|
+
|
41
|
+
def path
|
42
|
+
@tempfile.path
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def cache_current_values
|
48
|
+
@tempfile = copy_to_tempfile(@target)
|
49
|
+
@original_filename = @target.original_filename
|
50
|
+
@content_type = @target.content_type
|
51
|
+
@size = @tempfile.size || @target.size
|
52
|
+
end
|
53
|
+
|
54
|
+
def copy_to_tempfile(src)
|
55
|
+
dest = Tempfile.new(src.original_filename)
|
56
|
+
dest.binmode
|
57
|
+
if src.respond_to? :copy_to_local_file
|
58
|
+
src.copy_to_local_file(:original, dest.path)
|
59
|
+
else
|
60
|
+
FileUtils.cp(src.path(:original), dest.path)
|
61
|
+
end
|
62
|
+
dest
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
Paperclip.io_adapters.register Paperclip::AttachmentAdapter do |target|
|
68
|
+
Paperclip::Attachment === target
|
69
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class FileAdapter
|
3
|
+
def initialize(target)
|
4
|
+
@target = target
|
5
|
+
@tempfile = copy_to_tempfile(@target)
|
6
|
+
end
|
7
|
+
|
8
|
+
def original_filename
|
9
|
+
if @target.respond_to?(:original_filename)
|
10
|
+
@target.original_filename
|
11
|
+
else
|
12
|
+
File.basename(@target.path)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def content_type
|
17
|
+
types = MIME::Types.type_for(original_filename)
|
18
|
+
if types.length == 0
|
19
|
+
type_from_file_command
|
20
|
+
elsif types.length == 1
|
21
|
+
types.first.content_type
|
22
|
+
else
|
23
|
+
best_content_type_option(types)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def fingerprint
|
28
|
+
@fingerprint ||= Digest::MD5.file(path).to_s
|
29
|
+
end
|
30
|
+
|
31
|
+
def size
|
32
|
+
File.size(@tempfile)
|
33
|
+
end
|
34
|
+
|
35
|
+
def nil?
|
36
|
+
@target.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def read(length = nil, buffer = nil)
|
40
|
+
@tempfile.read(length, buffer)
|
41
|
+
end
|
42
|
+
|
43
|
+
# We don't use this directly, but aws/sdk does.
|
44
|
+
def rewind
|
45
|
+
@tempfile.rewind
|
46
|
+
end
|
47
|
+
|
48
|
+
def eof?
|
49
|
+
@tempfile.eof?
|
50
|
+
end
|
51
|
+
|
52
|
+
def path
|
53
|
+
@tempfile.path
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def copy_to_tempfile(src)
|
59
|
+
dest = Tempfile.new(original_filename)
|
60
|
+
dest.binmode
|
61
|
+
FileUtils.cp(src.path, dest.path)
|
62
|
+
dest
|
63
|
+
end
|
64
|
+
|
65
|
+
def best_content_type_option(types)
|
66
|
+
types.reject {|type| type.content_type.match(/\/x-/) }.first.content_type
|
67
|
+
end
|
68
|
+
|
69
|
+
def type_from_file_command
|
70
|
+
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
|
71
|
+
type = (self.original_filename.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
|
72
|
+
mime_type = (Paperclip.run("file", "-b --mime :file", :file => self.path).split(/[:;\s]+/)[0] rescue "application/x-#{type}")
|
73
|
+
mime_type = "application/x-#{type}" if mime_type.match(/\(.*?\)/)
|
74
|
+
mime_type
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
Paperclip.io_adapters.register Paperclip::FileAdapter do |target|
|
80
|
+
File === target || Tempfile === target
|
81
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class NilAdapter
|
3
|
+
def initialize(target)
|
4
|
+
end
|
5
|
+
|
6
|
+
def original_filename
|
7
|
+
""
|
8
|
+
end
|
9
|
+
|
10
|
+
def content_type
|
11
|
+
""
|
12
|
+
end
|
13
|
+
|
14
|
+
def size
|
15
|
+
0
|
16
|
+
end
|
17
|
+
|
18
|
+
def nil?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def read(*args)
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def eof?
|
27
|
+
true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Paperclip.io_adapters.register Paperclip::NilAdapter do |target|
|
33
|
+
target.nil?
|
34
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class AdapterRegistry
|
3
|
+
class NoHandlerError < Paperclip::Error; end
|
4
|
+
|
5
|
+
attr_reader :registered_handlers
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@registered_handlers = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def register(handler_class, &block)
|
12
|
+
@registered_handlers << [block, handler_class]
|
13
|
+
end
|
14
|
+
|
15
|
+
def handler_for(target)
|
16
|
+
@registered_handlers.each do |tester, handler|
|
17
|
+
return handler if tester.call(target)
|
18
|
+
end
|
19
|
+
raise NoHandlerError.new("No handler found for #{target.inspect}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def registered?(target)
|
23
|
+
@registered_handlers.any? do |tester, handler|
|
24
|
+
handler === target
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def for(target)
|
29
|
+
handler_for(target).new(target)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class StringioAdapter
|
3
|
+
def initialize(target)
|
4
|
+
@target = target
|
5
|
+
@tempfile = copy_to_tempfile(@target)
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_writer :original_filename, :content_type
|
9
|
+
|
10
|
+
def original_filename
|
11
|
+
@original_filename ||= @target.original_filename if @target.respond_to?(:original_filename)
|
12
|
+
@original_filename ||= "stringio.txt"
|
13
|
+
@original_filename.strip
|
14
|
+
end
|
15
|
+
|
16
|
+
def content_type
|
17
|
+
@content_type ||= @target.content_type if @target.respond_to?(:content_type)
|
18
|
+
@content_type ||= "text/plain"
|
19
|
+
@content_type
|
20
|
+
end
|
21
|
+
|
22
|
+
def size
|
23
|
+
@target.size
|
24
|
+
end
|
25
|
+
|
26
|
+
def fingerprint
|
27
|
+
Digest::MD5.hexdigest(read)
|
28
|
+
end
|
29
|
+
|
30
|
+
def read(length = nil, buffer = nil)
|
31
|
+
@tempfile.read(length, buffer)
|
32
|
+
end
|
33
|
+
|
34
|
+
# We don't use this directly, but aws/sdk does.
|
35
|
+
def rewind
|
36
|
+
@tempfile.rewind
|
37
|
+
end
|
38
|
+
|
39
|
+
def eof?
|
40
|
+
@tempfile.eof?
|
41
|
+
end
|
42
|
+
|
43
|
+
def path
|
44
|
+
@tempfile.path
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def copy_to_tempfile(src)
|
50
|
+
dest = Tempfile.new(original_filename)
|
51
|
+
dest.binmode
|
52
|
+
while data = src.read(16*1024)
|
53
|
+
dest.write(data)
|
54
|
+
end
|
55
|
+
dest.rewind
|
56
|
+
dest
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Paperclip.io_adapters.register Paperclip::StringioAdapter do |target|
|
63
|
+
StringIO === target
|
64
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Paperclip
|
2
|
+
class UploadedFileAdapter
|
3
|
+
def initialize(target)
|
4
|
+
@target = target
|
5
|
+
|
6
|
+
if @target.respond_to?(:tempfile)
|
7
|
+
@tempfile = copy_to_tempfile(@target.tempfile)
|
8
|
+
else
|
9
|
+
@tempfile = copy_to_tempfile(@target)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def original_filename
|
14
|
+
@target.original_filename
|
15
|
+
end
|
16
|
+
|
17
|
+
def content_type
|
18
|
+
@target.content_type
|
19
|
+
end
|
20
|
+
|
21
|
+
def fingerprint
|
22
|
+
@fingerprint ||= Digest::MD5.file(path).to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
def size
|
26
|
+
File.size(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def nil?
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
def read(length = nil, buffer = nil)
|
34
|
+
@tempfile.read(length, buffer)
|
35
|
+
end
|
36
|
+
|
37
|
+
# We don't use this directly, but aws/sdk does.
|
38
|
+
def rewind
|
39
|
+
@tempfile.rewind
|
40
|
+
end
|
41
|
+
|
42
|
+
def eof?
|
43
|
+
@tempfile.eof?
|
44
|
+
end
|
45
|
+
|
46
|
+
def path
|
47
|
+
@tempfile.path
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def copy_to_tempfile(src)
|
53
|
+
dest = Tempfile.new(original_filename)
|
54
|
+
dest.binmode
|
55
|
+
FileUtils.cp(src.path, dest.path)
|
56
|
+
dest
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Paperclip.io_adapters.register Paperclip::UploadedFileAdapter do |target|
|
62
|
+
target.class.name.include?("UploadedFile")
|
63
|
+
end
|