phildarnowsky-paperclip 2.2.10

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.
Files changed (50) hide show
  1. data/LICENSE +26 -0
  2. data/README.rdoc +174 -0
  3. data/Rakefile +99 -0
  4. data/generators/paperclip/USAGE +5 -0
  5. data/generators/paperclip/paperclip_generator.rb +27 -0
  6. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  7. data/init.rb +1 -0
  8. data/lib/paperclip/attachment.rb +461 -0
  9. data/lib/paperclip/callback_compatability.rb +33 -0
  10. data/lib/paperclip/content_type.rb +21 -0
  11. data/lib/paperclip/geometry.rb +115 -0
  12. data/lib/paperclip/interpolations.rb +105 -0
  13. data/lib/paperclip/iostream.rb +58 -0
  14. data/lib/paperclip/matchers/have_attached_file_matcher.rb +49 -0
  15. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +66 -0
  16. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +48 -0
  17. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +83 -0
  18. data/lib/paperclip/matchers.rb +4 -0
  19. data/lib/paperclip/processor.rb +49 -0
  20. data/lib/paperclip/storage.rb +236 -0
  21. data/lib/paperclip/thumbnail.rb +70 -0
  22. data/lib/paperclip/upfile.rb +40 -0
  23. data/lib/paperclip.rb +360 -0
  24. data/paperclip.gemspec +37 -0
  25. data/shoulda_macros/paperclip.rb +68 -0
  26. data/tasks/paperclip_tasks.rake +79 -0
  27. data/test/attachment_test.rb +859 -0
  28. data/test/content_type_test.rb +46 -0
  29. data/test/database.yml +4 -0
  30. data/test/fixtures/12k.png +0 -0
  31. data/test/fixtures/50x50.png +0 -0
  32. data/test/fixtures/5k.png +0 -0
  33. data/test/fixtures/bad.png +1 -0
  34. data/test/fixtures/s3.yml +4 -0
  35. data/test/fixtures/text.txt +0 -0
  36. data/test/fixtures/twopage.pdf +0 -0
  37. data/test/geometry_test.rb +177 -0
  38. data/test/helper.rb +100 -0
  39. data/test/integration_test.rb +484 -0
  40. data/test/interpolations_test.rb +120 -0
  41. data/test/iostream_test.rb +71 -0
  42. data/test/matchers/have_attached_file_matcher_test.rb +21 -0
  43. data/test/matchers/validate_attachment_content_type_matcher_test.rb +30 -0
  44. data/test/matchers/validate_attachment_presence_matcher_test.rb +21 -0
  45. data/test/matchers/validate_attachment_size_matcher_test.rb +50 -0
  46. data/test/paperclip_test.rb +291 -0
  47. data/test/processor_test.rb +10 -0
  48. data/test/storage_test.rb +371 -0
  49. data/test/thumbnail_test.rb +177 -0
  50. metadata +127 -0
@@ -0,0 +1,30 @@
1
+ require 'test/helper'
2
+
3
+ class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase
4
+ context "validate_attachment_content_type" do
5
+ setup do
6
+ reset_table("dummies") do |d|
7
+ d.string :avatar_file_name
8
+ end
9
+ @dummy_class = reset_class "Dummy"
10
+ @dummy_class.has_attached_file :avatar
11
+ @matcher = self.class.validate_attachment_content_type(:avatar).
12
+ allowing(%w(image/png image/jpeg)).
13
+ rejecting(%w(audio/mp3 application/octet-stream))
14
+ end
15
+
16
+ should "reject a class with no validation" do
17
+ assert_rejects @matcher, @dummy_class
18
+ end
19
+
20
+ should "reject a class with a validation that doesn't match" do
21
+ @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*}
22
+ assert_rejects @matcher, @dummy_class
23
+ end
24
+
25
+ should "accept a class with a validation" do
26
+ @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
27
+ assert_accepts @matcher, @dummy_class
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ require 'test/helper'
2
+
3
+ class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase
4
+ context "validate_attachment_presence" do
5
+ setup do
6
+ reset_table("dummies"){|d| d.string :avatar_file_name }
7
+ @dummy_class = reset_class "Dummy"
8
+ @dummy_class.has_attached_file :avatar
9
+ @matcher = self.class.validate_attachment_presence(:avatar)
10
+ end
11
+
12
+ should "reject a class with no validation" do
13
+ assert_rejects @matcher, @dummy_class
14
+ end
15
+
16
+ should "accept a class with a validation" do
17
+ @dummy_class.validates_attachment_presence :avatar
18
+ assert_accepts @matcher, @dummy_class
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,50 @@
1
+ require 'test/helper'
2
+
3
+ class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase
4
+ context "validate_attachment_size" do
5
+ setup do
6
+ reset_table("dummies") do |d|
7
+ d.string :avatar_file_name
8
+ end
9
+ @dummy_class = reset_class "Dummy"
10
+ @dummy_class.has_attached_file :avatar
11
+ end
12
+
13
+ context "of limited size" do
14
+ setup{ @matcher = self.class.validate_attachment_size(:avatar).in(256..1024) }
15
+
16
+ should "reject a class with no validation" do
17
+ assert_rejects @matcher, @dummy_class
18
+ end
19
+
20
+ should "reject a class with a validation that's too high" do
21
+ @dummy_class.validates_attachment_size :avatar, :in => 256..2048
22
+ assert_rejects @matcher, @dummy_class
23
+ end
24
+
25
+ should "reject a class with a validation that's too low" do
26
+ @dummy_class.validates_attachment_size :avatar, :in => 0..1024
27
+ assert_rejects @matcher, @dummy_class
28
+ end
29
+
30
+ should "accept a class with a validation that matches" do
31
+ @dummy_class.validates_attachment_size :avatar, :in => 256..1024
32
+ assert_accepts @matcher, @dummy_class
33
+ end
34
+ end
35
+
36
+ context "validates_attachment_size with infinite range" do
37
+ setup{ @matcher = self.class.validate_attachment_size(:avatar) }
38
+
39
+ should "accept a class with an upper limit" do
40
+ @dummy_class.validates_attachment_size :avatar, :less_than => 1
41
+ assert_accepts @matcher, @dummy_class
42
+ end
43
+
44
+ should "accept a class with no upper limit" do
45
+ @dummy_class.validates_attachment_size :avatar, :greater_than => 1
46
+ assert_accepts @matcher, @dummy_class
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,291 @@
1
+ require 'test/helper'
2
+
3
+ class PaperclipTest < Test::Unit::TestCase
4
+ [:image_magick_path, :convert_path].each do |path|
5
+ context "Calling Paperclip.run with an #{path} specified" do
6
+ setup do
7
+ Paperclip.options[:image_magick_path] = nil
8
+ Paperclip.options[:convert_path] = nil
9
+ Paperclip.options[path] = "/usr/bin"
10
+ end
11
+
12
+ should "execute the right command" do
13
+ Paperclip.expects(:path_for_command).with("convert").returns("/usr/bin/convert")
14
+ Paperclip.expects(:bit_bucket).returns("/dev/null")
15
+ Paperclip.expects(:"`").with("/usr/bin/convert one.jpg two.jpg 2>/dev/null")
16
+ Paperclip.run("convert", "one.jpg two.jpg")
17
+ end
18
+ end
19
+ end
20
+
21
+ context "Calling Paperclip.run with no path specified" do
22
+ setup do
23
+ Paperclip.options[:image_magick_path] = nil
24
+ Paperclip.options[:convert_path] = nil
25
+ end
26
+
27
+ should "execute the right command" do
28
+ Paperclip.expects(:path_for_command).with("convert").returns("convert")
29
+ Paperclip.expects(:bit_bucket).returns("/dev/null")
30
+ Paperclip.expects(:"`").with("convert one.jpg two.jpg 2>/dev/null")
31
+ Paperclip.run("convert", "one.jpg two.jpg")
32
+ end
33
+
34
+ should "log the command when :log_command is set" do
35
+ Paperclip.options[:log_command] = true
36
+ Paperclip.expects(:bit_bucket).returns("/dev/null")
37
+ Paperclip.expects(:log).with("this is the command 2>/dev/null")
38
+ Paperclip.expects(:"`").with("this is the command 2>/dev/null")
39
+ Paperclip.run("this","is the command")
40
+ end
41
+ end
42
+
43
+ should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do
44
+ assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) }
45
+ end
46
+
47
+ should "raise when sent #processor and the name of a class that doesn't exist" do
48
+ assert_raises(NameError){ Paperclip.processor(:boogey_man) }
49
+ end
50
+
51
+ should "return a class when sent #processor and the name of a class under Paperclip" do
52
+ assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail)
53
+ end
54
+
55
+ should "call a proc sent to check_guard" do
56
+ @dummy = Dummy.new
57
+ @dummy.expects(:one).returns(:one)
58
+ assert_equal :one, @dummy.avatar.send(:check_guard, lambda{|x| x.one })
59
+ end
60
+
61
+ should "call a method name sent to check_guard" do
62
+ @dummy = Dummy.new
63
+ @dummy.expects(:one).returns(:one)
64
+ assert_equal :one, @dummy.avatar.send(:check_guard, :one)
65
+ end
66
+
67
+ context "Paperclip.bit_bucket" do
68
+ context "on systems without /dev/null" do
69
+ setup do
70
+ File.expects(:exists?).with("/dev/null").returns(false)
71
+ end
72
+
73
+ should "return 'NUL'" do
74
+ assert_equal "NUL", Paperclip.bit_bucket
75
+ end
76
+ end
77
+
78
+ context "on systems with /dev/null" do
79
+ setup do
80
+ File.expects(:exists?).with("/dev/null").returns(true)
81
+ end
82
+
83
+ should "return '/dev/null'" do
84
+ assert_equal "/dev/null", Paperclip.bit_bucket
85
+ end
86
+ end
87
+ end
88
+
89
+ context "An ActiveRecord model with an 'avatar' attachment" do
90
+ setup do
91
+ rebuild_model :path => "tmp/:class/omg/:style.:extension"
92
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
93
+ end
94
+
95
+ teardown { @file.close }
96
+
97
+ should "not error when trying to also create a 'blah' attachment" do
98
+ assert_nothing_raised do
99
+ Dummy.class_eval do
100
+ has_attached_file :blah
101
+ end
102
+ end
103
+ end
104
+
105
+ context "that is attr_protected" do
106
+ setup do
107
+ Dummy.class_eval do
108
+ attr_protected :avatar
109
+ end
110
+ @dummy = Dummy.new
111
+ end
112
+
113
+ should "not assign the avatar on mass-set" do
114
+ @dummy.attributes = { :other => "I'm set!",
115
+ :avatar => @file }
116
+
117
+ assert_equal "I'm set!", @dummy.other
118
+ assert ! @dummy.avatar?
119
+ end
120
+
121
+ should "still allow assigment on normal set" do
122
+ @dummy.other = "I'm set!"
123
+ @dummy.avatar = @file
124
+
125
+ assert_equal "I'm set!", @dummy.other
126
+ assert @dummy.avatar?
127
+ end
128
+ end
129
+
130
+ context "with a subclass" do
131
+ setup do
132
+ class ::SubDummy < Dummy; end
133
+ end
134
+
135
+ should "be able to use the attachment from the subclass" do
136
+ assert_nothing_raised do
137
+ @subdummy = SubDummy.create(:avatar => @file)
138
+ end
139
+ end
140
+
141
+ should "be able to see the attachment definition from the subclass's class" do
142
+ assert_equal "tmp/:class/omg/:style.:extension", SubDummy.attachment_definitions[:avatar][:path]
143
+ end
144
+
145
+ teardown do
146
+ Object.send(:remove_const, "SubDummy") rescue nil
147
+ end
148
+ end
149
+
150
+ should "have an #avatar method" do
151
+ assert Dummy.new.respond_to?(:avatar)
152
+ end
153
+
154
+ should "have an #avatar= method" do
155
+ assert Dummy.new.respond_to?(:avatar=)
156
+ end
157
+
158
+ context "that is valid" do
159
+ setup do
160
+ @dummy = Dummy.new
161
+ @dummy.avatar = @file
162
+ end
163
+
164
+ should "be valid" do
165
+ assert @dummy.valid?
166
+ end
167
+
168
+ context "then has a validation added that makes it invalid" do
169
+ setup do
170
+ assert @dummy.save
171
+ Dummy.class_eval do
172
+ validates_attachment_content_type :avatar, :content_type => ["text/plain"]
173
+ end
174
+ @dummy2 = Dummy.find(@dummy.id)
175
+ end
176
+
177
+ should "be invalid when reloaded" do
178
+ assert ! @dummy2.valid?, @dummy2.errors.inspect
179
+ end
180
+
181
+ should "be able to call #valid? twice without having duplicate errors" do
182
+ @dummy2.avatar.valid?
183
+ first_errors = @dummy2.avatar.errors
184
+ @dummy2.avatar.valid?
185
+ assert_equal first_errors, @dummy2.avatar.errors
186
+ end
187
+ end
188
+ end
189
+
190
+ context "a validation with an if guard clause" do
191
+ setup do
192
+ Dummy.send(:"validates_attachment_presence", :avatar, :if => lambda{|i| i.foo })
193
+ @dummy = Dummy.new
194
+ end
195
+
196
+ should "attempt validation if the guard returns true" do
197
+ @dummy.expects(:foo).returns(true)
198
+ @dummy.avatar.expects(:validate_presence).returns(nil)
199
+ @dummy.valid?
200
+ end
201
+
202
+ should "not attempt validation if the guard returns false" do
203
+ @dummy.expects(:foo).returns(false)
204
+ @dummy.avatar.expects(:validate_presence).never
205
+ @dummy.valid?
206
+ end
207
+ end
208
+
209
+ context "a validation with an unless guard clause" do
210
+ setup do
211
+ Dummy.send(:"validates_attachment_presence", :avatar, :unless => lambda{|i| i.foo })
212
+ @dummy = Dummy.new
213
+ end
214
+
215
+ should "attempt validation if the guard returns true" do
216
+ @dummy.expects(:foo).returns(false)
217
+ @dummy.avatar.expects(:validate_presence).returns(nil)
218
+ @dummy.valid?
219
+ end
220
+
221
+ should "not attempt validation if the guard returns false" do
222
+ @dummy.expects(:foo).returns(true)
223
+ @dummy.avatar.expects(:validate_presence).never
224
+ @dummy.valid?
225
+ end
226
+ end
227
+
228
+ def self.should_validate validation, options, valid_file, invalid_file
229
+ context "with #{validation} validation and #{options.inspect} options" do
230
+ setup do
231
+ Dummy.send(:"validates_attachment_#{validation}", :avatar, options)
232
+ @dummy = Dummy.new
233
+ end
234
+ context "and assigning nil" do
235
+ setup do
236
+ @dummy.avatar = nil
237
+ @dummy.valid?
238
+ end
239
+ if validation == :presence
240
+ should "have an error on the attachment" do
241
+ assert @dummy.errors.on(:avatar)
242
+ end
243
+ else
244
+ should "not have an error on the attachment" do
245
+ assert_nil @dummy.errors.on(:avatar)
246
+ end
247
+ end
248
+ end
249
+ context "and assigned a valid file" do
250
+ setup do
251
+ @dummy.avatar = valid_file
252
+ @dummy.valid?
253
+ end
254
+ should "not have an error when assigned a valid file" do
255
+ assert ! @dummy.avatar.errors.key?(validation)
256
+ end
257
+ should "not have an error on the attachment" do
258
+ assert_nil @dummy.errors.on(:avatar)
259
+ end
260
+ end
261
+ context "and assigned an invalid file" do
262
+ setup do
263
+ @dummy.avatar = invalid_file
264
+ @dummy.valid?
265
+ end
266
+ should "have an error when assigned a valid file" do
267
+ assert_not_nil @dummy.avatar.errors[validation]
268
+ end
269
+ should "have an error on the attachment" do
270
+ assert @dummy.errors.on(:avatar)
271
+ end
272
+ end
273
+ end
274
+ end
275
+
276
+ [[:presence, {}, "5k.png", nil],
277
+ [:size, {:in => 1..10240}, nil, "12k.png"],
278
+ [:size, {:less_than => 10240}, "5k.png", "12k.png"],
279
+ [:size, {:greater_than => 8096}, "12k.png", "5k.png"],
280
+ [:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"],
281
+ [:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"],
282
+ [:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args|
283
+ validation, options, valid_file, invalid_file = args
284
+ valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb")
285
+ invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb")
286
+
287
+ should_validate validation, options, valid_file, invalid_file
288
+ end
289
+
290
+ end
291
+ end
@@ -0,0 +1,10 @@
1
+ require 'test/helper'
2
+
3
+ class ProcessorTest < Test::Unit::TestCase
4
+ should "instantiate and call #make when sent #make to the class" do
5
+ processor = mock
6
+ processor.expects(:make).with()
7
+ Paperclip::Processor.expects(:new).with(:one, :two, :three).returns(processor)
8
+ Paperclip::Processor.make(:one, :two, :three)
9
+ end
10
+ end