dm-paperclip 2.1.4 → 2.3.0

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.
@@ -1,40 +1,35 @@
1
1
  module Paperclip
2
2
  # Handles thumbnailing images that are uploaded.
3
- class Thumbnail
3
+ class Thumbnail < Processor
4
4
 
5
- attr_accessor :file, :current_geometry, :target_geometry, :format, :whiny_thumbnails, :convert_options
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
- # +whiny_thumbnails+ is true (which it is, by default. If +convert_options+ is
12
- # set, the options will be appended to the convert command upon image conversion
13
- def initialize file, target_geometry, format = nil, convert_options = nil, whiny_thumbnails = true
11
+ # +whiny+ is true (which it is, by default. If +convert_options+ is
12
+ # set, the options will be appended to the convert command upon image conversion
13
+ def initialize file, options = {}, attachment = nil
14
+ super
15
+ geometry = options[:geometry]
14
16
  @file = file
15
- @crop = target_geometry[-1,1] == '#'
16
- @target_geometry = Geometry.parse target_geometry
17
- @current_geometry = Geometry.from_file file
18
- @convert_options = convert_options
19
- @whiny_thumbnails = whiny_thumbnails
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.
34
29
  def crop?
35
30
  @crop
36
31
  end
37
-
32
+
38
33
  # Returns true if the image is meant to make use of additional convert options.
39
34
  def convert_options?
40
35
  not @convert_options.blank?
@@ -48,15 +43,15 @@ module Paperclip
48
43
  dst.binmode
49
44
 
50
45
  command = <<-end_command
51
- #{ Paperclip.path_for_command('convert') }
52
46
  "#{ File.expand_path(src.path) }[0]"
53
47
  #{ transformation_command }
54
48
  "#{ File.expand_path(dst.path) }"
55
49
  end_command
56
- success = system(command.gsub(/\s+/, " "))
57
50
 
58
- if !success && $?.exitstatus != 0 && @whiny_thumbnails
59
- raise PaperclipError, "There was an error processing this thumbnail"
51
+ begin
52
+ success = Paperclip.run("convert", command.gsub(/\s+/, " "))
53
+ rescue PaperclipCommandLineError
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
@@ -28,9 +28,20 @@ module Paperclip
28
28
  File.size(self)
29
29
  end
30
30
  end
31
+ end
31
32
 
33
+ if defined? StringIO
34
+ class StringIO
35
+ attr_accessor :original_filename, :content_type
36
+ def original_filename
37
+ @original_filename ||= "stringio.txt"
38
+ end
39
+ def content_type
40
+ @content_type ||= "text/plain"
41
+ end
42
+ end
32
43
  end
33
44
 
34
45
  class File #:nodoc:
35
46
  include Paperclip::Upfile
36
- end
47
+ end
@@ -1,6 +1,41 @@
1
1
  module Paperclip
2
2
  module Validate
3
3
 
4
+ module ClassMethods
5
+
6
+ # Places ActiveRecord-style validations on the size of the file assigned. The
7
+ # possible options are:
8
+ # * +in+: a Range of bytes (i.e. +1..1.megabyte+),
9
+ # * +less_than+: equivalent to :in => 0..options[:less_than]
10
+ # * +greater_than+: equivalent to :in => options[:greater_than]..Infinity
11
+ # * +message+: error message to display, use :min and :max as replacements
12
+ def validates_attachment_size(*fields)
13
+ opts = opts_from_validator_args(fields)
14
+ add_validator_to_context(opts, fields, Paperclip::Validate::SizeValidator)
15
+ end
16
+
17
+ # Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true.
18
+ def validates_attachment_thumbnails name, options = {}
19
+ self.attachment_definitions[name][:whiny_thumbnails] = true
20
+ end
21
+
22
+ # Places ActiveRecord-style validations on the presence of a file.
23
+ def validates_attachment_presence(*fields)
24
+ opts = opts_from_validator_args(fields)
25
+ add_validator_to_context(opts, fields, Paperclip::Validate::RequiredFieldValidator)
26
+ end
27
+
28
+ # Places ActiveRecord-style validations on the content type of the file assigned. The
29
+ # possible options are:
30
+ # * +content_type+: Allowed content types. Can be a single content type or an array. Allows all by default.
31
+ # * +message+: The message to display when the uploaded file has an invalid content type.
32
+ def validates_attachment_content_type(*fields)
33
+ opts = opts_from_validator_args(fields)
34
+ add_validator_to_context(opts, fields, Paperclip::Validate::ContentTypeValidator)
35
+ end
36
+
37
+ end
38
+
4
39
  class SizeValidator < DataMapper::Validate::GenericValidator #:nodoc:
5
40
  def initialize(field_name, options={})
6
41
  super
@@ -138,11 +138,9 @@ class AttachmentTest < Test::Unit::TestCase
138
138
  end
139
139
  end
140
140
 
141
- [:thumb, :large].each do |style|
142
- should "call extra_options_for(#{style})" do
143
- @dummy.avatar.expects(:extra_options_for).with(style)
144
- @dummy.avatar = @file
145
- end
141
+ should "call post_process" do
142
+ @dummy.avatar.expects(:post_process).once
143
+ @dummy.avatar = @file
146
144
  end
147
145
  end
148
146
  end
@@ -150,20 +148,20 @@ class AttachmentTest < Test::Unit::TestCase
150
148
  context "Assigning an attachment" do
151
149
  setup do
152
150
  rebuild_model
153
-
151
+
154
152
  @not_file = mock
155
153
  @not_file.stubs(:nil?).returns(false)
156
154
  @not_file.expects(:to_tempfile).returns(self)
157
155
  @not_file.expects(:original_filename).returns("filename.png\r\n")
158
156
  @not_file.expects(:content_type).returns("image/png\r\n")
159
157
  @not_file.expects(:size).returns(10)
160
-
158
+
161
159
  @dummy = Dummy.new
162
160
  @attachment = @dummy.avatar
163
161
  @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
164
162
  @attachment.expects(:queue_existing_for_delete)
165
163
  @attachment.expects(:post_process)
166
- @attachment.expects(:validate)
164
+ @attachment.expects(:validate).twice
167
165
  @dummy.avatar = @not_file
168
166
  end
169
167
 
@@ -174,33 +172,31 @@ class AttachmentTest < Test::Unit::TestCase
174
172
  should "strip whitespace from content_type field" do
175
173
  assert_equal "image/png", @dummy.avatar.instance.avatar_content_type
176
174
  end
177
-
178
175
  end
179
176
 
180
177
  context "Attachment with strange letters" do
181
178
  setup do
182
179
  rebuild_model
183
-
180
+
184
181
  @not_file = mock
185
182
  @not_file.stubs(:nil?).returns(false)
186
183
  @not_file.expects(:to_tempfile).returns(self)
187
- @not_file.expects(:original_filename).returns("sheep_say_b�.png\r\n")
184
+ @not_file.expects(:original_filename).returns("sheep_say_b_.png\r\n")
188
185
  @not_file.expects(:content_type).returns("image/png\r\n")
189
186
  @not_file.expects(:size).returns(10)
190
-
187
+
191
188
  @dummy = Dummy.new
192
189
  @attachment = @dummy.avatar
193
190
  @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
194
191
  @attachment.expects(:queue_existing_for_delete)
195
192
  @attachment.expects(:post_process)
196
- @attachment.expects(:validate)
193
+ @attachment.expects(:validate).twice
197
194
  @dummy.avatar = @not_file
198
195
  end
199
-
196
+
200
197
  should "remove strange letters and replace with underscore (_)" do
201
198
  assert_equal "sheep_say_b_.png", @dummy.avatar.original_filename
202
199
  end
203
-
204
200
  end
205
201
 
206
202
  context "An attachment" do
@@ -230,25 +226,24 @@ class AttachmentTest < Test::Unit::TestCase
230
226
  assert_equal "/avatars/original/missing.png", @attachment.url
231
227
  assert_equal "/avatars/blah/missing.png", @attachment.url(:blah)
232
228
  end
233
-
229
+
234
230
  context "with a file assigned in the database" do
235
231
  setup do
236
- @instance.stubs(:attribute_get).with(:avatar_file_name).returns('5k.png')
237
- @instance.stubs(:attribute_get).with(:avatar_content_type).returns("image/png")
238
- @instance.stubs(:attribute_get).with(:avatar_file_size).returns(12345)
239
- now = Time.now
240
- Time.stubs(:now).returns(now)
241
- @instance.stubs(:attribute_get).with(:avatar_updated_at).returns(Time.now)
232
+ @instance.stubs(:avatar_file_name).returns('5k.png')
233
+ @instance.stubs(:avatar_content_type).returns("image/png")
234
+ @instance.stubs(:avatar_file_size).returns(12345)
235
+ @now = Time.now
236
+ Time.stubs(:now).returns(@now)
237
+ @instance.stubs(:avatar_updated_at).returns(Time.now)
242
238
  end
243
239
 
244
240
  should "return a correct url even if the file does not exist" do
245
241
  assert_nil @attachment.to_file
246
- assert_match %r{^/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
242
+ assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah)
247
243
  end
248
244
 
249
245
  should "make sure the updated_at mtime is in the url if it is defined" do
250
- time = Time.now
251
- assert_match %r{#{time.year}#{time.month}#{time.day}#{time.hour}#{time.min}#{time.sec}$}, @attachment.url(:blah)
246
+ assert_match %r{#{@now.to_i.to_s}$}, @attachment.url(:blah)
252
247
  end
253
248
 
254
249
  context "with the updated_at field removed" do
@@ -266,7 +261,7 @@ class AttachmentTest < Test::Unit::TestCase
266
261
  end
267
262
 
268
263
  should "return the proper path when filename has multiple .'s" do
269
- @instance.stubs(:attribute_get).with(:avatar_file_name).returns("5k.old.png")
264
+ @instance.stubs(:avatar_file_name).returns("5k.old.png")
270
265
  assert_equal "./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png", @attachment.path
271
266
  end
272
267
 
@@ -298,8 +293,8 @@ class AttachmentTest < Test::Unit::TestCase
298
293
 
299
294
  should "return the real url" do
300
295
  assert @attachment.to_file
301
- assert_match %r{^/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
302
- assert_match %r{^/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
296
+ assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url
297
+ assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small)
303
298
  end
304
299
 
305
300
  should "commit the files to disk" do
@@ -333,15 +328,12 @@ class AttachmentTest < Test::Unit::TestCase
333
328
  @existing_names = @attachment.styles.keys.collect do |style|
334
329
  @attachment.path(style)
335
330
  end
336
- @instance.expects(:attributes=).with({ :avatar_file_name => nil,
337
- :avatar_content_type => nil,
338
- :avatar_file_size => nil })
339
331
  @attachment.assign nil
340
332
  @attachment.save
341
333
  end
342
334
 
343
335
  should "delete the files" do
344
- @existing_names.each{|f| assert ! File.exists?(f) }
336
+ @existing_names.each { |f| assert !File.exists?(f) }
345
337
  end
346
338
  end
347
339
  end
@@ -62,7 +62,7 @@ class GeometryTest < Test::Unit::TestCase
62
62
  should "make sure the modifier gets passed during transformation_to" do
63
63
  assert @src = Paperclip::Geometry.parse("123x456")
64
64
  assert @dst = Paperclip::Geometry.parse("123x456>")
65
- assert_equal "123x456>", @src.transformation_to(@dst).to_s
65
+ assert_equal "123x456>", @src.transformation_to(@dst).join
66
66
  end
67
67
 
68
68
  should "be generated from a file" do
@@ -42,6 +42,12 @@ unless defined?(Mash)
42
42
  end
43
43
  end
44
44
 
45
+ Paperclip.configure do |config|
46
+ config.root = Merb.root # the application root to anchor relative urls (defaults to Dir.pwd)
47
+ config.env = Merb.env # server env support, defaults to ENV['RACK_ENV'] or 'development'
48
+ config.use_dm_validations = true # validate attachment sizes and such, defaults to false
49
+ end
50
+
45
51
  def rebuild_model options = {}
46
52
  Object.send(:remove_const, "Dummy") rescue nil
47
53
  Object.const_set("Dummy", Class.new())
@@ -24,21 +24,21 @@ class StorageTest < Test::Unit::TestCase
24
24
 
25
25
  should "get the correct credentials when RAILS_ENV is production" do
26
26
  ENV['RAILS_ENV'] = 'production'
27
- assert_equal({:key => "12345"},
27
+ assert_equal({'key' => "12345"},
28
28
  @avatar.parse_credentials('production' => {:key => '12345'},
29
29
  :development => {:key => "54321"}))
30
30
  end
31
31
 
32
32
  should "get the correct credentials when RAILS_ENV is development" do
33
33
  ENV['RAILS_ENV'] = 'development'
34
- assert_equal({:key => "54321"},
34
+ assert_equal({'key' => "54321"},
35
35
  @avatar.parse_credentials('production' => {:key => '12345'},
36
36
  :development => {:key => "54321"}))
37
37
  end
38
38
 
39
39
  should "return the argument if the key does not exist" do
40
40
  ENV['RAILS_ENV'] = "not really an env"
41
- assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345"))
41
+ assert_equal({'test' => "12345"}, @avatar.parse_credentials(:test => "12345"))
42
42
  end
43
43
  end
44
44
 
@@ -48,11 +48,11 @@ class ThumbnailTest < Test::Unit::TestCase
48
48
  ].each do |args|
49
49
  context "being thumbnailed with a geometry of #{args[0]}" do
50
50
  setup do
51
- @thumb = Paperclip::Thumbnail.new(@file, args[0])
51
+ @thumb = Paperclip::Thumbnail.new(@file, :geometry => args[0])
52
52
  end
53
53
 
54
54
  should "start with dimensions of 434x66" do
55
- cmd = %Q[identify -format "%wx%h" #{@file.path}]
55
+ cmd = %Q[identify -format "%wx%h" #{@file.path}]
56
56
  assert_equal "434x66", `#{cmd}`.chomp
57
57
  end
58
58
 
@@ -66,7 +66,7 @@ class ThumbnailTest < Test::Unit::TestCase
66
66
  end
67
67
 
68
68
  should "be the size we expect it to be" do
69
- cmd = %Q[identify -format "%wx%h" #{@thumb_result.path}]
69
+ cmd = %Q[identify -format "%wx%h" #{@thumb_result.path}]
70
70
  assert_equal args[1], `#{cmd}`.chomp
71
71
  end
72
72
  end
@@ -75,7 +75,7 @@ class ThumbnailTest < Test::Unit::TestCase
75
75
 
76
76
  context "being thumbnailed at 100x50 with cropping" do
77
77
  setup do
78
- @thumb = Paperclip::Thumbnail.new(@file, "100x50#")
78
+ @thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x50#")
79
79
  end
80
80
 
81
81
  should "report its correct current and target geometries" do
@@ -88,16 +88,17 @@ class ThumbnailTest < Test::Unit::TestCase
88
88
  end
89
89
 
90
90
  should "have whiny_thumbnails turned on by default" do
91
- assert @thumb.whiny_thumbnails
91
+ assert @thumb.whiny
92
92
  end
93
-
93
+
94
94
  should "have convert_options set to nil by default" do
95
95
  assert_equal nil, @thumb.convert_options
96
96
  end
97
97
 
98
98
  should "send the right command to convert when sent #make" do
99
- @thumb.expects(:system).with do |arg|
100
- arg.match %r{convert\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+\"x50\"\s+-crop\s+\"100x50\+114\+0\"\s+\+repage\s+".*?"}
99
+ Paperclip.expects(:run).with do |cmd, arg|
100
+ cmd.match 'convert'
101
+ arg.match %r{"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+\"x50\"\s+-crop\s+\"100x50\+114\+0\"\s+\+repage\s+".*?"}
101
102
  end
102
103
  @thumb.make
103
104
  end
@@ -107,10 +108,10 @@ class ThumbnailTest < Test::Unit::TestCase
107
108
  assert_match /100x50/, `identify #{dst.path}`
108
109
  end
109
110
  end
110
-
111
+
111
112
  context "being thumbnailed with convert options set" do
112
113
  setup do
113
- @thumb = Paperclip::Thumbnail.new(@file, "100x50#", format=nil, convert_options="-strip -depth 8", whiny_thumbnails=true)
114
+ @thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x50#", :format => (format = nil), :convert_options => (convert_options="-strip -depth 8"), :whiny => (whiny_thumbnails=true))
114
115
  end
115
116
 
116
117
  should "have convert_options value set" do
@@ -118,8 +119,9 @@ class ThumbnailTest < Test::Unit::TestCase
118
119
  end
119
120
 
120
121
  should "send the right command to convert when sent #make" do
121
- @thumb.expects(:system).with do |arg|
122
- arg.match %r{convert\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+"x50"\s+-crop\s+"100x50\+114\+0"\s+\+repage\s+-strip\s+-depth\s+8\s+".*?"}
122
+ Paperclip.expects(:run).with do |cmd, arg|
123
+ cmd.match 'convert'
124
+ arg.match %r{"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+"x50"\s+-crop\s+"100x50\+114\+0"\s+\+repage\s+-strip\s+-depth\s+8\s+".*?"}
123
125
  end
124
126
  @thumb.make
125
127
  end
@@ -128,10 +130,10 @@ class ThumbnailTest < Test::Unit::TestCase
128
130
  dst = @thumb.make
129
131
  assert_match /100x50/, `identify #{dst.path}`
130
132
  end
131
-
133
+
132
134
  context "redefined to have bad convert_options setting" do
133
135
  setup do
134
- @thumb = Paperclip::Thumbnail.new(@file, "100x50#", format=nil, convert_options="-this-aint-no-option", whiny_thumbnails=true)
136
+ @thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x50#", :format => nil, :convert_options => "-this-aint-no-option", :whiny => true)
135
137
  end
136
138
 
137
139
  should "error when trying to create the thumbnail" do
@@ -139,7 +141,7 @@ class ThumbnailTest < Test::Unit::TestCase
139
141
  @thumb.make
140
142
  end
141
143
  end
142
- end
144
+ end
143
145
  end
144
146
  end
145
147
  end