paperclip 2.3.11 → 2.3.12

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.

@@ -11,6 +11,7 @@ module Paperclip
11
11
  when %r"jp(e|g|eg)" then "image/jpeg"
12
12
  when %r"tiff?" then "image/tiff"
13
13
  when %r"png", "gif", "bmp" then "image/#{type}"
14
+ when %r"svg" then "image/svg+xml"
14
15
  when "txt" then "text/plain"
15
16
  when %r"html?" then "text/html"
16
17
  when "js" then "application/js"
@@ -1,3 +1,3 @@
1
1
  module Paperclip
2
- VERSION = "2.3.11" unless defined? Paperclip::VERSION
2
+ VERSION = "2.3.12" unless defined? Paperclip::VERSION
3
3
  end
@@ -5,7 +5,7 @@ def obtain_class
5
5
  end
6
6
 
7
7
  def obtain_attachments(klass)
8
- klass = Object.const_get(klass.to_s)
8
+ klass = Paperclip.class_for(klass.to_s)
9
9
  name = ENV['ATTACHMENT'] || ENV['attachment']
10
10
  raise "Class #{klass.name} has no attachments specified" unless klass.respond_to?(:attachment_definitions)
11
11
  if !name.blank? && klass.attachment_definitions.keys.include?(name)
@@ -20,14 +20,15 @@ namespace :paperclip do
20
20
  task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"]
21
21
 
22
22
  namespace :refresh do
23
- desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)."
23
+ desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT and STYLES splitted by comma)."
24
24
  task :thumbnails => :environment do
25
25
  errors = []
26
26
  klass = obtain_class
27
27
  names = obtain_attachments(klass)
28
+ styles = (ENV['STYLES'] || ENV['styles'] || '').split(',').map(&:to_sym)
28
29
  names.each do |name|
29
30
  Paperclip.each_instance_with_attachment(klass, name) do |instance|
30
- result = instance.send(name).reprocess!
31
+ instance.send(name).reprocess!(*styles)
31
32
  errors << [instance.id, instance.errors] unless instance.errors.blank?
32
33
  end
33
34
  end
@@ -44,7 +45,11 @@ namespace :paperclip do
44
45
  instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
45
46
  instance.send("#{name}_content_type=", file.content_type.strip)
46
47
  instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
47
- instance.save(false)
48
+ if Rails.version >= "3.0.0"
49
+ instance.save(:validate => false)
50
+ else
51
+ instance.save(false)
52
+ end
48
53
  else
49
54
  true
50
55
  end
@@ -14,6 +14,28 @@ 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 "return the url by interpolating the default_url option when no file assigned" do
18
+ @attachment = attachment :default_url => ":class/blegga.png"
19
+ @model = @attachment.instance
20
+ assert_nil @model.avatar_file_name
21
+ assert_equal "fake_models/blegga.png", @attachment.url
22
+ end
23
+
24
+ should "return the url by executing and interpolating the default_url Proc when no file assigned" do
25
+ @attachment = attachment :default_url => lambda { |a| ":class/blegga.png" }
26
+ @model = @attachment.instance
27
+ assert_nil @model.avatar_file_name
28
+ assert_equal "fake_models/blegga.png", @attachment.url
29
+ end
30
+
31
+ should "return the url by executing and interpolating the default_url Proc with attachment arg when no file assigned" do
32
+ @attachment = attachment :default_url => lambda { |a| a.instance.some_method_to_determine_default_url }
33
+ @model = @attachment.instance
34
+ @model.stubs(:some_method_to_determine_default_url).returns(":class/blegga.png")
35
+ assert_nil @model.avatar_file_name
36
+ assert_equal "fake_models/blegga.png", @attachment.url
37
+ end
38
+
17
39
  context "Attachment default_options" do
18
40
  setup do
19
41
  rebuild_model
@@ -228,6 +250,24 @@ class AttachmentTest < Test::Unit::TestCase
228
250
  end
229
251
  end
230
252
 
253
+ context "An attachment with :only_process" do
254
+ setup do
255
+ rebuild_model :styles => {
256
+ :thumb => "100x100",
257
+ :large => "400x400"
258
+ },
259
+ :only_process => [:thumb]
260
+ @file = StringIO.new("...")
261
+ @attachment = Dummy.new.avatar
262
+ end
263
+
264
+ should "only process the provided style" do
265
+ @attachment.expects(:post_process).with(:thumb)
266
+ @attachment.expects(:post_process).with(:large).never
267
+ @attachment.assign(@file)
268
+ end
269
+ end
270
+
231
271
  context "An attachment with :convert_options that is a proc" do
232
272
  setup do
233
273
  rebuild_model :styles => {
@@ -287,6 +327,24 @@ class AttachmentTest < Test::Unit::TestCase
287
327
  assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
288
328
  end
289
329
  end
330
+
331
+ context "An attachment with conditional :styles that is a proc" do
332
+ setup do
333
+ rebuild_model :styles => lambda{ |attachment| attachment.instance.other == 'a' ? {:thumb => "50x50#"} : {:large => "400x400"} }
334
+
335
+ @dummy = Dummy.new(:other => 'a')
336
+ end
337
+
338
+ should "have the correct styles for the assigned instance values" do
339
+ assert_equal "50x50#", @dummy.avatar.styles[:thumb][:geometry]
340
+ assert_nil @dummy.avatar.styles[:large]
341
+
342
+ @dummy.other = 'b'
343
+
344
+ assert_equal "400x400", @dummy.avatar.styles[:large][:geometry]
345
+ assert_nil @dummy.avatar.styles[:thumb]
346
+ end
347
+ end
290
348
 
291
349
  context "An attachment with :url that is a proc" do
292
350
  setup do
@@ -101,6 +101,26 @@ class FogTest < Test::Unit::TestCase
101
101
  end
102
102
  end
103
103
 
104
+ context "with a fog_host that includes a wildcard placeholder" do
105
+ setup do
106
+ rebuild_model(
107
+ :fog_directory => @fog_directory,
108
+ :fog_credentials => @credentials,
109
+ :fog_host => 'http://img%d.example.com',
110
+ :fog_public => true,
111
+ :path => ":attachment/:basename.:extension",
112
+ :storage => :fog
113
+ )
114
+ @dummy = Dummy.new
115
+ @dummy.avatar = StringIO.new('.')
116
+ @dummy.save
117
+ end
118
+
119
+ should "provide a public url" do
120
+ assert @dummy.avatar.url =~ /^http:\/\/img[0123]\.example\.com\/avatars\/stringio\.txt\?\d*$/
121
+ end
122
+ end
123
+
104
124
  end
105
125
 
106
126
  end
@@ -120,6 +120,35 @@ class GeometryTest < Test::Unit::TestCase
120
120
  assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
121
121
  end
122
122
 
123
+ should "not generate from a blank filename" do
124
+ file = ""
125
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
126
+ end
127
+
128
+ should "not generate from a nil file" do
129
+ file = nil
130
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
131
+ end
132
+
133
+ should "not generate from a file with no path" do
134
+ file = mock("file", :path => "")
135
+ file.stubs(:respond_to?).with("path").returns(true)
136
+ assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) }
137
+ end
138
+
139
+ should "let us know when a command isn't found versus a processing error" do
140
+ old_path = ENV['PATH']
141
+ begin
142
+ ENV['PATH'] = ''
143
+ assert_raises(Paperclip::CommandNotFoundError) do
144
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
145
+ @geo = Paperclip::Geometry.from_file(file)
146
+ end
147
+ ensure
148
+ ENV['PATH'] = old_path
149
+ end
150
+ end
151
+
123
152
  [['vertical', 900, 1440, true, false, false, 1440, 900, 0.625],
124
153
  ['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333],
125
154
  ['square', 100, 100, false, false, true, 100, 100, 1]].each do |args|
@@ -67,6 +67,7 @@ end
67
67
 
68
68
  def rebuild_model options = {}
69
69
  ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
70
+ table.column :title, :string
70
71
  table.column :other, :string
71
72
  table.column :avatar_file_name, :string
72
73
  table.column :avatar_content_type, :string
@@ -85,6 +86,7 @@ def rebuild_class options = {}
85
86
  include Paperclip::Glue
86
87
  has_attached_file :avatar, options
87
88
  end
89
+ Dummy.reset_column_information
88
90
  end
89
91
 
90
92
  class FakeModel
@@ -34,20 +34,20 @@ class IntegrationTest < Test::Unit::TestCase
34
34
  should "create its thumbnails properly" do
35
35
  assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
36
36
  end
37
-
37
+
38
38
  context 'reprocessing with unreadable original' do
39
39
  setup { File.chmod(0000, @dummy.avatar.path) }
40
-
40
+
41
41
  should "not raise an error" do
42
42
  assert_nothing_raised do
43
43
  @dummy.avatar.reprocess!
44
44
  end
45
45
  end
46
-
46
+
47
47
  should "return false" do
48
48
  assert ! @dummy.avatar.reprocess!
49
49
  end
50
-
50
+
51
51
  teardown { File.chmod(0644, @dummy.avatar.path) }
52
52
  end
53
53
 
@@ -399,6 +399,7 @@ class IntegrationTest < Test::Unit::TestCase
399
399
  @dummy.save
400
400
  assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
401
401
  `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
402
+ assert_equal @dummy.avatar_file_name, @dummy2.avatar_file_name
402
403
  end
403
404
  end
404
405
 
@@ -466,6 +467,18 @@ class IntegrationTest < Test::Unit::TestCase
466
467
  @files_on_s3 = s3_files_for @dummy.avatar
467
468
  end
468
469
 
470
+ context 'assigning itself to a new model' do
471
+ setup do
472
+ @d2 = Dummy.new
473
+ @d2.avatar = @dummy.avatar
474
+ @d2.save
475
+ end
476
+
477
+ should "have the same name as the old file" do
478
+ assert_equal @d2.avatar.original_filename, @dummy.avatar.original_filename
479
+ end
480
+ end
481
+
469
482
  should "have the same contents as the original" do
470
483
  @file.rewind
471
484
  assert_equal @file.read, @files_on_s3[:original].read
@@ -50,6 +50,13 @@ class InterpolationsTest < Test::Unit::TestCase
50
50
  assert_equal "png", Paperclip::Interpolations.extension(attachment, :style)
51
51
  end
52
52
 
53
+ should "return the #to_param of the attachment" do
54
+ attachment = mock
55
+ attachment.expects(:to_param).returns("23-awesome")
56
+ attachment.expects(:instance).returns(attachment)
57
+ assert_equal "23-awesome", Paperclip::Interpolations.param(attachment, :style)
58
+ end
59
+
53
60
  should "return the id of the attachment" do
54
61
  attachment = mock
55
62
  attachment.expects(:id).returns(23)
@@ -110,6 +117,13 @@ class InterpolationsTest < Test::Unit::TestCase
110
117
  assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style)
111
118
  end
112
119
 
120
+ should "return the filename as basename when extension is blank" do
121
+ attachment = mock
122
+ attachment.stubs(:styles).returns({})
123
+ attachment.stubs(:original_filename).returns("one")
124
+ assert_equal "one", Paperclip::Interpolations.filename(attachment, :style)
125
+ end
126
+
113
127
  should "return the timestamp" do
114
128
  now = Time.now
115
129
  zone = 'UTC'
@@ -34,13 +34,13 @@ class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase
34
34
 
35
35
  should_accept_dummy_class
36
36
  end
37
-
37
+
38
38
  context "given a class with other validations but matching types" do
39
39
  setup do
40
40
  @dummy_class.validates_presence_of :title
41
41
  @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*}
42
42
  end
43
-
43
+
44
44
  should_accept_dummy_class
45
45
  end
46
46
  end
@@ -2,44 +2,9 @@ require './test/helper'
2
2
 
3
3
  class PaperclipTest < Test::Unit::TestCase
4
4
  context "Calling Paperclip.run" do
5
- setup do
6
- Paperclip.options[:image_magick_path] = nil
7
- Paperclip.options[:command_path] = nil
8
- Paperclip::CommandLine.stubs(:'`')
9
- end
10
-
11
- should "execute the right command with :image_magick_path" do
12
- Paperclip.options[:image_magick_path] = "/usr/bin"
13
- Paperclip.expects(:log).with(includes('[DEPRECATION]'))
14
- Paperclip.expects(:log).with(regexp_matches(%r{/usr/bin/convert ['"]one.jpg['"] ['"]two.jpg['"]}))
15
- Paperclip::CommandLine.expects(:"`").with(regexp_matches(%r{/usr/bin/convert ['"]one.jpg['"] ['"]two.jpg['"]}))
16
- Paperclip.run("convert", ":one :two", :one => "one.jpg", :two => "two.jpg")
17
- end
18
-
19
- should "execute the right command with :command_path" do
20
- Paperclip.options[:command_path] = "/usr/bin"
21
- Paperclip::CommandLine.expects(:"`").with(regexp_matches(%r{/usr/bin/convert ['"]one.jpg['"] ['"]two.jpg['"]}))
22
- Paperclip.run("convert", ":one :two", :one => "one.jpg", :two => "two.jpg")
23
- end
24
-
25
- should "execute the right command with no path" do
26
- Paperclip::CommandLine.expects(:"`").with(regexp_matches(%r{convert ['"]one.jpg['"] ['"]two.jpg['"]}))
27
- Paperclip.run("convert", ":one :two", :one => "one.jpg", :two => "two.jpg")
28
- end
29
-
30
- should "tell you the command isn't there if the shell returns 127" do
31
- with_exitstatus_returning(127) do
32
- assert_raises(Paperclip::CommandNotFoundError) do
33
- Paperclip.run("command")
34
- end
35
- end
36
- end
37
-
38
- should "tell you the command isn't there if an ENOENT is raised" do
39
- assert_raises(Paperclip::CommandNotFoundError) do
40
- Paperclip::CommandLine.stubs(:"`").raises(Errno::ENOENT)
41
- Paperclip.run("command")
42
- end
5
+ should "run the command with Cocaine" do
6
+ Cocaine::CommandLine.expects(:new).with("convert", "stuff").returns(stub(:run))
7
+ Paperclip.run("convert", "stuff")
43
8
  end
44
9
  end
45
10
 
@@ -72,6 +37,19 @@ class PaperclipTest < Test::Unit::TestCase
72
37
  assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail)
73
38
  end
74
39
 
40
+ should "get a class from a namespaced class name" do
41
+ class ::One; class Two; end; end
42
+ assert_equal ::One::Two, Paperclip.class_for("One::Two")
43
+ end
44
+
45
+ should "raise when class doesn't exist in specified namespace" do
46
+ class ::Three; end
47
+ class ::Four; end
48
+ assert_raise NameError do
49
+ Paperclip.class_for("Three::Four")
50
+ end
51
+ end
52
+
75
53
  context "An ActiveRecord model with an 'avatar' attachment" do
76
54
  setup do
77
55
  rebuild_model :path => "tmp/:class/omg/:style.:extension"
@@ -223,7 +201,7 @@ class PaperclipTest < Test::Unit::TestCase
223
201
  @dummy.valid?
224
202
  end
225
203
  should "not have an error when assigned a valid file" do
226
- assert_equal 0, @dummy.errors.length, @dummy.errors.full_messages.join(", ")
204
+ assert_equal 0, @dummy.errors.size, @dummy.errors.full_messages.join(", ")
227
205
  end
228
206
  end
229
207
  context "and assigned an invalid file" do
@@ -232,7 +210,7 @@ class PaperclipTest < Test::Unit::TestCase
232
210
  @dummy.valid?
233
211
  end
234
212
  should "have an error when assigned a valid file" do
235
- assert @dummy.errors.length > 0
213
+ assert @dummy.errors.size > 0
236
214
  end
237
215
  end
238
216
  end
@@ -7,7 +7,7 @@ class StorageTest < Test::Unit::TestCase
7
7
  Object.const_set(:Rails, stub('Rails', :env => env))
8
8
  end
9
9
  end
10
-
10
+
11
11
  context "filesystem" do
12
12
  setup do
13
13
  rebuild_model :styles => { :thumbnail => "25x25#" }
@@ -15,16 +15,16 @@ class StorageTest < Test::Unit::TestCase
15
15
 
16
16
  @dummy.avatar = File.open(File.join(File.dirname(__FILE__), "fixtures", "5k.png"))
17
17
  end
18
-
18
+
19
19
  should "allow file assignment" do
20
20
  assert @dummy.save
21
21
  end
22
-
22
+
23
23
  should "store the original" do
24
24
  @dummy.save
25
25
  assert File.exists?(@dummy.avatar.path)
26
26
  end
27
-
27
+
28
28
  should "store the thumbnail" do
29
29
  @dummy.save
30
30
  assert File.exists?(@dummy.avatar.path(:thumbnail))
@@ -78,6 +78,32 @@ class StorageTest < Test::Unit::TestCase
78
78
  assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url
79
79
  end
80
80
  end
81
+
82
+ context "An attachment that uses S3 for storage and has styles that return different file types" do
83
+ setup do
84
+ AWS::S3::Base.stubs(:establish_connection!)
85
+ rebuild_model :styles => { :large => ['500x500#', :jpg] },
86
+ :storage => :s3,
87
+ :bucket => "bucket",
88
+ :path => ":attachment/:basename.:extension",
89
+ :s3_credentials => {
90
+ 'access_key_id' => "12345",
91
+ 'secret_access_key' => "54321"
92
+ }
93
+
94
+ @dummy = Dummy.new
95
+ @dummy.avatar = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
96
+ end
97
+
98
+ should "return a url containing the correct original file mime type" do
99
+ assert_match /.+\/5k.png/, @dummy.avatar.url
100
+ end
101
+
102
+ should "return a url containing the correct processed file mime type" do
103
+ assert_match /.+\/5k.jpg/, @dummy.avatar.url(:large)
104
+ end
105
+ end
106
+
81
107
  context "" do
82
108
  setup do
83
109
  AWS::S3::Base.stubs(:establish_connection!)
@@ -94,6 +120,7 @@ class StorageTest < Test::Unit::TestCase
94
120
  assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url
95
121
  end
96
122
  end
123
+
97
124
  context "" do
98
125
  setup do
99
126
  AWS::S3::Base.stubs(:establish_connection!)
@@ -114,6 +141,45 @@ class StorageTest < Test::Unit::TestCase
114
141
  end
115
142
  end
116
143
 
144
+ context "generating a url with a proc as the host alias" do
145
+ setup do
146
+ AWS::S3::Base.stubs(:establish_connection!)
147
+ rebuild_model :storage => :s3,
148
+ :s3_credentials => { :bucket => "prod_bucket" },
149
+ :s3_host_alias => Proc.new { |image| "cdn#{image.size.to_i % 4}.example.com" },
150
+ :path => ":attachment/:basename.:extension",
151
+ :url => ":s3_alias_url"
152
+ @dummy = Dummy.new
153
+ @dummy.avatar = StringIO.new(".")
154
+ end
155
+
156
+ should "return a url based on the host_alias" do
157
+ assert_match %r{^http://cdn0.example.com/avatars/stringio.txt}, @dummy.avatar.url
158
+ end
159
+
160
+ should "still return the bucket name" do
161
+ assert_equal "prod_bucket", @dummy.avatar.bucket_name
162
+ end
163
+
164
+ end
165
+
166
+ context "" do
167
+ setup do
168
+ AWS::S3::Base.stubs(:establish_connection!)
169
+ rebuild_model :storage => :s3,
170
+ :s3_credentials => {},
171
+ :bucket => "bucket",
172
+ :path => ":attachment/:basename.:extension",
173
+ :url => ":asset_host"
174
+ @dummy = Dummy.new
175
+ @dummy.avatar = StringIO.new(".")
176
+ end
177
+
178
+ should "return a relative URL for Rails to calculate assets host" do
179
+ assert_match %r{^avatars/stringio.txt}, @dummy.avatar.url
180
+ end
181
+ end
182
+
117
183
  context "Generating a secure url with an expiration" do
118
184
  setup do
119
185
  AWS::S3::Base.stubs(:establish_connection!)
@@ -360,7 +426,7 @@ class StorageTest < Test::Unit::TestCase
360
426
  @dummy = Dummy.new
361
427
  end
362
428
 
363
- should "run it the file through ERB" do
429
+ should "run the file through ERB" do
364
430
  assert_equal 'env_bucket', @dummy.avatar.bucket_name
365
431
  assert_equal 'env_key', AWS::S3::Base.connection.options[:access_key_id]
366
432
  assert_equal 'env_secret', AWS::S3::Base.connection.options[:secret_access_key]