paperclip 2.1.5 → 2.2.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.
- data/README.rdoc +123 -10
- data/Rakefile +1 -5
- data/lib/paperclip.rb +63 -24
- data/lib/paperclip/attachment.rb +90 -48
- data/lib/paperclip/callback_compatability.rb +33 -0
- data/lib/paperclip/iostream.rb +1 -1
- data/lib/paperclip/processor.rb +47 -0
- data/lib/paperclip/storage.rb +11 -1
- data/lib/paperclip/thumbnail.rb +13 -31
- data/shoulda_macros/paperclip.rb +131 -10
- data/test/attachment_test.rb +126 -32
- data/test/helper.rb +2 -0
- data/test/integration_test.rb +64 -1
- data/test/iostream_test.rb +2 -0
- data/test/paperclip_test.rb +39 -3
- data/test/processor_test.rb +10 -0
- data/test/storage_test.rb +48 -0
- data/test/thumbnail_test.rb +12 -6
- metadata +5 -2
@@ -0,0 +1,33 @@
|
|
1
|
+
module Paperclip
|
2
|
+
# This module is intended as a compatability shim for the differences in
|
3
|
+
# callbacks between Rails 2.0 and Rails 2.1.
|
4
|
+
module CallbackCompatability
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
base.send(:include, InstanceMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# The implementation of this method is taken from the Rails 1.2.6 source,
|
12
|
+
# from rails/activerecord/lib/active_record/callbacks.rb, line 192.
|
13
|
+
def define_callbacks(*args)
|
14
|
+
args.each do |method|
|
15
|
+
self.class_eval <<-"end_eval"
|
16
|
+
def self.#{method}(*callbacks, &block)
|
17
|
+
callbacks << block if block_given?
|
18
|
+
write_inheritable_array(#{method.to_sym.inspect}, callbacks)
|
19
|
+
end
|
20
|
+
end_eval
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module InstanceMethods
|
26
|
+
# The callbacks in < 2.1 don't worry about the extra options or the
|
27
|
+
# block, so just run what we have available.
|
28
|
+
def run_callbacks(meth, opts = nil, &blk)
|
29
|
+
callback(meth)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/paperclip/iostream.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Paperclip
|
2
|
+
# Paperclip processors allow you to modify attached files when they are
|
3
|
+
# attached in any way you are able. Paperclip itself uses command-line
|
4
|
+
# programs for its included Thumbnail processor, but custom processors
|
5
|
+
# are not required to follow suit.
|
6
|
+
#
|
7
|
+
# Processors are required to be defined inside the Paperclip module and
|
8
|
+
# are also required to be a subclass of Paperclip::Processor. There are
|
9
|
+
# only two methods you must implement to properly be a subclass:
|
10
|
+
# #initialize and #make. Initialize's arguments are the file that will
|
11
|
+
# be operated on (which is an instance of File), and a hash of options
|
12
|
+
# that were defined in has_attached_file's style hash.
|
13
|
+
#
|
14
|
+
# All #make needs to do is return an instance of File (Tempfile is
|
15
|
+
# acceptable) which contains the results of the processing.
|
16
|
+
#
|
17
|
+
# See Paperclip.run for more information about using command-line
|
18
|
+
# utilities from within Processors.
|
19
|
+
class Processor
|
20
|
+
attr_accessor :file, :options
|
21
|
+
|
22
|
+
def initialize file, options = {}
|
23
|
+
@file = file
|
24
|
+
@options = options
|
25
|
+
end
|
26
|
+
|
27
|
+
def make
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.make file, options = {}
|
31
|
+
new(file, options).make
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Due to how ImageMagick handles its image format conversion and how Tempfile
|
36
|
+
# handles its naming scheme, it is necessary to override how Tempfile makes
|
37
|
+
# its names so as to allow for file extensions. Idea taken from the comments
|
38
|
+
# on this blog post:
|
39
|
+
# http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions
|
40
|
+
class Tempfile < ::Tempfile
|
41
|
+
# Replaces Tempfile's +make_tmpname+ with one that honors file extensions.
|
42
|
+
def make_tmpname(basename, n)
|
43
|
+
extension = File.extname(basename)
|
44
|
+
sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/paperclip/storage.rb
CHANGED
@@ -56,6 +56,14 @@ module Paperclip
|
|
56
56
|
rescue Errno::ENOENT => e
|
57
57
|
# ignore file-not-found, let everything else pass
|
58
58
|
end
|
59
|
+
begin
|
60
|
+
while(true)
|
61
|
+
path = File.dirname(path)
|
62
|
+
FileUtils.rmdir(path)
|
63
|
+
end
|
64
|
+
rescue Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL
|
65
|
+
# Stop trying to remove parent directories
|
66
|
+
end
|
59
67
|
end
|
60
68
|
@queued_for_delete = []
|
61
69
|
end
|
@@ -91,6 +99,7 @@ module Paperclip
|
|
91
99
|
# * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either
|
92
100
|
# 'http' or 'https'. Defaults to 'http' when your :s3_permissions are 'public-read' (the
|
93
101
|
# default), and 'https' when your :s3_permissions are anything else.
|
102
|
+
# * +s3_headers+: A hash of headers such as {'Expires' => 1.year.from_now.httpdate}
|
94
103
|
# * +bucket+: This is the name of the S3 bucket that will store your files. Remember
|
95
104
|
# that the bucket must be unique across all of Amazon S3. If the bucket does not exist
|
96
105
|
# Paperclip will attempt to create it. The bucket name will not be interpolated.
|
@@ -113,6 +122,7 @@ module Paperclip
|
|
113
122
|
@s3_options = @options[:s3_options] || {}
|
114
123
|
@s3_permissions = @options[:s3_permissions] || 'public-read'
|
115
124
|
@s3_protocol = @options[:s3_protocol] || (@s3_permissions == 'public-read' ? 'http' : 'https')
|
125
|
+
@s3_headers = @options[:s3_headers] || {}
|
116
126
|
@url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/)
|
117
127
|
end
|
118
128
|
base.class.interpolations[:s3_path_url] = lambda do |attachment, style|
|
@@ -165,7 +175,7 @@ module Paperclip
|
|
165
175
|
logger.info("[paperclip] -> #{path(style)}")
|
166
176
|
key = s3_bucket.key(path(style))
|
167
177
|
key.data = file
|
168
|
-
key.put(nil, @s3_permissions, {'Content-type' => instance_read(:content_type)})
|
178
|
+
key.put(nil, @s3_permissions, {'Content-type' => instance_read(:content_type)}.merge(@s3_headers))
|
169
179
|
rescue RightAws::AwsError => e
|
170
180
|
raise
|
171
181
|
end
|
data/lib/paperclip/thumbnail.rb
CHANGED
@@ -1,33 +1,28 @@
|
|
1
1
|
module Paperclip
|
2
2
|
# Handles thumbnailing images that are uploaded.
|
3
|
-
class Thumbnail
|
3
|
+
class Thumbnail < Processor
|
4
4
|
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_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+
|
9
9
|
# which is a "WxH"-style string. +format+ will be inferred from the +file+
|
10
10
|
# unless specified. Thumbnail creation will raise no errors unless
|
11
|
-
# +
|
11
|
+
# +whiny+ is true (which it is, by default. If +convert_options+ is
|
12
12
|
# set, the options will be appended to the convert command upon image conversion
|
13
|
-
def initialize file,
|
13
|
+
def initialize file, options = {}
|
14
|
+
super
|
15
|
+
geometry = options[:geometry]
|
14
16
|
@file = file
|
15
|
-
@crop =
|
16
|
-
@target_geometry = Geometry.parse
|
17
|
-
@current_geometry = Geometry.from_file file
|
18
|
-
@convert_options = convert_options
|
19
|
-
@
|
17
|
+
@crop = geometry[-1,1] == '#'
|
18
|
+
@target_geometry = Geometry.parse geometry
|
19
|
+
@current_geometry = Geometry.from_file @file
|
20
|
+
@convert_options = options[:convert_options]
|
21
|
+
@whiny = options[:whiny].nil? ? true : options[:whiny]
|
22
|
+
@format = options[:format]
|
20
23
|
|
21
24
|
@current_format = File.extname(@file.path)
|
22
25
|
@basename = File.basename(@file.path, @current_format)
|
23
|
-
|
24
|
-
@format = format
|
25
|
-
end
|
26
|
-
|
27
|
-
# Creates a thumbnail, as specified in +initialize+, +make+s it, and returns the
|
28
|
-
# resulting Tempfile.
|
29
|
-
def self.make file, dimensions, format = nil, convert_options = nil, whiny_thumbnails = true
|
30
|
-
new(file, dimensions, format, convert_options, whiny_thumbnails).make
|
31
26
|
end
|
32
27
|
|
33
28
|
# Returns true if the +target_geometry+ is meant to crop.
|
@@ -56,7 +51,7 @@ module Paperclip
|
|
56
51
|
begin
|
57
52
|
success = Paperclip.run("convert", command.gsub(/\s+/, " "))
|
58
53
|
rescue PaperclipCommandLineError
|
59
|
-
raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @
|
54
|
+
raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny
|
60
55
|
end
|
61
56
|
|
62
57
|
dst
|
@@ -72,17 +67,4 @@ module Paperclip
|
|
72
67
|
trans
|
73
68
|
end
|
74
69
|
end
|
75
|
-
|
76
|
-
# Due to how ImageMagick handles its image format conversion and how Tempfile
|
77
|
-
# handles its naming scheme, it is necessary to override how Tempfile makes
|
78
|
-
# its names so as to allow for file extensions. Idea taken from the comments
|
79
|
-
# on this blog post:
|
80
|
-
# http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions
|
81
|
-
class Tempfile < ::Tempfile
|
82
|
-
# Replaces Tempfile's +make_tmpname+ with one that honors file extensions.
|
83
|
-
def make_tmpname(basename, n)
|
84
|
-
extension = File.extname(basename)
|
85
|
-
sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension)
|
86
|
-
end
|
87
|
-
end
|
88
70
|
end
|
data/shoulda_macros/paperclip.rb
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
module Paperclip
|
2
|
+
# =Paperclip Shoulda Macros
|
3
|
+
#
|
4
|
+
# These macros are intended for use with shoulda, and will be included into
|
5
|
+
# your tests automatically. All of the macros use the standard shoulda
|
6
|
+
# assumption that the name of the test is based on the name of the model
|
7
|
+
# you're testing (that is, UserTest is the test for the User model), and
|
8
|
+
# will load that class for testing purposes.
|
2
9
|
module Shoulda
|
10
|
+
# This will test whether you have defined your attachment correctly by
|
11
|
+
# checking for all the required fields exist after the definition of the
|
12
|
+
# attachment.
|
3
13
|
def should_have_attached_file name, options = {}
|
4
14
|
klass = self.name.gsub(/Test$/, '').constantize
|
5
15
|
context "Class #{klass.name} with attachment #{name}" do
|
@@ -8,20 +18,131 @@ module Paperclip
|
|
8
18
|
assert klass.instance_methods.include?(meth), "#{klass.name} does not respond to #{name}."
|
9
19
|
end
|
10
20
|
end
|
21
|
+
end
|
22
|
+
end
|
11
23
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
24
|
+
# Tests for validations on the presence of the attachment.
|
25
|
+
def should_validate_attachment_presence name
|
26
|
+
klass = self.name.gsub(/Test$/, '').constantize
|
27
|
+
context "Class #{klass.name} validating presence on #{name}" do
|
28
|
+
context "when the assignment is nil" do
|
29
|
+
setup do
|
30
|
+
@attachment = klass.new.send(name)
|
31
|
+
@attachment.assign(nil)
|
32
|
+
end
|
33
|
+
should "have a :presence validation error" do
|
34
|
+
assert @assignment.errors[:presence]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
context "when the assignment is valid" do
|
38
|
+
setup do
|
39
|
+
@attachment = klass.new.send(name)
|
40
|
+
@attachment.assign(nil)
|
41
|
+
end
|
42
|
+
should "have a :presence validation error" do
|
43
|
+
assert ! @assignment.errors[:presence]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
17
48
|
|
18
|
-
|
49
|
+
# Tests that you have content_type validations specified. There are two
|
50
|
+
# options, :valid and :invalid. Both accept an array of strings. The
|
51
|
+
# strings should be a list of content types which will pass and fail
|
52
|
+
# validation, respectively.
|
53
|
+
def should_validate_attachment_content_type name, options = {}
|
54
|
+
klass = self.name.gsub(/Test$/, '').constantize
|
55
|
+
valid = [options[:valid]].flatten
|
56
|
+
invalid = [options[:invalid]].flatten
|
57
|
+
context "Class #{klass.name} validating content_types on #{name}" do
|
58
|
+
valid.each do |type|
|
59
|
+
context "being assigned a file with a content_type of #{type}" do
|
60
|
+
setup do
|
61
|
+
@file = StringIO.new(".")
|
62
|
+
class << @file; attr_accessor :content_type; end
|
63
|
+
@file.content_type = type
|
64
|
+
@attachment = klass.new.send(name)
|
65
|
+
@attachment.assign(@file)
|
66
|
+
end
|
67
|
+
should "not have a :content_type validation error" do
|
68
|
+
assert ! @assignment.errors[:content_type]
|
69
|
+
end
|
70
|
+
end
|
19
71
|
end
|
72
|
+
invalid.each do |type|
|
73
|
+
context "being assigned a file with a content_type of #{type}" do
|
74
|
+
setup do
|
75
|
+
@file = StringIO.new(".")
|
76
|
+
class << @file; attr_accessor :content_type; end
|
77
|
+
@file.content_type = type
|
78
|
+
@attachment = klass.new.send(name)
|
79
|
+
@attachment.assign(@file)
|
80
|
+
end
|
81
|
+
should "have a :content_type validation error" do
|
82
|
+
assert @assignment.errors[:content_type]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Tests to ensure that you have file size validations turned on. You
|
90
|
+
# can pass the same options to this that you can to
|
91
|
+
# validate_attachment_file_size - :less_than, :greater_than, and :in.
|
92
|
+
# :less_than checks that a file is less than a certain size, :greater_than
|
93
|
+
# checks that a file is more than a certain size, and :in takes a Range or
|
94
|
+
# Array which specifies the lower and upper limits of the file size.
|
95
|
+
def should_validate_attachment_size name, options = {}
|
96
|
+
klass = self.name.gsub(/Test$/, '').constantize
|
97
|
+
min = options[:greater_than] || (options[:in] && options[:in].first) || 0
|
98
|
+
max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
|
99
|
+
range = (min..max)
|
100
|
+
context "Class #{klass.name} validating file size on #{name}" do
|
101
|
+
context "with an attachment that is #{max+1} bytes" do
|
102
|
+
setup do
|
103
|
+
@file = StringIO.new("." * (max+1))
|
104
|
+
@attachment = klass.new.send(name)
|
105
|
+
@attachment.assign(@file)
|
106
|
+
end
|
107
|
+
|
108
|
+
should "have a :size validation error" do
|
109
|
+
assert @attachment.errors[:size]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
context "with an attachment that us #{max-1} bytes" do
|
113
|
+
setup do
|
114
|
+
@file = StringIO.new("." * (max-1))
|
115
|
+
@attachment = klass.new.send(name)
|
116
|
+
@attachment.assign(@file)
|
117
|
+
end
|
118
|
+
|
119
|
+
should "not have a :size validation error" do
|
120
|
+
assert ! @attachment.errors[:size]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
if min > 0
|
125
|
+
context "with an attachment that is #{min-1} bytes" do
|
126
|
+
setup do
|
127
|
+
@file = StringIO.new("." * (min-1))
|
128
|
+
@attachment = klass.new.send(name)
|
129
|
+
@attachment.assign(@file)
|
130
|
+
end
|
131
|
+
|
132
|
+
should "have a :size validation error" do
|
133
|
+
assert @attachment.errors[:size]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
context "with an attachment that us #{min+1} bytes" do
|
137
|
+
setup do
|
138
|
+
@file = StringIO.new("." * (min+1))
|
139
|
+
@attachment = klass.new.send(name)
|
140
|
+
@attachment.assign(@file)
|
141
|
+
end
|
20
142
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
assert_equal 0, $?, "ImageMagick's #{command} returned with an error. Make sure that #{command} is available at #{Paperclip.path_for_command(command)}"
|
143
|
+
should "not have a :size validation error" do
|
144
|
+
assert ! @attachment.errors[:size]
|
145
|
+
end
|
25
146
|
end
|
26
147
|
end
|
27
148
|
end
|
data/test/attachment_test.rb
CHANGED
@@ -81,6 +81,8 @@ class AttachmentTest < Test::Unit::TestCase
|
|
81
81
|
@dummy.avatar = @file
|
82
82
|
end
|
83
83
|
|
84
|
+
teardown { @file.close }
|
85
|
+
|
84
86
|
should "make sure that they are interpolated correctly" do
|
85
87
|
assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path
|
86
88
|
end
|
@@ -99,6 +101,8 @@ class AttachmentTest < Test::Unit::TestCase
|
|
99
101
|
@dummy.avatar = @file
|
100
102
|
end
|
101
103
|
|
104
|
+
teardown { @file.close }
|
105
|
+
|
102
106
|
should "return the proper path" do
|
103
107
|
temporary_rails_env(@rails_env) {
|
104
108
|
assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path
|
@@ -117,6 +121,7 @@ class AttachmentTest < Test::Unit::TestCase
|
|
117
121
|
:thumb => "-thumbnailize"
|
118
122
|
}
|
119
123
|
@dummy = Dummy.new
|
124
|
+
@dummy.avatar
|
120
125
|
end
|
121
126
|
|
122
127
|
should "report the correct options when sent #extra_options_for(:thumb)" do
|
@@ -127,48 +132,128 @@ class AttachmentTest < Test::Unit::TestCase
|
|
127
132
|
assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
|
128
133
|
end
|
129
134
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
135
|
+
before_should "call extra_options_for(:thumb/:large)" do
|
136
|
+
Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb)
|
137
|
+
Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "An attachment with both 'normal' and hash-style styles" do
|
142
|
+
setup do
|
143
|
+
rebuild_model :styles => {
|
144
|
+
:normal => ["50x50#", :png],
|
145
|
+
:hash => { :geometry => "50x50#", :format => :png }
|
146
|
+
}
|
147
|
+
@dummy = Dummy.new
|
148
|
+
@attachment = @dummy.avatar
|
149
|
+
end
|
150
|
+
|
151
|
+
[:processors, :whiny, :convert_options, :geometry, :format].each do |field|
|
152
|
+
should "have the same #{field} field" do
|
153
|
+
assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field]
|
139
154
|
end
|
155
|
+
end
|
156
|
+
end
|
140
157
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
158
|
+
context "An attachment with multiple processors" do
|
159
|
+
setup do
|
160
|
+
class Paperclip::Test < Paperclip::Processor; end
|
161
|
+
@style_params = { :once => {:one => 1, :two => 2} }
|
162
|
+
rebuild_model :processors => [:thumbnail, :test], :styles => @style_params
|
163
|
+
@dummy = Dummy.new
|
164
|
+
@file = StringIO.new("...")
|
165
|
+
@file.stubs(:to_tempfile).returns(@file)
|
166
|
+
Paperclip::Test.stubs(:make).returns(@file)
|
167
|
+
Paperclip::Thumbnail.stubs(:make).returns(@file)
|
168
|
+
end
|
169
|
+
|
170
|
+
context "when assigned" do
|
171
|
+
setup { @dummy.avatar = @file }
|
172
|
+
|
173
|
+
before_should "call #make on all specified processors" do
|
174
|
+
expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => nil, :convert_options => ""})
|
175
|
+
Paperclip::Thumbnail.expects(:make).with(@file, expected_params).returns(@file)
|
176
|
+
Paperclip::Test.expects(:make).with(@file, expected_params).returns(@file)
|
146
177
|
end
|
147
178
|
end
|
148
179
|
end
|
149
180
|
|
181
|
+
context "Assigning an attachment with post_process hooks" do
|
182
|
+
setup do
|
183
|
+
rebuild_model :styles => { :something => "100x100#" }
|
184
|
+
Dummy.class_eval do
|
185
|
+
before_avatar_post_process :do_before_avatar
|
186
|
+
after_avatar_post_process :do_after_avatar
|
187
|
+
before_post_process :do_before_all
|
188
|
+
after_post_process :do_after_all
|
189
|
+
def do_before_avatar; end
|
190
|
+
def do_after_avatar; end
|
191
|
+
def do_before_all; end
|
192
|
+
def do_after_all; end
|
193
|
+
end
|
194
|
+
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
|
195
|
+
@file.stubs(:to_tempfile).returns(@file)
|
196
|
+
@dummy = Dummy.new
|
197
|
+
Paperclip::Thumbnail.stubs(:make).returns(@file)
|
198
|
+
@attachment = @dummy.avatar
|
199
|
+
end
|
200
|
+
|
201
|
+
should "call the defined callbacks when assigned" do
|
202
|
+
@dummy.expects(:do_before_avatar).with()
|
203
|
+
@dummy.expects(:do_after_avatar).with()
|
204
|
+
@dummy.expects(:do_before_all).with()
|
205
|
+
@dummy.expects(:do_after_all).with()
|
206
|
+
Paperclip::Thumbnail.expects(:make).returns(@file)
|
207
|
+
@dummy.avatar = @file
|
208
|
+
end
|
209
|
+
|
210
|
+
should "not cancel the processing if a before_post_process returns nil" do
|
211
|
+
@dummy.expects(:do_before_avatar).with().returns(nil)
|
212
|
+
@dummy.expects(:do_after_avatar).with()
|
213
|
+
@dummy.expects(:do_before_all).with().returns(nil)
|
214
|
+
@dummy.expects(:do_after_all).with()
|
215
|
+
Paperclip::Thumbnail.expects(:make).returns(@file)
|
216
|
+
@dummy.avatar = @file
|
217
|
+
end
|
218
|
+
|
219
|
+
should "cancel the processing if a before_post_process returns false" do
|
220
|
+
@dummy.expects(:do_before_avatar).never
|
221
|
+
@dummy.expects(:do_after_avatar).never
|
222
|
+
@dummy.expects(:do_before_all).with().returns(false)
|
223
|
+
@dummy.expects(:do_after_all).never
|
224
|
+
Paperclip::Thumbnail.expects(:make).never
|
225
|
+
@dummy.avatar = @file
|
226
|
+
end
|
227
|
+
|
228
|
+
should "cancel the processing if a before_avatar_post_process returns false" do
|
229
|
+
@dummy.expects(:do_before_avatar).with().returns(false)
|
230
|
+
@dummy.expects(:do_after_avatar).never
|
231
|
+
@dummy.expects(:do_before_all).with().returns(true)
|
232
|
+
@dummy.expects(:do_after_all).never
|
233
|
+
Paperclip::Thumbnail.expects(:make).never
|
234
|
+
@dummy.avatar = @file
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
150
238
|
context "Assigning an attachment" do
|
151
239
|
setup do
|
152
|
-
rebuild_model
|
153
|
-
|
154
|
-
@
|
155
|
-
@
|
156
|
-
@
|
157
|
-
@not_file.expects(:original_filename).returns("filename.png\r\n")
|
158
|
-
@not_file.expects(:content_type).returns("image/png\r\n")
|
159
|
-
@not_file.expects(:size).returns(10).times(2)
|
160
|
-
|
240
|
+
rebuild_model :styles => { :something => "100x100#" }
|
241
|
+
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
|
242
|
+
@file.expects(:original_filename).returns("5k.png\n\n")
|
243
|
+
@file.expects(:content_type).returns("image/png\n\n")
|
244
|
+
@file.stubs(:to_tempfile).returns(@file)
|
161
245
|
@dummy = Dummy.new
|
246
|
+
Paperclip::Thumbnail.expects(:make).returns(@file)
|
247
|
+
@dummy.expects(:run_callbacks).with(:before_avatar_post_process, {:original => @file})
|
248
|
+
@dummy.expects(:run_callbacks).with(:before_post_process, {:original => @file})
|
249
|
+
@dummy.expects(:run_callbacks).with(:after_avatar_post_process, {:original => @file, :something => @file})
|
250
|
+
@dummy.expects(:run_callbacks).with(:after_post_process, {:original => @file, :something => @file})
|
162
251
|
@attachment = @dummy.avatar
|
163
|
-
@
|
164
|
-
@attachment.expects(:queue_existing_for_delete)
|
165
|
-
@attachment.expects(:post_process)
|
166
|
-
@attachment.expects(:validate)
|
167
|
-
@dummy.avatar = @not_file
|
252
|
+
@dummy.avatar = @file
|
168
253
|
end
|
169
254
|
|
170
255
|
should "strip whitespace from original_filename field" do
|
171
|
-
assert_equal "
|
256
|
+
assert_equal "5k.png", @dummy.avatar.original_filename
|
172
257
|
end
|
173
258
|
|
174
259
|
should "strip whitespace from content_type field" do
|
@@ -192,6 +277,7 @@ class AttachmentTest < Test::Unit::TestCase
|
|
192
277
|
@attachment.expects(:valid_assignment?).with(@not_file).returns(true)
|
193
278
|
@attachment.expects(:queue_existing_for_delete)
|
194
279
|
@attachment.expects(:post_process)
|
280
|
+
@attachment.expects(:valid?).returns(true)
|
195
281
|
@attachment.expects(:validate)
|
196
282
|
@dummy.avatar = @not_file
|
197
283
|
end
|
@@ -216,6 +302,8 @@ class AttachmentTest < Test::Unit::TestCase
|
|
216
302
|
"5k.png"), 'rb')
|
217
303
|
end
|
218
304
|
|
305
|
+
teardown { @file.close }
|
306
|
+
|
219
307
|
should "raise if there are not the correct columns when you try to assign" do
|
220
308
|
@other_attachment = Paperclip::Attachment.new(:not_here, @instance)
|
221
309
|
assert_raises(Paperclip::PaperclipError) do
|
@@ -247,12 +335,16 @@ class AttachmentTest < Test::Unit::TestCase
|
|
247
335
|
|
248
336
|
should "return a correct url even if the file does not exist" do
|
249
337
|
assert_nil @attachment.to_file
|
250
|
-
assert_match %r{^/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
|
338
|
+
assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
|
251
339
|
end
|
252
340
|
|
253
341
|
should "make sure the updated_at mtime is in the url if it is defined" do
|
254
342
|
assert_match %r{#{Time.now.to_i}$}, @attachment.url(:blah)
|
255
343
|
end
|
344
|
+
|
345
|
+
should "make sure the updated_at mtime is NOT in the url if false is passed to the url method" do
|
346
|
+
assert_no_match %r{#{Time.now.to_i}$}, @attachment.url(:blah, false)
|
347
|
+
end
|
256
348
|
|
257
349
|
context "with the updated_at field removed" do
|
258
350
|
setup do
|
@@ -302,8 +394,8 @@ class AttachmentTest < Test::Unit::TestCase
|
|
302
394
|
should "return the real url" do
|
303
395
|
file = @attachment.to_file
|
304
396
|
assert file
|
305
|
-
assert_match %r{^/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
|
306
|
-
assert_match %r{^/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
|
397
|
+
assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
|
398
|
+
assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
|
307
399
|
file.close
|
308
400
|
end
|
309
401
|
|
@@ -378,6 +470,8 @@ class AttachmentTest < Test::Unit::TestCase
|
|
378
470
|
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
379
471
|
end
|
380
472
|
|
473
|
+
teardown { @file.close }
|
474
|
+
|
381
475
|
should "not error when assigned an attachment" do
|
382
476
|
assert_nothing_raised { @dummy.avatar = @file }
|
383
477
|
end
|