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.

Files changed (56) hide show
  1. data/Appraisals +3 -3
  2. data/NEWS +43 -0
  3. data/README.md +81 -5
  4. data/features/basic_integration.feature +20 -2
  5. data/features/migration.feature +94 -0
  6. data/features/step_definitions/attachment_steps.rb +28 -0
  7. data/features/step_definitions/rails_steps.rb +19 -1
  8. data/features/step_definitions/web_steps.rb +3 -3
  9. data/gemfiles/3.0.gemfile +1 -1
  10. data/gemfiles/3.1.gemfile +1 -1
  11. data/gemfiles/3.2.gemfile +1 -1
  12. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +4 -8
  13. data/lib/paperclip.rb +2 -0
  14. data/lib/paperclip/attachment.rb +4 -0
  15. data/lib/paperclip/geometry.rb +33 -0
  16. data/lib/paperclip/glue.rb +2 -1
  17. data/lib/paperclip/io_adapters/abstract_adapter.rb +45 -0
  18. data/lib/paperclip/io_adapters/attachment_adapter.rb +13 -48
  19. data/lib/paperclip/io_adapters/file_adapter.rb +11 -61
  20. data/lib/paperclip/io_adapters/identity_adapter.rb +1 -1
  21. data/lib/paperclip/io_adapters/nil_adapter.rb +1 -1
  22. data/lib/paperclip/io_adapters/stringio_adapter.rb +11 -42
  23. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +6 -45
  24. data/lib/paperclip/matchers.rb +2 -2
  25. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +36 -17
  26. data/lib/paperclip/railtie.rb +5 -1
  27. data/lib/paperclip/schema.rb +59 -23
  28. data/lib/paperclip/storage/filesystem.rb +5 -0
  29. data/lib/paperclip/storage/fog.rb +36 -14
  30. data/lib/paperclip/storage/s3.rb +14 -16
  31. data/lib/paperclip/style.rb +2 -2
  32. data/lib/paperclip/tempfile_factory.rb +21 -0
  33. data/lib/paperclip/thumbnail.rb +10 -1
  34. data/lib/paperclip/version.rb +1 -1
  35. data/paperclip.gemspec +1 -1
  36. data/test/attachment_test.rb +56 -24
  37. data/test/fixtures/animated +0 -0
  38. data/test/fixtures/animated.unknown +0 -0
  39. data/test/generator_test.rb +26 -24
  40. data/test/geometry_test.rb +19 -0
  41. data/test/helper.rb +8 -0
  42. data/test/integration_test.rb +23 -23
  43. data/test/io_adapters/abstract_adapter_test.rb +44 -0
  44. data/test/io_adapters/attachment_adapter_test.rb +96 -34
  45. data/test/io_adapters/file_adapter_test.rb +13 -1
  46. data/test/io_adapters/stringio_adapter_test.rb +9 -10
  47. data/test/io_adapters/uploaded_file_adapter_test.rb +2 -1
  48. data/test/schema_test.rb +179 -77
  49. data/test/storage/filesystem_test.rb +18 -3
  50. data/test/storage/fog_test.rb +64 -1
  51. data/test/storage/s3_test.rb +38 -2
  52. data/test/tempfile_factory_test.rb +13 -0
  53. data/test/thumbnail_test.rb +45 -0
  54. metadata +16 -9
  55. data/features/support/fixtures/.boot_config.rb.swo +0 -0
  56. data/images.rake +0 -21
@@ -1,3 +1,3 @@
1
1
  module Paperclip
2
- VERSION = "3.0.4" unless defined? Paperclip::VERSION
2
+ VERSION = "3.1.0" unless defined? Paperclip::VERSION
3
3
  end
@@ -37,7 +37,7 @@ Gem::Specification.new do |s|
37
37
  s.add_development_dependency('aws-sdk')
38
38
  s.add_development_dependency('bourne')
39
39
  s.add_development_dependency('sqlite3', '~> 1.3.4')
40
- s.add_development_dependency('cucumber', '~> 1.1.0')
40
+ s.add_development_dependency('cucumber', '~> 1.2.1')
41
41
  s.add_development_dependency('aruba')
42
42
  s.add_development_dependency('nokogiri')
43
43
  s.add_development_dependency('capybara')
@@ -28,15 +28,15 @@ class AttachmentTest < Test::Unit::TestCase
28
28
  dummy.avatar = file
29
29
  dummy.save
30
30
 
31
- assert File.exists?(dummy.avatar.path(:small))
32
- assert File.exists?(dummy.avatar.path(:large))
33
- assert File.exists?(dummy.avatar.path(:original))
31
+ assert_file_exists(dummy.avatar.path(:small))
32
+ assert_file_exists(dummy.avatar.path(:large))
33
+ assert_file_exists(dummy.avatar.path(:original))
34
34
 
35
35
  dummy.avatar.reprocess!(:small)
36
36
 
37
- assert File.exists?(dummy.avatar.path(:small))
38
- assert File.exists?(dummy.avatar.path(:large))
39
- assert File.exists?(dummy.avatar.path(:original))
37
+ assert_file_exists(dummy.avatar.path(:small))
38
+ assert_file_exists(dummy.avatar.path(:large))
39
+ assert_file_exists(dummy.avatar.path(:original))
40
40
  end
41
41
 
42
42
  should "handle a boolean second argument to #url" do
@@ -742,21 +742,53 @@ class AttachmentTest < Test::Unit::TestCase
742
742
  context "Attachment with reserved filename" do
743
743
  setup do
744
744
  rebuild_model
745
- @file = Paperclip.io_adapters.for(StringIO.new("."))
745
+ @file = Tempfile.new(["filename","png"])
746
+ end
747
+
748
+ teardown do
749
+ @file.unlink
746
750
  end
747
751
 
748
752
  context "with default configuration" do
749
753
  "&$+,/:;=?@<>[]{}|\^~%# ".split(//).each do |character|
750
754
  context "with character #{character}" do
751
- setup do
752
- @file.original_filename = "file#{character}name.png"
753
- @dummy = Dummy.new
754
- @dummy.avatar = @file
755
+
756
+ context "at beginning of filename" do
757
+ setup do
758
+ @file.stubs(:original_filename).returns("#{character}filename.png")
759
+ @dummy = Dummy.new
760
+ @dummy.avatar = @file
761
+ end
762
+
763
+ should "convert special character into underscore" do
764
+ assert_equal "_filename.png", @dummy.avatar.original_filename
765
+ end
766
+ end
767
+
768
+ context "at end of filename" do
769
+ setup do
770
+ @file.stubs(:original_filename).returns("filename.png#{character}")
771
+ @dummy = Dummy.new
772
+ @dummy.avatar = @file
773
+ end
774
+
775
+ should "convert special character into underscore" do
776
+ assert_equal "filename.png_", @dummy.avatar.original_filename
777
+ end
755
778
  end
756
779
 
757
- should "convert special character into underscore" do
758
- assert_equal "file_name.png", @dummy.avatar.original_filename
780
+ context "in the middle of filename" do
781
+ setup do
782
+ @file.stubs(:original_filename).returns("file#{character}name.png")
783
+ @dummy = Dummy.new
784
+ @dummy.avatar = @file
785
+ end
786
+
787
+ should "convert special character into underscore" do
788
+ assert_equal "file_name.png", @dummy.avatar.original_filename
789
+ end
759
790
  end
791
+
760
792
  end
761
793
  end
762
794
  end
@@ -925,7 +957,7 @@ class AttachmentTest < Test::Unit::TestCase
925
957
 
926
958
  should "commit the files to disk" do
927
959
  [:large, :medium, :small].each do |style|
928
- assert File.exists?(@attachment.path(style))
960
+ assert_file_exists(@attachment.path(style))
929
961
  end
930
962
  end
931
963
 
@@ -957,7 +989,7 @@ class AttachmentTest < Test::Unit::TestCase
957
989
  @attachment.expects(:instance_write).with(:updated_at, nil)
958
990
  @attachment.assign nil
959
991
  @attachment.save
960
- @existing_names.each{|f| assert ! File.exists?(f) }
992
+ @existing_names.each{|f| assert_file_not_exists(f) }
961
993
  end
962
994
 
963
995
  should "delete the files when you call #clear and #save" do
@@ -968,7 +1000,7 @@ class AttachmentTest < Test::Unit::TestCase
968
1000
  @attachment.expects(:instance_write).with(:updated_at, nil)
969
1001
  @attachment.clear
970
1002
  @attachment.save
971
- @existing_names.each{|f| assert ! File.exists?(f) }
1003
+ @existing_names.each{|f| assert_file_not_exists(f) }
972
1004
  end
973
1005
 
974
1006
  should "delete the files when you call #delete" do
@@ -978,7 +1010,7 @@ class AttachmentTest < Test::Unit::TestCase
978
1010
  @attachment.expects(:instance_write).with(:fingerprint, nil)
979
1011
  @attachment.expects(:instance_write).with(:updated_at, nil)
980
1012
  @attachment.destroy
981
- @existing_names.each{|f| assert ! File.exists?(f) }
1013
+ @existing_names.each{|f| assert_file_not_exists(f) }
982
1014
  end
983
1015
 
984
1016
  context "when keeping old files" do
@@ -994,7 +1026,7 @@ class AttachmentTest < Test::Unit::TestCase
994
1026
  @attachment.expects(:instance_write).with(:updated_at, nil)
995
1027
  @attachment.assign nil
996
1028
  @attachment.save
997
- @existing_names.each{|f| assert File.exists?(f) }
1029
+ @existing_names.each{|f| assert_file_exists(f) }
998
1030
  end
999
1031
 
1000
1032
  should "keep the files when you call #clear and #save" do
@@ -1005,7 +1037,7 @@ class AttachmentTest < Test::Unit::TestCase
1005
1037
  @attachment.expects(:instance_write).with(:updated_at, nil)
1006
1038
  @attachment.clear
1007
1039
  @attachment.save
1008
- @existing_names.each{|f| assert File.exists?(f) }
1040
+ @existing_names.each{|f| assert_file_exists(f) }
1009
1041
  end
1010
1042
 
1011
1043
  should "keep the files when you call #delete" do
@@ -1015,7 +1047,7 @@ class AttachmentTest < Test::Unit::TestCase
1015
1047
  @attachment.expects(:instance_write).with(:fingerprint, nil)
1016
1048
  @attachment.expects(:instance_write).with(:updated_at, nil)
1017
1049
  @attachment.destroy
1018
- @existing_names.each{|f| assert File.exists?(f) }
1050
+ @existing_names.each{|f| assert_file_exists(f) }
1019
1051
  end
1020
1052
  end
1021
1053
  end
@@ -1174,12 +1206,12 @@ class AttachmentTest < Test::Unit::TestCase
1174
1206
 
1175
1207
  should "not delete the files from storage when attachment is destroyed" do
1176
1208
  @attachment.destroy
1177
- assert File.exists?(@path)
1209
+ assert_file_exists(@path)
1178
1210
  end
1179
1211
 
1180
1212
  should "not delete the file when model is destroyed" do
1181
1213
  @dummy.destroy
1182
- assert File.exists?(@path)
1214
+ assert_file_exists(@path)
1183
1215
  end
1184
1216
  end
1185
1217
 
@@ -1203,12 +1235,12 @@ class AttachmentTest < Test::Unit::TestCase
1203
1235
  @dummy.destroy
1204
1236
  end
1205
1237
 
1206
- assert File.exists?(@path), "#{@path} does not exist."
1238
+ assert_file_exists(@path)
1207
1239
  end
1208
1240
 
1209
1241
  should "be deleted when the model is destroyed" do
1210
1242
  @dummy.destroy
1211
- assert ! File.exists?(@path), "#{@path} does not exist."
1243
+ assert_file_not_exists(@path)
1212
1244
  end
1213
1245
  end
1214
1246
 
Binary file
@@ -18,17 +18,21 @@ class GeneratorTest < Rails::Generators::TestCase
18
18
  assert_match /class AddAttachmentAvatarToUsers/, migration
19
19
 
20
20
  assert_class_method :up, migration do |up|
21
- assert_match /add_column :users, :avatar_file_name, :string/, up
22
- assert_match /add_column :users, :avatar_content_type, :string/, up
23
- assert_match /add_column :users, :avatar_file_size, :integer/, up
24
- assert_match /add_column :users, :avatar_updated_at, :datetime/, up
21
+ expected = <<-migration
22
+ change_table :users do |t|
23
+ t.has_attached_file :avatar
24
+ end
25
+ migration
26
+
27
+ assert_equal expected.squish, up.squish
25
28
  end
26
29
 
27
30
  assert_class_method :down, migration do |down|
28
- assert_match /remove_column :users, :avatar_file_name/, down
29
- assert_match /remove_column :users, :avatar_content_type/, down
30
- assert_match /remove_column :users, :avatar_file_size/, down
31
- assert_match /remove_column :users, :avatar_updated_at/, down
31
+ expected = <<-migration
32
+ drop_attached_file :users, :avatar
33
+ migration
34
+
35
+ assert_equal expected.squish, down.squish
32
36
  end
33
37
  end
34
38
  end
@@ -44,25 +48,23 @@ class GeneratorTest < Rails::Generators::TestCase
44
48
  assert_match /class AddAttachmentAvatarPhotoToUsers/, migration
45
49
 
46
50
  assert_class_method :up, migration do |up|
47
- assert_match /add_column :users, :avatar_file_name, :string/, up
48
- assert_match /add_column :users, :avatar_content_type, :string/, up
49
- assert_match /add_column :users, :avatar_file_size, :integer/, up
50
- assert_match /add_column :users, :avatar_updated_at, :datetime/, up
51
- assert_match /add_column :users, :photo_file_name, :string/, up
52
- assert_match /add_column :users, :photo_content_type, :string/, up
53
- assert_match /add_column :users, :photo_file_size, :integer/, up
54
- assert_match /add_column :users, :photo_updated_at, :datetime/, up
51
+ expected = <<-migration
52
+ change_table :users do |t|
53
+ t.has_attached_file :avatar
54
+ t.has_attached_file :photo
55
+ end
56
+ migration
57
+
58
+ assert_equal expected.squish, up.squish
55
59
  end
56
60
 
57
61
  assert_class_method :down, migration do |down|
58
- assert_match /remove_column :users, :avatar_file_name/, down
59
- assert_match /remove_column :users, :avatar_content_type/, down
60
- assert_match /remove_column :users, :avatar_file_size/, down
61
- assert_match /remove_column :users, :avatar_updated_at/, down
62
- assert_match /remove_column :users, :photo_file_name/, down
63
- assert_match /remove_column :users, :photo_content_type/, down
64
- assert_match /remove_column :users, :photo_file_size/, down
65
- assert_match /remove_column :users, :photo_updated_at/, down
62
+ expected = <<-migration
63
+ drop_attached_file :users, :avatar
64
+ drop_attached_file :users, :photo
65
+ migration
66
+
67
+ assert_equal expected.squish, down.squish
66
68
  end
67
69
  end
68
70
  end
@@ -202,5 +202,24 @@ class GeometryTest < Test::Unit::TestCase
202
202
  end
203
203
  end
204
204
  end
205
+
206
+ [['256x256', '150x150!' => [150, 150], '150x150#' => [150, 150], '150x150>' => [150, 150], '150x150<' => [256, 256], '150x150' => [150, 150]],
207
+ ['256x256', '512x512!' => [512, 512], '512x512#' => [512, 512], '512x512>' => [256, 256], '512x512<' => [512, 512], '512x512' => [512, 512]],
208
+ ['600x400', '512x512!' => [512, 512], '512x512#' => [512, 512], '512x512>' => [512, 341], '512x512<' => [600, 400], '512x512' => [512, 341]]].each do |original_size, options|
209
+ options.each_pair do |size, dimensions|
210
+ context "#{original_size} resize_to #{size}" do
211
+ setup do
212
+ @source = Paperclip::Geometry.parse original_size
213
+ @new_geometry = @source.resize_to size
214
+ end
215
+ should "have #{dimensions.first} width" do
216
+ assert_equal dimensions.first, @new_geometry.width
217
+ end
218
+ should "have #{dimensions.last} height" do
219
+ assert_equal dimensions.last, @new_geometry.height
220
+ end
221
+ end
222
+ end
223
+ end
205
224
  end
206
225
  end
@@ -177,3 +177,11 @@ def assert_not_found_response(url)
177
177
  "Expected HTTP response code 404, got #{response.code}"
178
178
  end
179
179
  end
180
+
181
+ def assert_file_exists(path)
182
+ assert File.exists?(path), %(Expect "#{path}" to be exists.)
183
+ end
184
+
185
+ def assert_file_not_exists(path)
186
+ assert !File.exists?(path), %(Expect "#{path}" to not exists.)
187
+ end
@@ -96,14 +96,14 @@ class IntegrationTest < Test::Unit::TestCase
96
96
  @dummy.avatar.post_processing = false
97
97
  @dummy.avatar = @file
98
98
  assert @dummy.save
99
- assert !File.exists?(@thumb_path)
99
+ assert_file_not_exists @thumb_path
100
100
  end
101
101
 
102
102
  should "create the thumbnails upon saving when post_processing is enabled" do
103
103
  @dummy.avatar.post_processing = true
104
104
  @dummy.avatar = @file
105
105
  assert @dummy.save
106
- assert File.exists?(@thumb_path)
106
+ assert_file_exists @thumb_path
107
107
  end
108
108
  end
109
109
 
@@ -126,25 +126,25 @@ class IntegrationTest < Test::Unit::TestCase
126
126
  teardown { @file.close }
127
127
 
128
128
  should "allow us to create all thumbnails in one go" do
129
- assert !File.exists?(@thumb_small_path)
130
- assert !File.exists?(@thumb_large_path)
129
+ assert_file_not_exists(@thumb_small_path)
130
+ assert_file_not_exists(@thumb_large_path)
131
131
 
132
132
  @dummy.avatar.reprocess!
133
133
 
134
- assert File.exists?(@thumb_small_path)
135
- assert File.exists?(@thumb_large_path)
134
+ assert_file_exists(@thumb_small_path)
135
+ assert_file_exists(@thumb_large_path)
136
136
  end
137
137
 
138
138
  should "allow us to selectively create each thumbnail" do
139
- assert !File.exists?(@thumb_small_path)
140
- assert !File.exists?(@thumb_large_path)
139
+ assert_file_not_exists(@thumb_small_path)
140
+ assert_file_not_exists(@thumb_large_path)
141
141
 
142
142
  @dummy.avatar.reprocess! :thumb_small
143
- assert File.exists?(@thumb_small_path)
144
- assert !File.exists?(@thumb_large_path)
143
+ assert_file_exists(@thumb_small_path)
144
+ assert_file_not_exists(@thumb_large_path)
145
145
 
146
146
  @dummy.avatar.reprocess! :thumb_large
147
- assert File.exists?(@thumb_large_path)
147
+ assert_file_exists(@thumb_large_path)
148
148
  end
149
149
  end
150
150
 
@@ -182,7 +182,7 @@ class IntegrationTest < Test::Unit::TestCase
182
182
  end
183
183
 
184
184
  should "have a large file in the right place" do
185
- assert File.exists?(@dummy.avatar.path(:large))
185
+ assert_file_exists(@dummy.avatar.path(:large))
186
186
  end
187
187
 
188
188
  context "and deleted" do
@@ -192,12 +192,12 @@ class IntegrationTest < Test::Unit::TestCase
192
192
  end
193
193
 
194
194
  should "not have a large file in the right place anymore" do
195
- assert ! File.exists?(@saved_path)
195
+ assert_file_not_exists(@saved_path)
196
196
  end
197
197
 
198
198
  should "not have its next two parent directories" do
199
- assert ! File.exists?(File.dirname(@saved_path))
200
- assert ! File.exists?(File.dirname(File.dirname(@saved_path)))
199
+ assert_file_not_exists(File.dirname(@saved_path))
200
+ assert_file_not_exists(File.dirname(File.dirname(@saved_path)))
201
201
  end
202
202
 
203
203
  before_should "not die if an unexpected SystemCallError happens" do
@@ -334,7 +334,7 @@ class IntegrationTest < Test::Unit::TestCase
334
334
  assert @dummy.save
335
335
 
336
336
  saved_paths.each do |p|
337
- assert File.exists?(p)
337
+ assert_file_exists(p)
338
338
  end
339
339
 
340
340
  @dummy.avatar.clear
@@ -343,7 +343,7 @@ class IntegrationTest < Test::Unit::TestCase
343
343
  assert @dummy.save
344
344
 
345
345
  saved_paths.each do |p|
346
- assert ! File.exists?(p)
346
+ assert_file_not_exists(p)
347
347
  end
348
348
 
349
349
  @d2 = Dummy.find(@dummy.id)
@@ -364,7 +364,7 @@ class IntegrationTest < Test::Unit::TestCase
364
364
  assert @d2.save
365
365
 
366
366
  saved_paths.each do |p|
367
- assert ! File.exists?(p)
367
+ assert_file_not_exists(p)
368
368
  end
369
369
  end
370
370
 
@@ -457,8 +457,8 @@ class IntegrationTest < Test::Unit::TestCase
457
457
  end
458
458
 
459
459
  should "be accessible" do
460
- assert File.exists?(@dummy.avatar.path(:original))
461
- assert File.exists?(@dummy.avatar.path(:thumb))
460
+ assert_file_exists(@dummy.avatar.path(:original))
461
+ assert_file_exists(@dummy.avatar.path(:thumb))
462
462
  end
463
463
 
464
464
  context "when new style is added" do
@@ -469,9 +469,9 @@ class IntegrationTest < Test::Unit::TestCase
469
469
  end
470
470
 
471
471
  should "make all the styles accessible" do
472
- assert File.exists?(@dummy.avatar.path(:original))
473
- assert File.exists?(@dummy.avatar.path(:thumb))
474
- assert File.exists?(@dummy.avatar.path(:mini))
472
+ assert_file_exists(@dummy.avatar.path(:original))
473
+ assert_file_exists(@dummy.avatar.path(:thumb))
474
+ assert_file_exists(@dummy.avatar.path(:mini))
475
475
  end
476
476
  end
477
477
  end
@@ -0,0 +1,44 @@
1
+ require './test/helper'
2
+
3
+ class AbstractAdapterTest < Test::Unit::TestCase
4
+ class TestAdapter < Paperclip::AbstractAdapter
5
+ attr_accessor :original_file_name, :tempfile
6
+
7
+ def content_type
8
+ type_from_file_command
9
+ end
10
+ end
11
+
12
+ context "content type from file command" do
13
+ setup do
14
+ @adapter = TestAdapter.new
15
+ @adapter.stubs(:path)
16
+ Paperclip.stubs(:run).returns("image/png\n")
17
+ end
18
+
19
+ should "return the content type without newline" do
20
+ assert_equal "image/png", @adapter.content_type
21
+ end
22
+ end
23
+
24
+ context "nil?" do
25
+ should "return false" do
26
+ assert !TestAdapter.new.nil?
27
+ end
28
+ end
29
+
30
+ context "delegation" do
31
+ setup do
32
+ @adapter = TestAdapter.new
33
+ @adapter.tempfile = stub("Tempfile")
34
+ end
35
+
36
+ [:close, :closed?, :eof?, :path, :rewind, :unlink].each do |method|
37
+ should "delegate #{method} to @tempfile" do
38
+ @adapter.tempfile.stubs(method)
39
+ @adapter.public_send(method)
40
+ assert_received @adapter.tempfile, method
41
+ end
42
+ end
43
+ end
44
+ end