paperclip 3.0.4 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of paperclip might be problematic. Click here for more details.
- data/Appraisals +3 -3
- data/NEWS +43 -0
- data/README.md +81 -5
- data/features/basic_integration.feature +20 -2
- data/features/migration.feature +94 -0
- data/features/step_definitions/attachment_steps.rb +28 -0
- data/features/step_definitions/rails_steps.rb +19 -1
- data/features/step_definitions/web_steps.rb +3 -3
- data/gemfiles/3.0.gemfile +1 -1
- data/gemfiles/3.1.gemfile +1 -1
- data/gemfiles/3.2.gemfile +1 -1
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +4 -8
- data/lib/paperclip.rb +2 -0
- data/lib/paperclip/attachment.rb +4 -0
- data/lib/paperclip/geometry.rb +33 -0
- data/lib/paperclip/glue.rb +2 -1
- data/lib/paperclip/io_adapters/abstract_adapter.rb +45 -0
- data/lib/paperclip/io_adapters/attachment_adapter.rb +13 -48
- data/lib/paperclip/io_adapters/file_adapter.rb +11 -61
- data/lib/paperclip/io_adapters/identity_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/nil_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/stringio_adapter.rb +11 -42
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +6 -45
- data/lib/paperclip/matchers.rb +2 -2
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +36 -17
- data/lib/paperclip/railtie.rb +5 -1
- data/lib/paperclip/schema.rb +59 -23
- data/lib/paperclip/storage/filesystem.rb +5 -0
- data/lib/paperclip/storage/fog.rb +36 -14
- data/lib/paperclip/storage/s3.rb +14 -16
- data/lib/paperclip/style.rb +2 -2
- data/lib/paperclip/tempfile_factory.rb +21 -0
- data/lib/paperclip/thumbnail.rb +10 -1
- data/lib/paperclip/version.rb +1 -1
- data/paperclip.gemspec +1 -1
- data/test/attachment_test.rb +56 -24
- data/test/fixtures/animated +0 -0
- data/test/fixtures/animated.unknown +0 -0
- data/test/generator_test.rb +26 -24
- data/test/geometry_test.rb +19 -0
- data/test/helper.rb +8 -0
- data/test/integration_test.rb +23 -23
- data/test/io_adapters/abstract_adapter_test.rb +44 -0
- data/test/io_adapters/attachment_adapter_test.rb +96 -34
- data/test/io_adapters/file_adapter_test.rb +13 -1
- data/test/io_adapters/stringio_adapter_test.rb +9 -10
- data/test/io_adapters/uploaded_file_adapter_test.rb +2 -1
- data/test/schema_test.rb +179 -77
- data/test/storage/filesystem_test.rb +18 -3
- data/test/storage/fog_test.rb +64 -1
- data/test/storage/s3_test.rb +38 -2
- data/test/tempfile_factory_test.rb +13 -0
- data/test/thumbnail_test.rb +45 -0
- metadata +16 -9
- data/features/support/fixtures/.boot_config.rb.swo +0 -0
- data/images.rake +0 -21
@@ -1,51 +1,113 @@
|
|
1
1
|
require './test/helper'
|
2
2
|
|
3
3
|
class AttachmentAdapterTest < Test::Unit::TestCase
|
4
|
+
|
4
5
|
def setup
|
5
|
-
rebuild_model :path => "tmp/:class/:attachment/:style/:filename"
|
6
|
+
rebuild_model :path => "tmp/:class/:attachment/:style/:filename", :styles => {:thumb => '50x50'}
|
6
7
|
@attachment = Dummy.new.avatar
|
7
|
-
@file = File.new(fixture_file("5k.png"))
|
8
|
-
@file.binmode
|
9
|
-
|
10
|
-
@attachment.assign(@file)
|
11
|
-
@attachment.save
|
12
|
-
@subject = Paperclip.io_adapters.for(@attachment)
|
13
8
|
end
|
9
|
+
|
10
|
+
context "for an attachment" do
|
11
|
+
setup do
|
12
|
+
@file = File.new(fixture_file("5k.png"))
|
13
|
+
@file.binmode
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
@attachment.assign(@file)
|
16
|
+
@attachment.save
|
17
|
+
@subject = Paperclip.io_adapters.for(@attachment)
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
teardown do
|
21
|
+
@file.close
|
22
|
+
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
should "get the right filename" do
|
25
|
+
assert_equal "5k.png", @subject.original_filename
|
26
|
+
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
should "force binmode on tempfile" do
|
29
|
+
assert @subject.instance_variable_get("@tempfile").binmode?
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
should "get the content type" do
|
33
|
+
assert_equal "image/png", @subject.content_type
|
34
|
+
end
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
36
|
+
should "get the file's size" do
|
37
|
+
assert_equal 4456, @subject.size
|
38
|
+
end
|
39
|
+
|
40
|
+
should "return false for a call to nil?" do
|
41
|
+
assert ! @subject.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
should "generate a MD5 hash of the contents" do
|
45
|
+
expected = Digest::MD5.file(@file.path).to_s
|
46
|
+
assert_equal expected, @subject.fingerprint
|
47
|
+
end
|
38
48
|
|
39
|
-
|
40
|
-
|
41
|
-
|
49
|
+
should "read the contents of the file" do
|
50
|
+
expected = @file.read
|
51
|
+
actual = @subject.read
|
52
|
+
assert expected.length > 0
|
53
|
+
assert_equal expected.length, actual.length
|
54
|
+
assert_equal expected, actual
|
55
|
+
end
|
56
|
+
|
42
57
|
end
|
58
|
+
|
59
|
+
context "for a style" do
|
60
|
+
setup do
|
61
|
+
@file = File.new(fixture_file("5k.png"))
|
62
|
+
@file.binmode
|
63
|
+
|
64
|
+
@attachment.assign(@file)
|
65
|
+
|
66
|
+
@thumb = Tempfile.new("thumbnail").tap(&:binmode)
|
67
|
+
FileUtils.cp @attachment.queued_for_write[:thumb].path, @thumb.path
|
68
|
+
|
69
|
+
@attachment.save
|
70
|
+
@subject = Paperclip.io_adapters.for(@attachment.styles[:thumb])
|
71
|
+
end
|
72
|
+
|
73
|
+
teardown do
|
74
|
+
@file.close
|
75
|
+
@thumb.close
|
76
|
+
end
|
77
|
+
|
78
|
+
should "get the original filename" do
|
79
|
+
assert_equal "5k.png", @subject.original_filename
|
80
|
+
end
|
81
|
+
|
82
|
+
should "force binmode on tempfile" do
|
83
|
+
assert @subject.instance_variable_get("@tempfile").binmode?
|
84
|
+
end
|
85
|
+
|
86
|
+
should "get the content type" do
|
87
|
+
assert_equal "image/png", @subject.content_type
|
88
|
+
end
|
89
|
+
|
90
|
+
should "get the thumbnail's file size" do
|
91
|
+
assert_equal @thumb.size, @subject.size
|
92
|
+
end
|
93
|
+
|
94
|
+
should "return false for a call to nil?" do
|
95
|
+
assert ! @subject.nil?
|
96
|
+
end
|
97
|
+
|
98
|
+
should "generate a MD5 hash of the contents" do
|
99
|
+
expected = Digest::MD5.file(@thumb.path).to_s
|
100
|
+
assert_equal expected, @subject.fingerprint
|
101
|
+
end
|
43
102
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
103
|
+
should "read the contents of the thumbnail" do
|
104
|
+
@thumb.rewind
|
105
|
+
expected = @thumb.read
|
106
|
+
actual = @subject.read
|
107
|
+
assert expected.length > 0
|
108
|
+
assert_equal expected.length, actual.length
|
109
|
+
assert_equal expected, actual
|
110
|
+
end
|
111
|
+
|
50
112
|
end
|
51
113
|
end
|
@@ -60,10 +60,22 @@ class FileAdapterTest < Test::Unit::TestCase
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
context "file with multiple possible x-types but no official type" do
|
64
|
+
setup do
|
65
|
+
MIME::Types.stubs(:type_for).returns([MIME::Type.new('image/x-mp4'), MIME::Type.new('image/x-video')])
|
66
|
+
@subject = Paperclip.io_adapters.for(@file)
|
67
|
+
end
|
68
|
+
|
69
|
+
should "return the first" do
|
70
|
+
assert_equal "image/x-mp4", @subject.content_type
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
63
74
|
context "file with content type derived from file command on *nix" do
|
64
75
|
setup do
|
65
76
|
MIME::Types.stubs(:type_for).returns([])
|
66
77
|
Paperclip.stubs(:run).returns("application/vnd.ms-office\n")
|
78
|
+
@subject = Paperclip.io_adapters.for(@file)
|
67
79
|
end
|
68
80
|
|
69
81
|
should "return content type without newline character" do
|
@@ -81,7 +93,7 @@ class FileAdapterTest < Test::Unit::TestCase
|
|
81
93
|
teardown { @file.close }
|
82
94
|
|
83
95
|
should "provide correct mime-type" do
|
84
|
-
|
96
|
+
assert_match %r{.*/x-empty}, @subject.content_type
|
85
97
|
end
|
86
98
|
end
|
87
99
|
end
|
@@ -12,20 +12,10 @@ class StringioFileProxyTest < Test::Unit::TestCase
|
|
12
12
|
assert_equal "stringio.txt", @subject.original_filename
|
13
13
|
end
|
14
14
|
|
15
|
-
should "allow us to set a name" do
|
16
|
-
@subject.original_filename = "data.txt"
|
17
|
-
assert_equal "data.txt", @subject.original_filename
|
18
|
-
end
|
19
|
-
|
20
15
|
should "return a content type" do
|
21
16
|
assert_equal "text/plain", @subject.content_type
|
22
17
|
end
|
23
18
|
|
24
|
-
should "allow us to set a content type" do
|
25
|
-
@subject.content_type = "image/jpg"
|
26
|
-
assert_equal "image/jpg", @subject.content_type
|
27
|
-
end
|
28
|
-
|
29
19
|
should "return the size of the data" do
|
30
20
|
assert_equal 6, @subject.size
|
31
21
|
end
|
@@ -34,6 +24,15 @@ class StringioFileProxyTest < Test::Unit::TestCase
|
|
34
24
|
assert_equal Digest::MD5.hexdigest(@contents), @subject.fingerprint
|
35
25
|
end
|
36
26
|
|
27
|
+
should "generate correct fingerprint after read" do
|
28
|
+
fingerprint = Digest::MD5.hexdigest(@subject.read)
|
29
|
+
assert_equal fingerprint, @subject.fingerprint
|
30
|
+
end
|
31
|
+
|
32
|
+
should "generate same fingerprint" do
|
33
|
+
assert_equal @subject.fingerprint, @subject.fingerprint
|
34
|
+
end
|
35
|
+
|
37
36
|
should "return the data contained in the StringIO" do
|
38
37
|
assert_equal "abc123", @subject.read
|
39
38
|
end
|
@@ -12,7 +12,8 @@ class UploadedFileAdapterTest < Test::Unit::TestCase
|
|
12
12
|
:original_filename => "5k.png",
|
13
13
|
:content_type => "image/png",
|
14
14
|
:head => "",
|
15
|
-
:tempfile => tempfile
|
15
|
+
:tempfile => tempfile,
|
16
|
+
:path => tempfile.path
|
16
17
|
)
|
17
18
|
@subject = Paperclip.io_adapters.for(@file)
|
18
19
|
end
|
data/test/schema_test.rb
CHANGED
@@ -1,98 +1,200 @@
|
|
1
1
|
require './test/helper'
|
2
2
|
require 'paperclip/schema'
|
3
|
+
require 'active_support/testing/deprecation'
|
3
4
|
|
4
|
-
class
|
5
|
-
include
|
6
|
-
|
7
|
-
def initialize(table_name = nil)
|
8
|
-
@table_name = table_name
|
9
|
-
@columns = {}
|
10
|
-
@deleted_columns = []
|
11
|
-
end
|
12
|
-
|
13
|
-
def column(name, type)
|
14
|
-
@columns[name] = type
|
15
|
-
end
|
16
|
-
|
17
|
-
def remove_column(table_name, column_name)
|
18
|
-
return if @table_name && @table_name != table_name
|
19
|
-
@columns.delete(column_name)
|
20
|
-
@deleted_columns.push(column_name)
|
21
|
-
end
|
22
|
-
|
23
|
-
def has_column?(column_name)
|
24
|
-
@columns.key?(column_name)
|
25
|
-
end
|
5
|
+
class SchemaTest < Test::Unit::TestCase
|
6
|
+
include ActiveSupport::Testing::Deprecation
|
26
7
|
|
27
|
-
def
|
28
|
-
|
8
|
+
def setup
|
9
|
+
rebuild_class
|
29
10
|
end
|
30
11
|
|
31
|
-
def
|
32
|
-
|
12
|
+
def teardown
|
13
|
+
Dummy.connection.drop_table :dummies rescue nil
|
33
14
|
end
|
34
|
-
end
|
35
|
-
|
36
|
-
class SchemaTest < Test::Unit::TestCase
|
37
|
-
context "Migrating up" do
|
38
|
-
setup do
|
39
|
-
@schema = MockSchema.new
|
40
|
-
@schema.has_attached_file :avatar
|
41
|
-
end
|
42
|
-
|
43
|
-
should "create the file_name column" do
|
44
|
-
assert @schema.has_column?(:avatar_file_name)
|
45
|
-
end
|
46
|
-
|
47
|
-
should "create the content_type column" do
|
48
|
-
assert @schema.has_column?(:avatar_content_type)
|
49
|
-
end
|
50
|
-
|
51
|
-
should "create the file_size column" do
|
52
|
-
assert @schema.has_column?(:avatar_file_size)
|
53
|
-
end
|
54
|
-
|
55
|
-
should "create the updated_at column" do
|
56
|
-
assert @schema.has_column?(:avatar_updated_at)
|
57
|
-
end
|
58
15
|
|
59
|
-
|
60
|
-
|
16
|
+
context "within table definition" do
|
17
|
+
context "using #has_attached_file" do
|
18
|
+
should "create attachment columns" do
|
19
|
+
Dummy.connection.create_table :dummies, :force => true do |t|
|
20
|
+
ActiveSupport::Deprecation.silence do
|
21
|
+
t.has_attached_file :avatar
|
22
|
+
end
|
23
|
+
end
|
24
|
+
rebuild_class
|
25
|
+
|
26
|
+
columns = Dummy.columns.map{ |column| [column.name, column.type] }
|
27
|
+
|
28
|
+
assert_includes columns, ['avatar_file_name', :string]
|
29
|
+
assert_includes columns, ['avatar_content_type', :string]
|
30
|
+
assert_includes columns, ['avatar_file_size', :integer]
|
31
|
+
assert_includes columns, ['avatar_updated_at', :datetime]
|
32
|
+
end
|
33
|
+
|
34
|
+
should "display deprecation warning" do
|
35
|
+
Dummy.connection.create_table :dummies, :force => true do |t|
|
36
|
+
assert_deprecated do
|
37
|
+
t.has_attached_file :avatar
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
61
41
|
end
|
62
42
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
43
|
+
context "using #attachment" do
|
44
|
+
setup do
|
45
|
+
Dummy.connection.create_table :dummies, :force => true do |t|
|
46
|
+
t.attachment :avatar
|
47
|
+
end
|
48
|
+
rebuild_class
|
49
|
+
end
|
50
|
+
|
51
|
+
should "create attachment columns" do
|
52
|
+
columns = Dummy.columns.map{ |column| [column.name, column.type] }
|
53
|
+
|
54
|
+
assert_includes columns, ['avatar_file_name', :string]
|
55
|
+
assert_includes columns, ['avatar_content_type', :string]
|
56
|
+
assert_includes columns, ['avatar_file_size', :integer]
|
57
|
+
assert_includes columns, ['avatar_updated_at', :datetime]
|
58
|
+
end
|
73
59
|
end
|
74
60
|
end
|
75
61
|
|
76
|
-
context "
|
62
|
+
context "within schema statement" do
|
77
63
|
setup do
|
78
|
-
|
79
|
-
@schema.drop_attached_file :users, :avatar
|
80
|
-
end
|
81
|
-
|
82
|
-
should "remove the file_name column" do
|
83
|
-
assert @schema.deleted_column?(:avatar_file_name)
|
84
|
-
end
|
85
|
-
|
86
|
-
should "remove the content_type column" do
|
87
|
-
assert @schema.deleted_column?(:avatar_content_type)
|
64
|
+
Dummy.connection.create_table :dummies, :force => true
|
88
65
|
end
|
89
66
|
|
90
|
-
|
91
|
-
|
67
|
+
context "migrating up" do
|
68
|
+
context "with single attachment" do
|
69
|
+
setup do
|
70
|
+
Dummy.connection.add_attachment :dummies, :avatar
|
71
|
+
rebuild_class
|
72
|
+
end
|
73
|
+
|
74
|
+
should "create attachment columns" do
|
75
|
+
columns = Dummy.columns.map{ |column| [column.name, column.type] }
|
76
|
+
|
77
|
+
assert_includes columns, ['avatar_file_name', :string]
|
78
|
+
assert_includes columns, ['avatar_content_type', :string]
|
79
|
+
assert_includes columns, ['avatar_file_size', :integer]
|
80
|
+
assert_includes columns, ['avatar_updated_at', :datetime]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with multiple attachments" do
|
85
|
+
setup do
|
86
|
+
Dummy.connection.add_attachment :dummies, :avatar, :photo
|
87
|
+
rebuild_class
|
88
|
+
end
|
89
|
+
|
90
|
+
should "create attachment columns" do
|
91
|
+
columns = Dummy.columns.map{ |column| [column.name, column.type] }
|
92
|
+
|
93
|
+
assert_includes columns, ['avatar_file_name', :string]
|
94
|
+
assert_includes columns, ['avatar_content_type', :string]
|
95
|
+
assert_includes columns, ['avatar_file_size', :integer]
|
96
|
+
assert_includes columns, ['avatar_updated_at', :datetime]
|
97
|
+
assert_includes columns, ['photo_file_name', :string]
|
98
|
+
assert_includes columns, ['photo_content_type', :string]
|
99
|
+
assert_includes columns, ['photo_file_size', :integer]
|
100
|
+
assert_includes columns, ['photo_updated_at', :datetime]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context "with no attachment" do
|
105
|
+
should "raise an error" do
|
106
|
+
assert_raise ArgumentError do
|
107
|
+
Dummy.connection.add_attachment :dummies
|
108
|
+
rebuild_class
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
92
112
|
end
|
93
113
|
|
94
|
-
|
95
|
-
|
114
|
+
context "migrating down" do
|
115
|
+
setup do
|
116
|
+
Dummy.connection.change_table :dummies do |t|
|
117
|
+
t.column :avatar_file_name, :string
|
118
|
+
t.column :avatar_content_type, :string
|
119
|
+
t.column :avatar_file_size, :integer
|
120
|
+
t.column :avatar_updated_at, :datetime
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context "using #drop_attached_file" do
|
125
|
+
should "remove the attachment columns" do
|
126
|
+
ActiveSupport::Deprecation.silence do
|
127
|
+
Dummy.connection.drop_attached_file :dummies, :avatar
|
128
|
+
end
|
129
|
+
rebuild_class
|
130
|
+
|
131
|
+
columns = Dummy.columns.map{ |column| [column.name, column.type] }
|
132
|
+
|
133
|
+
assert_not_includes columns, ['avatar_file_name', :string]
|
134
|
+
assert_not_includes columns, ['avatar_content_type', :string]
|
135
|
+
assert_not_includes columns, ['avatar_file_size', :integer]
|
136
|
+
assert_not_includes columns, ['avatar_updated_at', :datetime]
|
137
|
+
end
|
138
|
+
|
139
|
+
should "display a deprecation warning" do
|
140
|
+
assert_deprecated do
|
141
|
+
Dummy.connection.drop_attached_file :dummies, :avatar
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context "using #remove_attachment" do
|
147
|
+
context "with single attachment" do
|
148
|
+
setup do
|
149
|
+
Dummy.connection.remove_attachment :dummies, :avatar
|
150
|
+
rebuild_class
|
151
|
+
end
|
152
|
+
|
153
|
+
should "remove the attachment columns" do
|
154
|
+
columns = Dummy.columns.map{ |column| [column.name, column.type] }
|
155
|
+
|
156
|
+
assert_not_includes columns, ['avatar_file_name', :string]
|
157
|
+
assert_not_includes columns, ['avatar_content_type', :string]
|
158
|
+
assert_not_includes columns, ['avatar_file_size', :integer]
|
159
|
+
assert_not_includes columns, ['avatar_updated_at', :datetime]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context "with multiple attachments" do
|
164
|
+
setup do
|
165
|
+
Dummy.connection.change_table :dummies do |t|
|
166
|
+
t.column :photo_file_name, :string
|
167
|
+
t.column :photo_content_type, :string
|
168
|
+
t.column :photo_file_size, :integer
|
169
|
+
t.column :photo_updated_at, :datetime
|
170
|
+
end
|
171
|
+
|
172
|
+
Dummy.connection.remove_attachment :dummies, :avatar, :photo
|
173
|
+
rebuild_class
|
174
|
+
end
|
175
|
+
|
176
|
+
should "remove the attachment columns" do
|
177
|
+
columns = Dummy.columns.map{ |column| [column.name, column.type] }
|
178
|
+
|
179
|
+
assert_not_includes columns, ['avatar_file_name', :string]
|
180
|
+
assert_not_includes columns, ['avatar_content_type', :string]
|
181
|
+
assert_not_includes columns, ['avatar_file_size', :integer]
|
182
|
+
assert_not_includes columns, ['avatar_updated_at', :datetime]
|
183
|
+
assert_not_includes columns, ['photo_file_name', :string]
|
184
|
+
assert_not_includes columns, ['photo_content_type', :string]
|
185
|
+
assert_not_includes columns, ['photo_file_size', :integer]
|
186
|
+
assert_not_includes columns, ['photo_updated_at', :datetime]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context "with no attachment" do
|
191
|
+
should "raise an error" do
|
192
|
+
assert_raise ArgumentError do
|
193
|
+
Dummy.connection.remove_attachment :dummies
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
96
198
|
end
|
97
199
|
end
|
98
200
|
end
|