paperclip 3.4.2 → 3.5.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 (50) hide show
  1. checksums.yaml +15 -0
  2. data/.travis.yml +0 -1
  3. data/Appraisals +4 -4
  4. data/NEWS +16 -0
  5. data/README.md +21 -2
  6. data/features/step_definitions/rails_steps.rb +9 -0
  7. data/features/step_definitions/s3_steps.rb +1 -1
  8. data/features/support/fakeweb.rb +4 -1
  9. data/lib/paperclip.rb +6 -42
  10. data/lib/paperclip/attachment.rb +25 -27
  11. data/lib/paperclip/filename_cleaner.rb +16 -0
  12. data/lib/paperclip/glue.rb +0 -1
  13. data/lib/paperclip/has_attached_file.rb +86 -0
  14. data/lib/paperclip/io_adapters/abstract_adapter.rb +8 -0
  15. data/lib/paperclip/io_adapters/data_uri_adapter.rb +27 -0
  16. data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
  17. data/lib/paperclip/io_adapters/stringio_adapter.rb +3 -3
  18. data/lib/paperclip/matchers/have_attached_file_matcher.rb +1 -5
  19. data/lib/paperclip/missing_attachment_styles.rb +11 -16
  20. data/lib/paperclip/storage/filesystem.rb +7 -3
  21. data/lib/paperclip/storage/s3.rb +2 -0
  22. data/lib/paperclip/tasks/attachments.rb +59 -0
  23. data/lib/paperclip/validators.rb +21 -2
  24. data/lib/paperclip/validators/attachment_content_type_validator.rb +9 -2
  25. data/lib/paperclip/validators/attachment_presence_validator.rb +8 -8
  26. data/lib/paperclip/validators/attachment_size_validator.rb +12 -7
  27. data/lib/paperclip/version.rb +1 -1
  28. data/lib/tasks/paperclip.rake +24 -6
  29. data/paperclip.gemspec +5 -3
  30. data/test/attachment_processing_test.rb +69 -15
  31. data/test/attachment_test.rb +49 -0
  32. data/test/filename_cleaner_test.rb +14 -0
  33. data/test/has_attached_file_test.rb +109 -0
  34. data/test/helper.rb +1 -1
  35. data/test/integration_test.rb +1 -65
  36. data/test/io_adapters/abstract_adapter_test.rb +8 -0
  37. data/test/io_adapters/data_uri_adapter_test.rb +60 -0
  38. data/test/io_adapters/empty_string_adapter_test.rb +17 -0
  39. data/test/paperclip_missing_attachment_styles_test.rb +4 -8
  40. data/test/paperclip_test.rb +0 -5
  41. data/test/rake_test.rb +103 -0
  42. data/test/storage/s3_test.rb +13 -1
  43. data/test/tasks/attachments_test.rb +77 -0
  44. data/test/validators/attachment_content_type_validator_test.rb +26 -0
  45. data/test/validators/attachment_size_validator_test.rb +10 -0
  46. data/test/validators_test.rb +8 -1
  47. metadata +56 -77
  48. data/lib/paperclip/attachment_options.rb +0 -9
  49. data/lib/paperclip/instance_methods.rb +0 -35
  50. data/test/attachment_options_test.rb +0 -27
@@ -25,12 +25,12 @@ Gem::Specification.new do |s|
25
25
  s.requirements << "ImageMagick"
26
26
  s.required_ruby_version = ">= 1.9.2"
27
27
 
28
- s.add_dependency('activerecord', '>= 3.0.0')
29
28
  s.add_dependency('activemodel', '>= 3.0.0')
30
29
  s.add_dependency('activesupport', '>= 3.0.0')
31
30
  s.add_dependency('cocaine', '~> 0.5.0')
32
31
  s.add_dependency('mime-types')
33
32
 
33
+ s.add_development_dependency('activerecord', '>= 3.0.0')
34
34
  s.add_development_dependency('shoulda')
35
35
  s.add_development_dependency('appraisal')
36
36
  s.add_development_dependency('mocha')
@@ -40,13 +40,15 @@ Gem::Specification.new do |s|
40
40
  s.add_development_dependency('cucumber', '~> 1.2.1')
41
41
  s.add_development_dependency('aruba')
42
42
  s.add_development_dependency('nokogiri')
43
- s.add_development_dependency('capybara')
43
+ # Ruby version < 1.9.3 can't install capybara > 2.0.3.
44
+ s.add_development_dependency('capybara', '= 2.0.3')
44
45
  s.add_development_dependency('bundler')
45
46
  s.add_development_dependency('fog', '>= 1.4.0', "< 1.7.0")
46
47
  s.add_development_dependency('pry')
48
+ s.add_development_dependency('pry-debugger')
47
49
  s.add_development_dependency('launchy')
48
50
  s.add_development_dependency('rake')
49
51
  s.add_development_dependency('fakeweb')
50
52
  s.add_development_dependency('railties')
51
- s.add_development_dependency('actionmailer')
53
+ s.add_development_dependency('actionmailer', '>= 3.0.0')
52
54
  end
@@ -7,23 +7,77 @@ class AttachmentProcessingTest < Test::Unit::TestCase
7
7
  rebuild_model
8
8
  end
9
9
 
10
- should 'process attachments given a valid assignment' do
11
- file = File.new(fixture_file("5k.png"))
12
- Dummy.validates_attachment_content_type :avatar, :content_type => "image/png"
13
- instance = Dummy.new
14
- attachment = instance.avatar
15
- attachment.expects(:post_process)
16
-
17
- attachment.assign(file)
10
+ context 'using validates_attachment_content_type' do
11
+ should 'process attachments given a valid assignment' do
12
+ file = File.new(fixture_file("5k.png"))
13
+ Dummy.validates_attachment_content_type :avatar, :content_type => "image/png"
14
+ instance = Dummy.new
15
+ attachment = instance.avatar
16
+ attachment.expects(:post_process_styles)
17
+
18
+ attachment.assign(file)
19
+ end
20
+
21
+ should 'not process attachments given an invalid assignment with :not' do
22
+ file = File.new(fixture_file("5k.png"))
23
+ Dummy.validates_attachment_content_type :avatar, :not => "image/png"
24
+ instance = Dummy.new
25
+ attachment = instance.avatar
26
+ attachment.expects(:post_process_styles).never
27
+
28
+ attachment.assign(file)
29
+ end
30
+
31
+ should 'not process attachments given an invalid assignment with :content_type' do
32
+ file = File.new(fixture_file("5k.png"))
33
+ Dummy.validates_attachment_content_type :avatar, :content_type => "image/tiff"
34
+ instance = Dummy.new
35
+ attachment = instance.avatar
36
+ attachment.expects(:post_process_styles).never
37
+
38
+ attachment.assign(file)
39
+ end
40
+
41
+ should 'when validation :if clause returns false, allow what would be an invalid assignment' do
42
+ invalid_assignment = File.new(fixture_file("5k.png"))
43
+ Dummy.validates_attachment_content_type :avatar, :content_type => "image/tiff", :if => lambda{false}
44
+ instance = Dummy.new
45
+ attachment = instance.avatar
46
+ attachment.expects(:post_process_styles)
47
+
48
+ attachment.assign(invalid_assignment)
49
+ end
18
50
  end
19
51
 
20
- should 'not process attachments if the assignment does not pass validation' do
21
- file = File.new(fixture_file("5k.png"))
22
- Dummy.validates_attachment_content_type :avatar, :content_type => "image/tiff"
23
- instance = Dummy.new
24
- attachment = instance.avatar
25
- attachment.expects(:post_process).never
52
+ context 'using validates_attachment' do
53
+ should 'process attachments given a valid assignment' do
54
+ file = File.new(fixture_file("5k.png"))
55
+ Dummy.validates_attachment :avatar, :content_type => {:content_type => "image/png"}
56
+ instance = Dummy.new
57
+ attachment = instance.avatar
58
+ attachment.expects(:post_process_styles)
59
+
60
+ attachment.assign(file)
61
+ end
62
+
63
+ should 'not process attachments given an invalid assignment with :not' do
64
+ file = File.new(fixture_file("5k.png"))
65
+ Dummy.validates_attachment :avatar, :content_type => {:not => "image/png"}
66
+ instance = Dummy.new
67
+ attachment = instance.avatar
68
+ attachment.expects(:post_process_styles).never
69
+
70
+ attachment.assign(file)
71
+ end
72
+
73
+ should 'not process attachments given an invalid assignment with :content_type' do
74
+ file = File.new(fixture_file("5k.png"))
75
+ Dummy.validates_attachment :avatar, :content_type => {:content_type => "image/tiff"}
76
+ instance = Dummy.new
77
+ attachment = instance.avatar
78
+ attachment.expects(:post_process_styles).never
26
79
 
27
- attachment.assign(file)
80
+ attachment.assign(file)
81
+ end
28
82
  end
29
83
  end
@@ -916,6 +916,41 @@ class AttachmentTest < Test::Unit::TestCase
916
916
  end
917
917
  end
918
918
  end
919
+
920
+ context 'with specified cleaner' do
921
+ setup do
922
+ @old_defaults = Paperclip::Attachment.default_options.dup
923
+ end
924
+
925
+ teardown do
926
+ Paperclip::Attachment.default_options.merge! @old_defaults
927
+ end
928
+
929
+ should 'call the given proc and take the result as cleaned filename' do
930
+ Paperclip::Attachment.default_options[:filename_cleaner] = lambda do |str|
931
+ "from_proc_#{str}"
932
+ end
933
+
934
+ @file.stubs(:original_filename).returns("goood.png")
935
+ @dummy = Dummy.new
936
+ @dummy.avatar = @file
937
+ assert_equal "from_proc_goood.png", @dummy.avatar.original_filename
938
+ end
939
+
940
+ should 'call the given object and take the result as the cleaned filename' do
941
+ class MyCleaner
942
+ def call(filename)
943
+ "foo"
944
+ end
945
+ end
946
+ Paperclip::Attachment.default_options[:filename_cleaner] = MyCleaner.new
947
+
948
+ @file.stubs(:original_filename).returns("goood.png")
949
+ @dummy = Dummy.new
950
+ @dummy.avatar = @file
951
+ assert_equal "foo", @dummy.avatar.original_filename
952
+ end
953
+ end
919
954
  end
920
955
 
921
956
  context "Attachment with uppercase extension and a default style" do
@@ -985,6 +1020,20 @@ class AttachmentTest < Test::Unit::TestCase
985
1020
  end
986
1021
  end
987
1022
 
1023
+ should 'clear out the previous assignment when assigned nil' do
1024
+ @attachment.assign(@file)
1025
+ original_file = @attachment.queued_for_write[:original]
1026
+ @attachment.assign(nil)
1027
+ assert_nil @attachment.queued_for_write[:original]
1028
+ end
1029
+
1030
+ should 'not do anything when it is assigned an empty string' do
1031
+ @attachment.assign(@file)
1032
+ original_file = @attachment.queued_for_write[:original]
1033
+ @attachment.assign("")
1034
+ assert_equal original_file, @attachment.queued_for_write[:original]
1035
+ end
1036
+
988
1037
  should "return nil as path when no file assigned" do
989
1038
  assert_equal nil, @attachment.path
990
1039
  assert_equal nil, @attachment.path(:blah)
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+ require './test/helper'
3
+
4
+ class FilenameCleanerTest < Test::Unit::TestCase
5
+ should 'convert invalid characters to underscores' do
6
+ cleaner = Paperclip::FilenameCleaner.new(/[aeiou]/)
7
+ assert_equal "b_s_b_ll", cleaner.call("baseball")
8
+ end
9
+
10
+ should 'not convert anything if the character regex is nil' do
11
+ cleaner = Paperclip::FilenameCleaner.new(nil)
12
+ assert_equal "baseball", cleaner.call("baseball")
13
+ end
14
+ end
@@ -0,0 +1,109 @@
1
+ require './test/helper'
2
+ require 'paperclip/has_attached_file'
3
+
4
+ class HasAttachedFileTest < Test::Unit::TestCase
5
+ context '#define_on' do
6
+ should 'define a setter on the class object' do
7
+ assert_adding_attachment('avatar').defines_method('avatar=')
8
+ end
9
+
10
+ should 'define a getter on the class object' do
11
+ assert_adding_attachment('avatar').defines_method('avatar')
12
+ end
13
+
14
+ should 'define a query on the class object' do
15
+ assert_adding_attachment('avatar').defines_method('avatar?')
16
+ end
17
+
18
+ should 'flush errors as part of validations' do
19
+ assert_adding_attachment('avatar').defines_validation
20
+ end
21
+
22
+ should 'register the attachment with Paperclip::Tasks' do
23
+ assert_adding_attachment('avatar').registers_with_tasks
24
+ end
25
+
26
+ should 'define an after_save callback' do
27
+ assert_adding_attachment('avatar').defines_callback('after_save')
28
+ end
29
+
30
+ should 'define a before_destroy callback' do
31
+ assert_adding_attachment('avatar').defines_callback('before_destroy')
32
+ end
33
+
34
+ should 'define an after_destroy callback' do
35
+ assert_adding_attachment('avatar').defines_callback('after_destroy')
36
+ end
37
+
38
+ should 'define the Paperclip-specific callbacks' do
39
+ assert_adding_attachment('avatar').defines_callback('define_paperclip_callbacks')
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def assert_adding_attachment(attachment_name)
46
+ AttachmentAdder.new(attachment_name)
47
+ end
48
+
49
+ class AttachmentAdder
50
+ include Mocha::API
51
+ include Test::Unit::Assertions
52
+
53
+ def initialize(attachment_name)
54
+ @attachment_name = attachment_name
55
+ end
56
+
57
+ def defines_method(method_name)
58
+ a_class = stub_class
59
+
60
+ Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
61
+
62
+ assert_received(a_class, :define_method) do |expect|
63
+ expect.with(method_name)
64
+ end
65
+ end
66
+
67
+ def defines_validation
68
+ a_class = stub_class
69
+
70
+ Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
71
+
72
+ assert_received(a_class, :validates_each) do |expect|
73
+ expect.with(@attachment_name)
74
+ end
75
+ end
76
+
77
+ def registers_with_tasks
78
+ a_class = stub_class
79
+ Paperclip::Tasks::Attachments.stubs(:add)
80
+
81
+ Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {size: 1})
82
+
83
+ assert_received(Paperclip::Tasks::Attachments, :add) do |expect|
84
+ expect.with(a_class, @attachment_name, {size: 1})
85
+ end
86
+ end
87
+
88
+ def defines_callback(callback_name)
89
+ a_class = stub_class
90
+
91
+ Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
92
+
93
+ assert_received(a_class, callback_name.to_sym)
94
+ end
95
+
96
+ private
97
+
98
+ def stub_class
99
+ stub('class',
100
+ validates_each: nil,
101
+ define_method: nil,
102
+ after_save: nil,
103
+ before_destroy: nil,
104
+ after_destroy: nil,
105
+ define_paperclip_callbacks: nil,
106
+ name: 'Billy')
107
+ end
108
+ end
109
+ end
@@ -4,7 +4,7 @@ require 'pathname'
4
4
  require 'test/unit'
5
5
 
6
6
  require 'shoulda'
7
- require 'mocha'
7
+ require 'mocha/setup'
8
8
  require 'bourne'
9
9
 
10
10
  require 'active_record'
@@ -207,70 +207,6 @@ class IntegrationTest < Test::Unit::TestCase
207
207
  end
208
208
  end
209
209
 
210
- context "A model with no convert_options setting" do
211
- setup do
212
- rebuild_model :styles => { :large => "300x300>",
213
- :medium => "100x100",
214
- :thumb => ["32x32#", :gif] },
215
- :default_style => :medium,
216
- :url => "/:attachment/:class/:style/:id/:basename.:extension",
217
- :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
218
- @dummy = Dummy.new
219
- end
220
-
221
- should "have its definition return nil when asked about convert_options" do
222
- assert ! Dummy.attachment_definitions[:avatar][:convert_options]
223
- end
224
-
225
- context "redefined to have convert_options setting" do
226
- setup do
227
- rebuild_model :styles => { :large => "300x300>",
228
- :medium => "100x100",
229
- :thumb => ["32x32#", :gif] },
230
- :convert_options => "-strip -depth 8",
231
- :default_style => :medium,
232
- :url => "/:attachment/:class/:style/:id/:basename.:extension",
233
- :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
234
- end
235
-
236
- should "have its definition return convert_options value when asked about convert_options" do
237
- assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options]
238
- end
239
- end
240
- end
241
-
242
- context "A model with no source_file_options setting" do
243
- setup do
244
- rebuild_model :styles => { :large => "300x300>",
245
- :medium => "100x100",
246
- :thumb => ["32x32#", :gif] },
247
- :default_style => :medium,
248
- :url => "/:attachment/:class/:style/:id/:basename.:extension",
249
- :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
250
- @dummy = Dummy.new
251
- end
252
-
253
- should "have its definition return nil when asked about source_file_options" do
254
- assert ! Dummy.attachment_definitions[:avatar][:source_file_options]
255
- end
256
-
257
- context "redefined to have source_file_options setting" do
258
- setup do
259
- rebuild_model :styles => { :large => "300x300>",
260
- :medium => "100x100",
261
- :thumb => ["32x32#", :gif] },
262
- :source_file_options => "-density 400",
263
- :default_style => :medium,
264
- :url => "/:attachment/:class/:style/:id/:basename.:extension",
265
- :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
266
- end
267
-
268
- should "have its definition return source_file_options value when asked about source_file_options" do
269
- assert_equal "-density 400", Dummy.attachment_definitions[:avatar][:source_file_options]
270
- end
271
- end
272
- end
273
-
274
210
  [000,002,022].each do |umask|
275
211
  context "when the umask is #{umask}" do
276
212
  setup do
@@ -412,7 +348,7 @@ class IntegrationTest < Test::Unit::TestCase
412
348
  Dummy.validates_attachment_presence :avatar
413
349
  @d2 = Dummy.find(@dummy.id)
414
350
  @d2.avatar = @file
415
- assert @d2.valid?, @d2.errors.full_messages.inspect
351
+ assert @d2.valid?, @d2.errors.full_messages.inspect
416
352
  @d2.avatar = @bad_file
417
353
  assert ! @d2.valid?
418
354
  end
@@ -47,4 +47,12 @@ class AbstractAdapterTest < Test::Unit::TestCase
47
47
 
48
48
  assert_equal "awesome_file_name.png", @adapter.original_filename
49
49
  end
50
+
51
+ should 'be an assignment' do
52
+ assert TestAdapter.new.assignment?
53
+ end
54
+
55
+ should 'not be nil' do
56
+ assert !TestAdapter.new.nil?
57
+ end
50
58
  end
@@ -0,0 +1,60 @@
1
+ require './test/helper'
2
+
3
+ class DataUriAdapterTest < Test::Unit::TestCase
4
+ context "a new instance" do
5
+ setup do
6
+ @contents = "data:image/png;base64,dGVzdA=="
7
+ @subject = Paperclip.io_adapters.for(@contents)
8
+ end
9
+
10
+ should "return a file name" do
11
+ assert_equal "base64.txt", @subject.original_filename
12
+ end
13
+
14
+ should "return a content type" do
15
+ assert_equal "image/png", @subject.content_type
16
+ end
17
+
18
+ should "return the size of the data" do
19
+ assert_equal 4, @subject.size
20
+ end
21
+
22
+ should "generate an MD5 hash of the contents" do
23
+ assert_equal Digest::MD5.hexdigest(Base64.decode64('dGVzdA==')), @subject.fingerprint
24
+ end
25
+
26
+ should "generate correct fingerprint after read" do
27
+ fingerprint = Digest::MD5.hexdigest(@subject.read)
28
+ assert_equal fingerprint, @subject.fingerprint
29
+ end
30
+
31
+ should "generate same fingerprint" do
32
+ assert_equal @subject.fingerprint, @subject.fingerprint
33
+ end
34
+
35
+ should "return the data contained in the StringIO" do
36
+ assert_equal "test", @subject.read
37
+ end
38
+
39
+ should 'accept a content_type' do
40
+ @subject.content_type = 'image/png'
41
+ assert_equal 'image/png', @subject.content_type
42
+ end
43
+
44
+ should 'accept an original_filename' do
45
+ @subject.original_filename = 'image.png'
46
+ assert_equal 'image.png', @subject.original_filename
47
+ end
48
+
49
+ should "not generate filenames that include restricted characters" do
50
+ @subject.original_filename = 'image:restricted.png'
51
+ assert_equal 'image_restricted.png', @subject.original_filename
52
+ end
53
+
54
+ should "not generate paths that include restricted characters" do
55
+ @subject.original_filename = 'image:restricted.png'
56
+ assert_no_match /:/, @subject.path
57
+ end
58
+
59
+ end
60
+ end