mender_paperclip 2.4.3
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.
- data/LICENSE +26 -0
- data/README.md +402 -0
- data/Rakefile +86 -0
- data/generators/paperclip/USAGE +5 -0
- data/generators/paperclip/paperclip_generator.rb +27 -0
- data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
- data/init.rb +4 -0
- data/lib/generators/paperclip/USAGE +8 -0
- data/lib/generators/paperclip/paperclip_generator.rb +33 -0
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
- data/lib/paperclip/attachment.rb +454 -0
- data/lib/paperclip/callback_compatibility.rb +61 -0
- data/lib/paperclip/geometry.rb +120 -0
- data/lib/paperclip/interpolations.rb +181 -0
- data/lib/paperclip/iostream.rb +45 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
- data/lib/paperclip/matchers.rb +33 -0
- data/lib/paperclip/missing_attachment_styles.rb +87 -0
- data/lib/paperclip/options.rb +79 -0
- data/lib/paperclip/processor.rb +58 -0
- data/lib/paperclip/railtie.rb +26 -0
- data/lib/paperclip/storage/filesystem.rb +81 -0
- data/lib/paperclip/storage/fog.rb +162 -0
- data/lib/paperclip/storage/s3.rb +262 -0
- data/lib/paperclip/storage.rb +3 -0
- data/lib/paperclip/style.rb +95 -0
- data/lib/paperclip/thumbnail.rb +105 -0
- data/lib/paperclip/upfile.rb +62 -0
- data/lib/paperclip/version.rb +3 -0
- data/lib/paperclip.rb +478 -0
- data/lib/tasks/paperclip.rake +97 -0
- data/rails/init.rb +2 -0
- data/shoulda_macros/paperclip.rb +124 -0
- data/test/attachment_test.rb +1120 -0
- data/test/database.yml +4 -0
- data/test/fixtures/12k.png +0 -0
- data/test/fixtures/50x50.png +0 -0
- data/test/fixtures/5k.png +0 -0
- data/test/fixtures/animated.gif +0 -0
- data/test/fixtures/bad.png +1 -0
- data/test/fixtures/fog.yml +8 -0
- data/test/fixtures/s3.yml +8 -0
- data/test/fixtures/spaced file.png +0 -0
- data/test/fixtures/text.txt +1 -0
- data/test/fixtures/twopage.pdf +0 -0
- data/test/fixtures/uppercase.PNG +0 -0
- data/test/fog_test.rb +191 -0
- data/test/geometry_test.rb +206 -0
- data/test/helper.rb +152 -0
- data/test/integration_test.rb +654 -0
- data/test/interpolations_test.rb +195 -0
- data/test/iostream_test.rb +71 -0
- data/test/matchers/have_attached_file_matcher_test.rb +24 -0
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +87 -0
- data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
- data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
- data/test/options_test.rb +68 -0
- data/test/paperclip_missing_attachment_styles_test.rb +80 -0
- data/test/paperclip_test.rb +329 -0
- data/test/processor_test.rb +10 -0
- data/test/storage/filesystem_test.rb +52 -0
- data/test/storage/s3_live_test.rb +51 -0
- data/test/storage/s3_test.rb +633 -0
- data/test/style_test.rb +180 -0
- data/test/thumbnail_test.rb +383 -0
- data/test/upfile_test.rb +53 -0
- metadata +243 -0
@@ -0,0 +1,329 @@
|
|
1
|
+
require './test/helper'
|
2
|
+
|
3
|
+
class PaperclipTest < Test::Unit::TestCase
|
4
|
+
context "Calling Paperclip.run" do
|
5
|
+
setup do
|
6
|
+
Cocaine::CommandLine.expects(:new).with("convert", "stuff").returns(stub(:run))
|
7
|
+
@original_command_line_path = Cocaine::CommandLine.path
|
8
|
+
end
|
9
|
+
|
10
|
+
teardown do
|
11
|
+
Cocaine::CommandLine.path = @original_command_line_path
|
12
|
+
end
|
13
|
+
|
14
|
+
should "run the command with Cocaine" do
|
15
|
+
Paperclip.run("convert", "stuff")
|
16
|
+
end
|
17
|
+
|
18
|
+
should "save Cocaine::CommandLine.path that set before" do
|
19
|
+
Cocaine::CommandLine.path = "/opt/my_app/bin"
|
20
|
+
Paperclip.run("convert", "stuff")
|
21
|
+
assert_equal [Cocaine::CommandLine.path].flatten.include?("/opt/my_app/bin"), true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "Paperclip.each_instance_with_attachment" do
|
26
|
+
setup do
|
27
|
+
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
|
28
|
+
d1 = Dummy.create(:avatar => @file)
|
29
|
+
d2 = Dummy.create
|
30
|
+
d3 = Dummy.create(:avatar => @file)
|
31
|
+
@expected = [d1, d3]
|
32
|
+
end
|
33
|
+
should "yield every instance of a model that has an attachment" do
|
34
|
+
actual = []
|
35
|
+
Paperclip.each_instance_with_attachment("Dummy", "avatar") do |instance|
|
36
|
+
actual << instance
|
37
|
+
end
|
38
|
+
assert_same_elements @expected, actual
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
should "raise when sent #processor and the name of a class that doesn't exist" do
|
43
|
+
assert_raises(NameError){ Paperclip.processor(:boogey_man) }
|
44
|
+
end
|
45
|
+
|
46
|
+
should "return a class when sent #processor and the name of a class under Paperclip" do
|
47
|
+
assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail)
|
48
|
+
end
|
49
|
+
|
50
|
+
should "get a class from a namespaced class name" do
|
51
|
+
class ::One; class Two; end; end
|
52
|
+
assert_equal ::One::Two, Paperclip.class_for("One::Two")
|
53
|
+
end
|
54
|
+
|
55
|
+
should "raise when class doesn't exist in specified namespace" do
|
56
|
+
class ::Three; end
|
57
|
+
class ::Four; end
|
58
|
+
assert_raise NameError do
|
59
|
+
Paperclip.class_for("Three::Four")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "Attachments with clashing URLs should raise error" do
|
64
|
+
setup do
|
65
|
+
class Dummy2 < ActiveRecord::Base
|
66
|
+
include Paperclip::Glue
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
should "generate warning if attachment is redefined with the same url string" do
|
71
|
+
Paperclip.expects(:log).with("Duplicate URL for blah with /system/:attachment/:id/:style/:filename. This will clash with attachment defined in Dummy class")
|
72
|
+
Dummy.class_eval do
|
73
|
+
has_attached_file :blah
|
74
|
+
end
|
75
|
+
Dummy2.class_eval do
|
76
|
+
has_attached_file :blah
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "An ActiveRecord model with an 'avatar' attachment" do
|
82
|
+
setup do
|
83
|
+
rebuild_model :path => "tmp/:class/omg/:style.:extension"
|
84
|
+
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
|
85
|
+
end
|
86
|
+
|
87
|
+
teardown { @file.close }
|
88
|
+
|
89
|
+
should "not error when trying to also create a 'blah' attachment" do
|
90
|
+
assert_nothing_raised do
|
91
|
+
Dummy.class_eval do
|
92
|
+
has_attached_file :blah
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "that is attr_protected" do
|
98
|
+
setup do
|
99
|
+
Dummy.class_eval do
|
100
|
+
attr_protected :avatar
|
101
|
+
end
|
102
|
+
@dummy = Dummy.new
|
103
|
+
end
|
104
|
+
|
105
|
+
should "not assign the avatar on mass-set" do
|
106
|
+
@dummy.attributes = { :other => "I'm set!",
|
107
|
+
:avatar => @file }
|
108
|
+
|
109
|
+
assert_equal "I'm set!", @dummy.other
|
110
|
+
assert ! @dummy.avatar?
|
111
|
+
end
|
112
|
+
|
113
|
+
should "still allow assigment on normal set" do
|
114
|
+
@dummy.other = "I'm set!"
|
115
|
+
@dummy.avatar = @file
|
116
|
+
|
117
|
+
assert_equal "I'm set!", @dummy.other
|
118
|
+
assert @dummy.avatar?
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context "with a subclass" do
|
123
|
+
setup do
|
124
|
+
class ::SubDummy < Dummy; end
|
125
|
+
end
|
126
|
+
|
127
|
+
should "be able to use the attachment from the subclass" do
|
128
|
+
assert_nothing_raised do
|
129
|
+
@subdummy = SubDummy.create(:avatar => @file)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
should "be able to see the attachment definition from the subclass's class" do
|
134
|
+
assert_equal "tmp/:class/omg/:style.:extension",
|
135
|
+
SubDummy.attachment_definitions[:avatar][:path]
|
136
|
+
end
|
137
|
+
|
138
|
+
teardown do
|
139
|
+
Object.send(:remove_const, "SubDummy") rescue nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
should "have an #avatar method" do
|
144
|
+
assert Dummy.new.respond_to?(:avatar)
|
145
|
+
end
|
146
|
+
|
147
|
+
should "have an #avatar= method" do
|
148
|
+
assert Dummy.new.respond_to?(:avatar=)
|
149
|
+
end
|
150
|
+
|
151
|
+
context "that is valid" do
|
152
|
+
setup do
|
153
|
+
@dummy = Dummy.new
|
154
|
+
@dummy.avatar = @file
|
155
|
+
end
|
156
|
+
|
157
|
+
should "be valid" do
|
158
|
+
assert @dummy.valid?
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "a validation with an if guard clause" do
|
163
|
+
setup do
|
164
|
+
Dummy.send(:"validates_attachment_presence", :avatar, :if => lambda{|i| i.foo })
|
165
|
+
@dummy = Dummy.new
|
166
|
+
@dummy.stubs(:avatar_file_name).returns(nil)
|
167
|
+
end
|
168
|
+
|
169
|
+
should "attempt validation if the guard returns true" do
|
170
|
+
@dummy.expects(:foo).returns(true)
|
171
|
+
assert ! @dummy.valid?
|
172
|
+
end
|
173
|
+
|
174
|
+
should "not attempt validation if the guard returns false" do
|
175
|
+
@dummy.expects(:foo).returns(false)
|
176
|
+
assert @dummy.valid?
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "a validation with an unless guard clause" do
|
181
|
+
setup do
|
182
|
+
Dummy.send(:"validates_attachment_presence", :avatar, :unless => lambda{|i| i.foo })
|
183
|
+
@dummy = Dummy.new
|
184
|
+
@dummy.stubs(:avatar_file_name).returns(nil)
|
185
|
+
end
|
186
|
+
|
187
|
+
should "attempt validation if the guard returns true" do
|
188
|
+
@dummy.expects(:foo).returns(false)
|
189
|
+
assert ! @dummy.valid?
|
190
|
+
end
|
191
|
+
|
192
|
+
should "not attempt validation if the guard returns false" do
|
193
|
+
@dummy.expects(:foo).returns(true)
|
194
|
+
assert @dummy.valid?
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
should "not have Attachment in the ActiveRecord::Base namespace" do
|
199
|
+
assert_raises(NameError) do
|
200
|
+
ActiveRecord::Base::Attachment
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.should_validate validation, options, valid_file, invalid_file
|
205
|
+
context "with #{validation} validation and #{options.inspect} options" do
|
206
|
+
setup do
|
207
|
+
rebuild_class
|
208
|
+
Dummy.send(:"validates_attachment_#{validation}", :avatar, options)
|
209
|
+
@dummy = Dummy.new
|
210
|
+
end
|
211
|
+
context "and assigning nil" do
|
212
|
+
setup do
|
213
|
+
@dummy.avatar = nil
|
214
|
+
@dummy.valid?
|
215
|
+
end
|
216
|
+
if validation == :presence
|
217
|
+
should "have an error on the attachment" do
|
218
|
+
assert @dummy.errors[:avatar_file_name]
|
219
|
+
end
|
220
|
+
else
|
221
|
+
should "not have an error on the attachment" do
|
222
|
+
assert @dummy.errors.blank?, @dummy.errors.full_messages.join(", ")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
context "and assigned a valid file" do
|
227
|
+
setup do
|
228
|
+
@dummy.avatar = valid_file
|
229
|
+
@dummy.valid?
|
230
|
+
end
|
231
|
+
should "not have an error when assigned a valid file" do
|
232
|
+
assert_equal 0, @dummy.errors.size, @dummy.errors.full_messages.join(", ")
|
233
|
+
end
|
234
|
+
end
|
235
|
+
context "and assigned an invalid file" do
|
236
|
+
setup do
|
237
|
+
@dummy.avatar = invalid_file
|
238
|
+
@dummy.valid?
|
239
|
+
end
|
240
|
+
should "have an error when assigned a valid file" do
|
241
|
+
assert @dummy.errors.size > 0
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
[[:presence, {}, "5k.png", nil],
|
248
|
+
[:size, {:in => 1..10240}, "5k.png", "12k.png"],
|
249
|
+
[:size, {:less_than => 10240}, "5k.png", "12k.png"],
|
250
|
+
[:size, {:greater_than => 8096}, "12k.png", "5k.png"],
|
251
|
+
[:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"],
|
252
|
+
[:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"],
|
253
|
+
[:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args|
|
254
|
+
validation, options, valid_file, invalid_file = args
|
255
|
+
valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb")
|
256
|
+
invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb")
|
257
|
+
|
258
|
+
should_validate validation, options, valid_file, invalid_file
|
259
|
+
end
|
260
|
+
|
261
|
+
context "with content_type validation and lambda message" do
|
262
|
+
context "and assigned an invalid file" do
|
263
|
+
setup do
|
264
|
+
Dummy.send(:"validates_attachment_content_type", :avatar, :content_type => %r{image/.*}, :message => lambda {'lambda content type message'})
|
265
|
+
@dummy = Dummy.new
|
266
|
+
@dummy.avatar &&= File.open(File.join(FIXTURES_DIR, "text.txt"), "rb")
|
267
|
+
@dummy.valid?
|
268
|
+
end
|
269
|
+
|
270
|
+
should "have a content type error message" do
|
271
|
+
assert [@dummy.errors[:avatar_content_type]].flatten.any?{|error| error =~ %r/lambda content type message/ }
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
context "with size validation and less_than 10240 option" do
|
277
|
+
context "and assigned an invalid file" do
|
278
|
+
setup do
|
279
|
+
Dummy.send(:"validates_attachment_size", :avatar, :less_than => 10240)
|
280
|
+
@dummy = Dummy.new
|
281
|
+
@dummy.avatar &&= File.open(File.join(FIXTURES_DIR, "12k.png"), "rb")
|
282
|
+
@dummy.valid?
|
283
|
+
end
|
284
|
+
|
285
|
+
should "have a file size min/max error message" do
|
286
|
+
assert [@dummy.errors[:avatar_file_size]].flatten.any?{|error| error =~ %r/between 0 and 10240 bytes/ }
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
context "with size validation and less_than 10240 option with lambda message" do
|
292
|
+
context "and assigned an invalid file" do
|
293
|
+
setup do
|
294
|
+
Dummy.send(:"validates_attachment_size", :avatar, :less_than => 10240, :message => lambda {'lambda between 0 and 10240 bytes'})
|
295
|
+
@dummy = Dummy.new
|
296
|
+
@dummy.avatar &&= File.open(File.join(FIXTURES_DIR, "12k.png"), "rb")
|
297
|
+
@dummy.valid?
|
298
|
+
end
|
299
|
+
|
300
|
+
should "have a file size min/max error message" do
|
301
|
+
assert [@dummy.errors[:avatar_file_size]].flatten.any?{|error| error =~ %r/lambda between 0 and 10240 bytes/ }
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|
307
|
+
|
308
|
+
context "configuring a custom processor" do
|
309
|
+
setup do
|
310
|
+
@freedom_processor = Class.new do
|
311
|
+
def make(file, options = {}, attachment = nil)
|
312
|
+
file
|
313
|
+
end
|
314
|
+
end.new
|
315
|
+
|
316
|
+
Paperclip.configure do |config|
|
317
|
+
config.register_processor(:freedom, @freedom_processor)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
should "be able to find the custom processor" do
|
322
|
+
assert_equal @freedom_processor, Paperclip.processor(:freedom)
|
323
|
+
end
|
324
|
+
|
325
|
+
teardown do
|
326
|
+
Paperclip.clear_processors!
|
327
|
+
end
|
328
|
+
end
|
329
|
+
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
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require './test/helper'
|
2
|
+
|
3
|
+
class FileSystemTest < Test::Unit::TestCase
|
4
|
+
context "Filesystem" do
|
5
|
+
setup do
|
6
|
+
rebuild_model :styles => { :thumbnail => "25x25#" }
|
7
|
+
@dummy = Dummy.create!
|
8
|
+
|
9
|
+
@dummy.avatar = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "5k.png"))
|
10
|
+
end
|
11
|
+
|
12
|
+
should "allow file assignment" do
|
13
|
+
assert @dummy.save
|
14
|
+
end
|
15
|
+
|
16
|
+
should "store the original" do
|
17
|
+
@dummy.save
|
18
|
+
assert File.exists?(@dummy.avatar.path)
|
19
|
+
end
|
20
|
+
|
21
|
+
should "store the thumbnail" do
|
22
|
+
@dummy.save
|
23
|
+
assert File.exists?(@dummy.avatar.path(:thumbnail))
|
24
|
+
end
|
25
|
+
|
26
|
+
should "clean up file objects" do
|
27
|
+
File.stubs(:exist?).returns(true)
|
28
|
+
Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
|
29
|
+
Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
|
30
|
+
|
31
|
+
@dummy.save!
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with file that has space in file name" do
|
35
|
+
setup do
|
36
|
+
rebuild_model :styles => { :thumbnail => "25x25#" }
|
37
|
+
@dummy = Dummy.create!
|
38
|
+
|
39
|
+
@dummy.avatar = File.open(File.join(File.dirname(__FILE__), "..", "fixtures", "spaced file.png"))
|
40
|
+
@dummy.save
|
41
|
+
end
|
42
|
+
|
43
|
+
should "store the file" do
|
44
|
+
assert File.exists?(@dummy.avatar.path)
|
45
|
+
end
|
46
|
+
|
47
|
+
should "return an escaped version of URL" do
|
48
|
+
assert_match /\/spaced%20file\.png/, @dummy.avatar.url
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require './test/helper'
|
2
|
+
require 'aws/s3'
|
3
|
+
|
4
|
+
unless ENV["S3_TEST_BUCKET"].blank?
|
5
|
+
class S3LiveTest < Test::Unit::TestCase
|
6
|
+
context "Using S3 for real, an attachment with S3 storage" do
|
7
|
+
setup do
|
8
|
+
rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" },
|
9
|
+
:storage => :s3,
|
10
|
+
:bucket => ENV["S3_TEST_BUCKET"],
|
11
|
+
:path => ":class/:attachment/:id/:style.:extension",
|
12
|
+
:s3_credentials => File.new(File.join(File.dirname(__FILE__), "..", "s3.yml"))
|
13
|
+
|
14
|
+
Dummy.delete_all
|
15
|
+
@dummy = Dummy.new
|
16
|
+
end
|
17
|
+
|
18
|
+
should "be extended by the S3 module" do
|
19
|
+
assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3)
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when assigned" do
|
23
|
+
setup do
|
24
|
+
@file = File.new(File.join(File.dirname(__FILE__), '..', 'fixtures', '5k.png'), 'rb')
|
25
|
+
@dummy.avatar = @file
|
26
|
+
end
|
27
|
+
|
28
|
+
teardown { @file.close }
|
29
|
+
|
30
|
+
should "still return a Tempfile when sent #to_file" do
|
31
|
+
assert_equal Paperclip::Tempfile, @dummy.avatar.to_file.class
|
32
|
+
end
|
33
|
+
|
34
|
+
context "and saved" do
|
35
|
+
setup do
|
36
|
+
@dummy.save
|
37
|
+
end
|
38
|
+
|
39
|
+
should "be on S3" do
|
40
|
+
assert true
|
41
|
+
end
|
42
|
+
|
43
|
+
should "generate a tempfile with the right name" do
|
44
|
+
file = @dummy.avatar.to_file
|
45
|
+
assert_match /^original.*\.png$/, File.basename(file.path)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|