thoughtbot-paperclip 2.3.0 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/paperclip.rb +5 -3
- data/lib/paperclip/interpolations.rb +4 -1
- data/lib/paperclip/storage.rb +32 -25
- data/lib/paperclip/thumbnail.rb +16 -13
- data/test/attachment_test.rb +13 -1
- data/test/helper.rb +10 -1
- data/test/integration_test.rb +13 -11
- data/test/interpolations_test.rb +5 -1
- data/test/paperclip_test.rb +68 -32
- data/test/storage_test.rb +33 -35
- data/test/thumbnail_test.rb +50 -0
- metadata +4 -3
data/lib/paperclip.rb
CHANGED
@@ -44,7 +44,7 @@ end
|
|
44
44
|
# documentation for Paperclip::ClassMethods for more useful information.
|
45
45
|
module Paperclip
|
46
46
|
|
47
|
-
VERSION = "2.3.
|
47
|
+
VERSION = "2.3.1"
|
48
48
|
|
49
49
|
class << self
|
50
50
|
# Provides configurability to Paperclip. There are a number of options available, such as:
|
@@ -93,7 +93,7 @@ module Paperclip
|
|
93
93
|
# Paperclip.options[:log_command] is set to true (defaults to false). This
|
94
94
|
# will only log if logging in general is set to true as well.
|
95
95
|
def run cmd, params = "", expected_outcodes = 0
|
96
|
-
command = %Q
|
96
|
+
command = %Q[#{path_for_command(cmd)} #{params}].gsub(/\s+/, " ")
|
97
97
|
command = "#{command} 2>#{bit_bucket}" if Paperclip.options[:swallow_stderr]
|
98
98
|
Paperclip.log(command) if Paperclip.options[:log_command]
|
99
99
|
output = `#{command}`
|
@@ -257,7 +257,9 @@ module Paperclip
|
|
257
257
|
range = (min..max)
|
258
258
|
message = options[:message] || "file size must be between :min and :max bytes."
|
259
259
|
|
260
|
-
attachment_definitions[name][:validations] << [:size, {:
|
260
|
+
attachment_definitions[name][:validations] << [:size, {:min => min,
|
261
|
+
:max => max,
|
262
|
+
:range => range,
|
261
263
|
:message => message,
|
262
264
|
:if => options[:if],
|
263
265
|
:unless => options[:unless]}]
|
@@ -63,7 +63,10 @@ module Paperclip
|
|
63
63
|
|
64
64
|
# Returns the underscored, pluralized version of the class name.
|
65
65
|
# e.g. "users" for the User class.
|
66
|
-
|
66
|
+
# NOTE: The arguments need to be optional, because some tools fetch
|
67
|
+
# all class names. Calling #class will return the expected class.
|
68
|
+
def class attachment = nil, style = nil
|
69
|
+
return super() if attachment.nil? && style.nil?
|
67
70
|
attachment.instance.class.to_s.underscore.pluralize
|
68
71
|
end
|
69
72
|
|
data/lib/paperclip/storage.rb
CHANGED
@@ -33,7 +33,6 @@ module Paperclip
|
|
33
33
|
def to_file style = default_style
|
34
34
|
@queued_for_write[style] || (File.new(path(style), 'rb') if exists?(style))
|
35
35
|
end
|
36
|
-
alias_method :to_io, :to_file
|
37
36
|
|
38
37
|
def flush_writes #:nodoc:
|
39
38
|
@queued_for_write.each do |style, file|
|
@@ -128,17 +127,27 @@ module Paperclip
|
|
128
127
|
# separate parts of your file name.
|
129
128
|
module S3
|
130
129
|
def self.extended base
|
131
|
-
|
130
|
+
begin
|
131
|
+
require 'aws/s3'
|
132
|
+
rescue LoadError => e
|
133
|
+
e.message << " (You may need to install the aws-s3 gem)"
|
134
|
+
raise e
|
135
|
+
end
|
136
|
+
|
132
137
|
base.instance_eval do
|
133
138
|
@s3_credentials = parse_credentials(@options[:s3_credentials])
|
134
139
|
@bucket = @options[:bucket] || @s3_credentials[:bucket]
|
135
140
|
@bucket = @bucket.call(self) if @bucket.is_a?(Proc)
|
136
141
|
@s3_options = @options[:s3_options] || {}
|
137
|
-
@s3_permissions = @options[:s3_permissions] ||
|
138
|
-
@s3_protocol = @options[:s3_protocol] || (@s3_permissions ==
|
142
|
+
@s3_permissions = @options[:s3_permissions] || :public_read
|
143
|
+
@s3_protocol = @options[:s3_protocol] || (@s3_permissions == :public_read ? 'http' : 'https')
|
139
144
|
@s3_headers = @options[:s3_headers] || {}
|
140
145
|
@s3_host_alias = @options[:s3_host_alias]
|
141
146
|
@url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/)
|
147
|
+
AWS::S3::Base.establish_connection!( @s3_options.merge(
|
148
|
+
:access_key_id => @s3_credentials[:access_key_id],
|
149
|
+
:secret_access_key => @s3_credentials[:secret_access_key]
|
150
|
+
))
|
142
151
|
end
|
143
152
|
Paperclip.interpolates(:s3_alias_url) do |attachment, style|
|
144
153
|
"#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}"
|
@@ -151,16 +160,6 @@ module Paperclip
|
|
151
160
|
end
|
152
161
|
end
|
153
162
|
|
154
|
-
def s3
|
155
|
-
@s3 ||= RightAws::S3.new(@s3_credentials[:access_key_id],
|
156
|
-
@s3_credentials[:secret_access_key],
|
157
|
-
@s3_options)
|
158
|
-
end
|
159
|
-
|
160
|
-
def s3_bucket
|
161
|
-
@s3_bucket ||= s3.bucket(@bucket, true, @s3_permissions)
|
162
|
-
end
|
163
|
-
|
164
163
|
def bucket_name
|
165
164
|
@bucket
|
166
165
|
end
|
@@ -175,7 +174,11 @@ module Paperclip
|
|
175
174
|
end
|
176
175
|
|
177
176
|
def exists?(style = default_style)
|
178
|
-
|
177
|
+
if original_filename
|
178
|
+
AWS::S3::S3Object.exists?(path(style), bucket_name)
|
179
|
+
else
|
180
|
+
false
|
181
|
+
end
|
179
182
|
end
|
180
183
|
|
181
184
|
def s3_protocol
|
@@ -185,18 +188,24 @@ module Paperclip
|
|
185
188
|
# Returns representation of the data of the file assigned to the given
|
186
189
|
# style, in the format most representative of the current storage.
|
187
190
|
def to_file style = default_style
|
188
|
-
@queued_for_write[style]
|
191
|
+
return @queued_for_write[style] if @queued_for_write[style]
|
192
|
+
file = Tempfile.new(path(style))
|
193
|
+
file.write(AWS::S3::S3Object.value(path(style), bucket_name))
|
194
|
+
file.rewind
|
195
|
+
return file
|
189
196
|
end
|
190
|
-
alias_method :to_io, :to_file
|
191
197
|
|
192
198
|
def flush_writes #:nodoc:
|
193
199
|
@queued_for_write.each do |style, file|
|
194
200
|
begin
|
195
201
|
log("saving #{path(style)}")
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
202
|
+
AWS::S3::S3Object.store(path(style),
|
203
|
+
file,
|
204
|
+
bucket_name,
|
205
|
+
{:content_type => instance_read(:content_type),
|
206
|
+
:access => @s3_permissions,
|
207
|
+
}.merge(@s3_headers))
|
208
|
+
rescue AWS::S3::ResponseError => e
|
200
209
|
raise
|
201
210
|
end
|
202
211
|
end
|
@@ -207,10 +216,8 @@ module Paperclip
|
|
207
216
|
@queued_for_delete.each do |path|
|
208
217
|
begin
|
209
218
|
log("deleting #{path}")
|
210
|
-
|
211
|
-
|
212
|
-
end
|
213
|
-
rescue RightAws::AwsError
|
219
|
+
AWS::S3::S3Object.delete(path, bucket_name)
|
220
|
+
rescue AWS::S3::ResponseError
|
214
221
|
# Ignore this.
|
215
222
|
end
|
216
223
|
end
|
data/lib/paperclip/thumbnail.rb
CHANGED
@@ -2,7 +2,7 @@ module Paperclip
|
|
2
2
|
# Handles thumbnailing images that are uploaded.
|
3
3
|
class Thumbnail < Processor
|
4
4
|
|
5
|
-
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options
|
5
|
+
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options, :source_file_options
|
6
6
|
|
7
7
|
# Creates a Thumbnail object set to work on the +file+ given. It
|
8
8
|
# will attempt to transform the image into one defined by +target_geometry+
|
@@ -12,17 +12,18 @@ module Paperclip
|
|
12
12
|
# set, the options will be appended to the convert command upon image conversion
|
13
13
|
def initialize file, options = {}, attachment = nil
|
14
14
|
super
|
15
|
-
geometry
|
16
|
-
@file
|
17
|
-
@crop
|
18
|
-
@target_geometry
|
19
|
-
@current_geometry
|
20
|
-
@
|
21
|
-
@
|
22
|
-
@
|
15
|
+
geometry = options[:geometry]
|
16
|
+
@file = file
|
17
|
+
@crop = geometry[-1,1] == '#'
|
18
|
+
@target_geometry = Geometry.parse geometry
|
19
|
+
@current_geometry = Geometry.from_file @file
|
20
|
+
@source_file_options = options[:source_file_options]
|
21
|
+
@convert_options = options[:convert_options]
|
22
|
+
@whiny = options[:whiny].nil? ? true : options[:whiny]
|
23
|
+
@format = options[:format]
|
23
24
|
|
24
|
-
@current_format
|
25
|
-
@basename
|
25
|
+
@current_format = File.extname(@file.path)
|
26
|
+
@basename = File.basename(@file.path, @current_format)
|
26
27
|
end
|
27
28
|
|
28
29
|
# Returns true if the +target_geometry+ is meant to crop.
|
@@ -32,7 +33,7 @@ module Paperclip
|
|
32
33
|
|
33
34
|
# Returns true if the image is meant to make use of additional convert options.
|
34
35
|
def convert_options?
|
35
|
-
|
36
|
+
!@convert_options.nil? && !@convert_options.empty?
|
36
37
|
end
|
37
38
|
|
38
39
|
# Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile
|
@@ -43,6 +44,7 @@ module Paperclip
|
|
43
44
|
dst.binmode
|
44
45
|
|
45
46
|
command = <<-end_command
|
47
|
+
#{ source_file_options }
|
46
48
|
"#{ File.expand_path(src.path) }[0]"
|
47
49
|
#{ transformation_command }
|
48
50
|
"#{ File.expand_path(dst.path) }"
|
@@ -61,7 +63,8 @@ module Paperclip
|
|
61
63
|
# into the thumbnail.
|
62
64
|
def transformation_command
|
63
65
|
scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
|
64
|
-
trans = "
|
66
|
+
trans = ""
|
67
|
+
trans << " -resize \"#{scale}\"" unless scale.nil? || scale.empty?
|
65
68
|
trans << " -crop \"#{crop}\" +repage" if crop
|
66
69
|
trans << " #{convert_options}" if convert_options?
|
67
70
|
trans
|
data/test/attachment_test.rb
CHANGED
@@ -14,6 +14,18 @@ class AttachmentTest < Test::Unit::TestCase
|
|
14
14
|
assert_equal "#{RAILS_ROOT}/public/fake_models/1234/fake", @attachment.path
|
15
15
|
end
|
16
16
|
|
17
|
+
should "call a proc sent to check_guard" do
|
18
|
+
@dummy = Dummy.new
|
19
|
+
@dummy.expects(:one).returns(:one)
|
20
|
+
assert_equal :one, @dummy.avatar.send(:check_guard, lambda{|x| x.one })
|
21
|
+
end
|
22
|
+
|
23
|
+
should "call a method name sent to check_guard" do
|
24
|
+
@dummy = Dummy.new
|
25
|
+
@dummy.expects(:one).returns(:one)
|
26
|
+
assert_equal :one, @dummy.avatar.send(:check_guard, :one)
|
27
|
+
end
|
28
|
+
|
17
29
|
context "Attachment default_options" do
|
18
30
|
setup do
|
19
31
|
rebuild_model
|
@@ -592,7 +604,7 @@ class AttachmentTest < Test::Unit::TestCase
|
|
592
604
|
|
593
605
|
should "commit the files to disk" do
|
594
606
|
[:large, :medium, :small].each do |style|
|
595
|
-
io = @attachment.
|
607
|
+
io = @attachment.to_file(style)
|
596
608
|
assert File.exists?(io)
|
597
609
|
assert ! io.is_a?(::Tempfile)
|
598
610
|
io.close
|
data/test/helper.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'test/unit'
|
3
3
|
require 'shoulda'
|
4
|
-
require 'mocha'
|
5
4
|
require 'tempfile'
|
6
5
|
|
6
|
+
gem 'jferris-mocha', '0.9.5.0.1241126838'
|
7
|
+
require 'mocha'
|
8
|
+
|
7
9
|
gem 'sqlite3-ruby'
|
8
10
|
|
9
11
|
require 'active_record'
|
@@ -97,3 +99,10 @@ end
|
|
97
99
|
def attachment options
|
98
100
|
Paperclip::Attachment.new(:avatar, FakeModel.new, options)
|
99
101
|
end
|
102
|
+
|
103
|
+
def silence_warnings
|
104
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
105
|
+
yield
|
106
|
+
ensure
|
107
|
+
$VERBOSE = old_verbose
|
108
|
+
end
|
data/test/integration_test.rb
CHANGED
@@ -379,6 +379,11 @@ class IntegrationTest < Test::Unit::TestCase
|
|
379
379
|
@files_on_s3 = s3_files_for @dummy.avatar
|
380
380
|
end
|
381
381
|
|
382
|
+
should "have the same contents as the original" do
|
383
|
+
@file.rewind
|
384
|
+
assert_equal @file.read, @files_on_s3[:original].read
|
385
|
+
end
|
386
|
+
|
382
387
|
should "write and delete its files" do
|
383
388
|
[["434x66", :original],
|
384
389
|
["300x46", :large],
|
@@ -403,10 +408,8 @@ class IntegrationTest < Test::Unit::TestCase
|
|
403
408
|
assert @dummy.valid?
|
404
409
|
assert @dummy.save
|
405
410
|
|
406
|
-
|
407
|
-
|
408
|
-
saved_keys.each do |key|
|
409
|
-
assert key.exists?
|
411
|
+
[:thumb, :medium, :large, :original].each do |style|
|
412
|
+
assert @dummy.avatar.exists?(style)
|
410
413
|
end
|
411
414
|
|
412
415
|
@dummy.avatar.clear
|
@@ -414,8 +417,8 @@ class IntegrationTest < Test::Unit::TestCase
|
|
414
417
|
assert @dummy.valid?
|
415
418
|
assert @dummy.save
|
416
419
|
|
417
|
-
|
418
|
-
assert !
|
420
|
+
[:thumb, :medium, :large, :original].each do |style|
|
421
|
+
assert ! @dummy.avatar.exists?(style)
|
419
422
|
end
|
420
423
|
|
421
424
|
@d2 = Dummy.find(@dummy.id)
|
@@ -427,7 +430,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
427
430
|
|
428
431
|
assert_equal @dummy.avatar_file_name, @d2.avatar_file_name
|
429
432
|
[:thumb, :medium, :large, :original].each do |style|
|
430
|
-
assert_equal @dummy.avatar.to_file(style).
|
433
|
+
assert_equal @dummy.avatar.to_file(style).read, @d2.avatar.to_file(style).read
|
431
434
|
end
|
432
435
|
|
433
436
|
saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) }
|
@@ -435,8 +438,8 @@ class IntegrationTest < Test::Unit::TestCase
|
|
435
438
|
@d2.avatar.clear
|
436
439
|
assert @d2.save
|
437
440
|
|
438
|
-
|
439
|
-
assert !
|
441
|
+
[:thumb, :medium, :large, :original].each do |style|
|
442
|
+
assert ! @dummy.avatar.exists?(style)
|
440
443
|
end
|
441
444
|
end
|
442
445
|
|
@@ -444,7 +447,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
444
447
|
expected = @dummy.avatar.to_file
|
445
448
|
@dummy.avatar = "not a file"
|
446
449
|
assert @dummy.valid?
|
447
|
-
assert_equal expected.
|
450
|
+
assert_equal expected.read, @dummy.avatar.to_file.read
|
448
451
|
|
449
452
|
@dummy.avatar = @bad_file
|
450
453
|
assert ! @dummy.valid?
|
@@ -472,7 +475,6 @@ class IntegrationTest < Test::Unit::TestCase
|
|
472
475
|
|
473
476
|
should "have the right content type" do
|
474
477
|
headers = s3_headers_for(@dummy.avatar, :original)
|
475
|
-
p headers
|
476
478
|
assert_equal 'image/png', headers['content-type']
|
477
479
|
end
|
478
480
|
end
|
data/test/interpolations_test.rb
CHANGED
@@ -7,7 +7,7 @@ class InterpolationsTest < Test::Unit::TestCase
|
|
7
7
|
assert ! methods.include?(:[]=)
|
8
8
|
assert ! methods.include?(:all)
|
9
9
|
methods.each do |m|
|
10
|
-
assert Paperclip::Interpolations.respond_to?
|
10
|
+
assert Paperclip::Interpolations.respond_to?(m)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -19,6 +19,10 @@ class InterpolationsTest < Test::Unit::TestCase
|
|
19
19
|
assert_equal RAILS_ENV, Paperclip::Interpolations.rails_env(:attachment, :style)
|
20
20
|
end
|
21
21
|
|
22
|
+
should "return the class of the Interpolations module when called with no params" do
|
23
|
+
assert_equal Module, Paperclip::Interpolations.class
|
24
|
+
end
|
25
|
+
|
22
26
|
should "return the class of the instance" do
|
23
27
|
attachment = mock
|
24
28
|
attachment.expects(:instance).returns(attachment)
|
data/test/paperclip_test.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
require 'test/helper'
|
2
2
|
|
3
3
|
class PaperclipTest < Test::Unit::TestCase
|
4
|
-
[:image_magick_path, :
|
5
|
-
context "Calling Paperclip.run with
|
4
|
+
[:image_magick_path, :command_path].each do |path|
|
5
|
+
context "Calling Paperclip.run with #{path} specified" do
|
6
6
|
setup do
|
7
7
|
Paperclip.options[:image_magick_path] = nil
|
8
|
-
Paperclip.options[:
|
8
|
+
Paperclip.options[:command_path] = nil
|
9
9
|
Paperclip.options[path] = "/usr/bin"
|
10
10
|
end
|
11
11
|
|
12
|
+
should "return the expected path for path_for_command" do
|
13
|
+
assert_equal "/usr/bin/convert", Paperclip.path_for_command("convert")
|
14
|
+
end
|
15
|
+
|
12
16
|
should "execute the right command" do
|
13
17
|
Paperclip.expects(:path_for_command).with("convert").returns("/usr/bin/convert")
|
14
18
|
Paperclip.expects(:bit_bucket).returns("/dev/null")
|
@@ -21,7 +25,11 @@ class PaperclipTest < Test::Unit::TestCase
|
|
21
25
|
context "Calling Paperclip.run with no path specified" do
|
22
26
|
setup do
|
23
27
|
Paperclip.options[:image_magick_path] = nil
|
24
|
-
Paperclip.options[:
|
28
|
+
Paperclip.options[:command_path] = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
should "return the expected path fro path_for_command" do
|
32
|
+
assert_equal "convert", Paperclip.path_for_command("convert")
|
25
33
|
end
|
26
34
|
|
27
35
|
should "execute the right command" do
|
@@ -30,38 +38,38 @@ class PaperclipTest < Test::Unit::TestCase
|
|
30
38
|
Paperclip.expects(:"`").with("convert one.jpg two.jpg 2>/dev/null")
|
31
39
|
Paperclip.run("convert", "one.jpg two.jpg")
|
32
40
|
end
|
41
|
+
end
|
33
42
|
|
34
|
-
|
43
|
+
context "Calling Paperclip.run and logging" do
|
44
|
+
setup do
|
45
|
+
Paperclip.options[:image_magick_path] = nil
|
46
|
+
Paperclip.options[:command_path] = nil
|
47
|
+
Paperclip.stubs(:bit_bucket).returns("/dev/null")
|
48
|
+
Paperclip.stubs(:log)
|
49
|
+
Paperclip.stubs(:"`").with("this is the command 2>/dev/null")
|
50
|
+
end
|
51
|
+
|
52
|
+
should "log the command when :log_command is true" do
|
35
53
|
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
54
|
Paperclip.run("this","is the command")
|
55
|
+
assert_received(Paperclip, :log) do |p|
|
56
|
+
p.with("this is the command 2>/dev/null")
|
57
|
+
end
|
58
|
+
assert_received(Paperclip, :`) do |p|
|
59
|
+
p.with("this is the command 2>/dev/null")
|
60
|
+
end
|
40
61
|
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
62
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
63
|
+
should "not log the command when :log_command is false" do
|
64
|
+
Paperclip.options[:log_command] = false
|
65
|
+
Paperclip.run("this","is the command")
|
66
|
+
assert_received(Paperclip, :log) do |p|
|
67
|
+
p.with("this is the command 2>/dev/null").never
|
68
|
+
end
|
69
|
+
assert_received(Paperclip, :`) do |p|
|
70
|
+
p.with("this is the command 2>/dev/null")
|
71
|
+
end
|
72
|
+
end
|
65
73
|
end
|
66
74
|
|
67
75
|
context "Paperclip.bit_bucket" do
|
@@ -86,6 +94,18 @@ class PaperclipTest < Test::Unit::TestCase
|
|
86
94
|
end
|
87
95
|
end
|
88
96
|
|
97
|
+
should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do
|
98
|
+
assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) }
|
99
|
+
end
|
100
|
+
|
101
|
+
should "raise when sent #processor and the name of a class that doesn't exist" do
|
102
|
+
assert_raises(NameError){ Paperclip.processor(:boogey_man) }
|
103
|
+
end
|
104
|
+
|
105
|
+
should "return a class when sent #processor and the name of a class under Paperclip" do
|
106
|
+
assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail)
|
107
|
+
end
|
108
|
+
|
89
109
|
context "An ActiveRecord model with an 'avatar' attachment" do
|
90
110
|
setup do
|
91
111
|
rebuild_model :path => "tmp/:class/omg/:style.:extension"
|
@@ -139,7 +159,8 @@ class PaperclipTest < Test::Unit::TestCase
|
|
139
159
|
end
|
140
160
|
|
141
161
|
should "be able to see the attachment definition from the subclass's class" do
|
142
|
-
assert_equal "tmp/:class/omg/:style.:extension",
|
162
|
+
assert_equal "tmp/:class/omg/:style.:extension",
|
163
|
+
SubDummy.attachment_definitions[:avatar][:path]
|
143
164
|
end
|
144
165
|
|
145
166
|
teardown do
|
@@ -286,6 +307,21 @@ class PaperclipTest < Test::Unit::TestCase
|
|
286
307
|
|
287
308
|
should_validate validation, options, valid_file, invalid_file
|
288
309
|
end
|
310
|
+
|
311
|
+
context "with size validation and less_than 10240 option" do
|
312
|
+
context "and assigned an invalid file" do
|
313
|
+
setup do
|
314
|
+
Dummy.send(:"validates_attachment_size", :avatar, :less_than => 10240)
|
315
|
+
@dummy = Dummy.new
|
316
|
+
@dummy.avatar &&= File.open(File.join(FIXTURES_DIR, "12k.png"), "rb")
|
317
|
+
@dummy.valid?
|
318
|
+
end
|
319
|
+
|
320
|
+
should "have a file size min/max error message" do
|
321
|
+
assert_match /between 0 and 10240 bytes/, @dummy.errors.on(:avatar)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
289
325
|
|
290
326
|
end
|
291
327
|
end
|
data/test/storage_test.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
require 'test/helper'
|
2
|
+
require 'aws/s3'
|
2
3
|
|
3
4
|
class StorageTest < Test::Unit::TestCase
|
5
|
+
def rails_env(env)
|
6
|
+
silence_warnings do
|
7
|
+
Object.const_set(:RAILS_ENV, env)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
4
11
|
context "Parsing S3 credentials" do
|
5
12
|
setup do
|
13
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
6
14
|
rebuild_model :storage => :s3,
|
7
15
|
:bucket => "testing",
|
8
16
|
:s3_credentials => {:not => :important}
|
@@ -14,31 +22,32 @@ class StorageTest < Test::Unit::TestCase
|
|
14
22
|
end
|
15
23
|
|
16
24
|
teardown do
|
17
|
-
|
25
|
+
rails_env(@current_env)
|
18
26
|
end
|
19
27
|
|
20
28
|
should "get the correct credentials when RAILS_ENV is production" do
|
21
|
-
|
29
|
+
rails_env("production")
|
22
30
|
assert_equal({:key => "12345"},
|
23
31
|
@avatar.parse_credentials('production' => {:key => '12345'},
|
24
32
|
:development => {:key => "54321"}))
|
25
33
|
end
|
26
34
|
|
27
35
|
should "get the correct credentials when RAILS_ENV is development" do
|
28
|
-
|
36
|
+
rails_env("development")
|
29
37
|
assert_equal({:key => "54321"},
|
30
38
|
@avatar.parse_credentials('production' => {:key => '12345'},
|
31
39
|
:development => {:key => "54321"}))
|
32
40
|
end
|
33
41
|
|
34
42
|
should "return the argument if the key does not exist" do
|
35
|
-
|
43
|
+
rails_env("not really an env")
|
36
44
|
assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345"))
|
37
45
|
end
|
38
46
|
end
|
39
47
|
|
40
48
|
context "" do
|
41
49
|
setup do
|
50
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
42
51
|
rebuild_model :storage => :s3,
|
43
52
|
:s3_credentials => {},
|
44
53
|
:bucket => "bucket",
|
@@ -54,6 +63,7 @@ class StorageTest < Test::Unit::TestCase
|
|
54
63
|
end
|
55
64
|
context "" do
|
56
65
|
setup do
|
66
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
57
67
|
rebuild_model :storage => :s3,
|
58
68
|
:s3_credentials => {},
|
59
69
|
:bucket => "bucket",
|
@@ -69,6 +79,7 @@ class StorageTest < Test::Unit::TestCase
|
|
69
79
|
end
|
70
80
|
context "" do
|
71
81
|
setup do
|
82
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
72
83
|
rebuild_model :storage => :s3,
|
73
84
|
:s3_credentials => {
|
74
85
|
:production => { :bucket => "prod_bucket" },
|
@@ -88,6 +99,7 @@ class StorageTest < Test::Unit::TestCase
|
|
88
99
|
|
89
100
|
context "Parsing S3 credentials with a bucket in them" do
|
90
101
|
setup do
|
102
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
91
103
|
rebuild_model :storage => :s3,
|
92
104
|
:s3_credentials => {
|
93
105
|
:production => { :bucket => "prod_bucket" },
|
@@ -97,15 +109,15 @@ class StorageTest < Test::Unit::TestCase
|
|
97
109
|
@old_env = RAILS_ENV
|
98
110
|
end
|
99
111
|
|
100
|
-
teardown{
|
112
|
+
teardown{ rails_env(@old_env) }
|
101
113
|
|
102
114
|
should "get the right bucket in production" do
|
103
|
-
|
115
|
+
rails_env("production")
|
104
116
|
assert_equal "prod_bucket", @dummy.avatar.bucket_name
|
105
117
|
end
|
106
118
|
|
107
119
|
should "get the right bucket in development" do
|
108
|
-
|
120
|
+
rails_env("development")
|
109
121
|
assert_equal "dev_bucket", @dummy.avatar.bucket_name
|
110
122
|
end
|
111
123
|
end
|
@@ -146,14 +158,7 @@ class StorageTest < Test::Unit::TestCase
|
|
146
158
|
|
147
159
|
context "and saved" do
|
148
160
|
setup do
|
149
|
-
@
|
150
|
-
@bucket_mock = stub
|
151
|
-
RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock)
|
152
|
-
@s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock)
|
153
|
-
@key_mock = stub
|
154
|
-
@bucket_mock.expects(:key).returns(@key_mock)
|
155
|
-
@key_mock.expects(:data=)
|
156
|
-
@key_mock.expects(:put).with(nil, 'public-read', 'Content-type' => 'image/png')
|
161
|
+
AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path, anything, 'testing', :content_type => 'image/png', :access => :public_read)
|
157
162
|
@dummy.save
|
158
163
|
end
|
159
164
|
|
@@ -164,13 +169,8 @@ class StorageTest < Test::Unit::TestCase
|
|
164
169
|
|
165
170
|
context "and remove" do
|
166
171
|
setup do
|
167
|
-
|
168
|
-
|
169
|
-
RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock)
|
170
|
-
@s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock)
|
171
|
-
@key_mock = stub
|
172
|
-
@bucket_mock.expects(:key).at_least(2).returns(@key_mock)
|
173
|
-
@key_mock.expects(:delete)
|
172
|
+
AWS::S3::S3Object.stubs(:exists?).returns(true)
|
173
|
+
AWS::S3::S3Object.stubs(:delete)
|
174
174
|
@dummy.destroy_attached_files
|
175
175
|
end
|
176
176
|
|
@@ -183,6 +183,7 @@ class StorageTest < Test::Unit::TestCase
|
|
183
183
|
|
184
184
|
context "An attachment with S3 storage and bucket defined as a Proc" do
|
185
185
|
setup do
|
186
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
186
187
|
rebuild_model :storage => :s3,
|
187
188
|
:bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" },
|
188
189
|
:s3_credentials => {:not => :important}
|
@@ -196,6 +197,7 @@ class StorageTest < Test::Unit::TestCase
|
|
196
197
|
|
197
198
|
context "An attachment with S3 storage and specific s3 headers set" do
|
198
199
|
setup do
|
200
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
199
201
|
rebuild_model :storage => :s3,
|
200
202
|
:bucket => "testing",
|
201
203
|
:path => ":attachment/:style/:basename.:extension",
|
@@ -217,17 +219,13 @@ class StorageTest < Test::Unit::TestCase
|
|
217
219
|
|
218
220
|
context "and saved" do
|
219
221
|
setup do
|
220
|
-
|
221
|
-
@
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
@key_mock.expects(:put).with(nil,
|
228
|
-
'public-read',
|
229
|
-
'Content-type' => 'image/png',
|
230
|
-
'Cache-Control' => 'max-age=31557600')
|
222
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
223
|
+
AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path,
|
224
|
+
anything,
|
225
|
+
'testing',
|
226
|
+
:content_type => 'image/png',
|
227
|
+
:access => :public_read,
|
228
|
+
'Cache-Control' => 'max-age=31557600')
|
231
229
|
@dummy.save
|
232
230
|
end
|
233
231
|
|
@@ -263,8 +261,8 @@ class StorageTest < Test::Unit::TestCase
|
|
263
261
|
|
264
262
|
teardown { @file.close }
|
265
263
|
|
266
|
-
should "still return a Tempfile when sent #
|
267
|
-
assert_equal Tempfile, @dummy.avatar.
|
264
|
+
should "still return a Tempfile when sent #to_file" do
|
265
|
+
assert_equal Tempfile, @dummy.avatar.to_file.class
|
268
266
|
end
|
269
267
|
|
270
268
|
context "and saved" do
|
data/test/thumbnail_test.rb
CHANGED
@@ -103,6 +103,44 @@ class ThumbnailTest < Test::Unit::TestCase
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
|
106
|
+
context "being thumbnailed with source file options set" do
|
107
|
+
setup do
|
108
|
+
@thumb = Paperclip::Thumbnail.new(@file,
|
109
|
+
:geometry => "100x50#",
|
110
|
+
:source_file_options => "-strip")
|
111
|
+
end
|
112
|
+
|
113
|
+
should "have source_file_options value set" do
|
114
|
+
assert_equal "-strip", @thumb.source_file_options
|
115
|
+
end
|
116
|
+
|
117
|
+
should "send the right command to convert when sent #make" do
|
118
|
+
Paperclip.expects(:"`").with do |arg|
|
119
|
+
arg.match %r{convert\s+-strip\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+"x50"\s+-crop\s+"100x50\+114\+0"\s+\+repage\s+".*?"}
|
120
|
+
end
|
121
|
+
@thumb.make
|
122
|
+
end
|
123
|
+
|
124
|
+
should "create the thumbnail when sent #make" do
|
125
|
+
dst = @thumb.make
|
126
|
+
assert_match /100x50/, `identify "#{dst.path}"`
|
127
|
+
end
|
128
|
+
|
129
|
+
context "redefined to have bad source_file_options setting" do
|
130
|
+
setup do
|
131
|
+
@thumb = Paperclip::Thumbnail.new(@file,
|
132
|
+
:geometry => "100x50#",
|
133
|
+
:source_file_options => "-this-aint-no-option")
|
134
|
+
end
|
135
|
+
|
136
|
+
should "error when trying to create the thumbnail" do
|
137
|
+
assert_raises(Paperclip::PaperclipError) do
|
138
|
+
@thumb.make
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
106
144
|
context "being thumbnailed with convert options set" do
|
107
145
|
setup do
|
108
146
|
@thumb = Paperclip::Thumbnail.new(@file,
|
@@ -140,6 +178,18 @@ class ThumbnailTest < Test::Unit::TestCase
|
|
140
178
|
end
|
141
179
|
end
|
142
180
|
end
|
181
|
+
|
182
|
+
context "being thumbnailed with a blank geometry string" do
|
183
|
+
setup do
|
184
|
+
@thumb = Paperclip::Thumbnail.new(@file,
|
185
|
+
:geometry => "",
|
186
|
+
:convert_options => "-gravity center -crop \"300x300+0-0\"")
|
187
|
+
end
|
188
|
+
|
189
|
+
should "not get resized by default" do
|
190
|
+
assert_no_match(/-resize/, @thumb.transformation_command)
|
191
|
+
end
|
192
|
+
end
|
143
193
|
end
|
144
194
|
|
145
195
|
context "A multipage PDF" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thoughtbot-paperclip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.
|
4
|
+
version: 2.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Yurek
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-08-21 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- shoulda_macros/paperclip.rb
|
96
96
|
has_rdoc: true
|
97
97
|
homepage: http://www.thoughtbot.com/projects/paperclip
|
98
|
+
licenses:
|
98
99
|
post_install_message:
|
99
100
|
rdoc_options:
|
100
101
|
- --line-numbers
|
@@ -116,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
116
117
|
requirements:
|
117
118
|
- ImageMagick
|
118
119
|
rubyforge_project: paperclip
|
119
|
-
rubygems_version: 1.
|
120
|
+
rubygems_version: 1.3.5
|
120
121
|
signing_key:
|
121
122
|
specification_version: 2
|
122
123
|
summary: File attachments as attributes for ActiveRecord
|