paperclip-cloudfiles 2.3.2 → 2.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README.rdoc +10 -3
  2. data/Rakefile +8 -4
  3. data/generators/paperclip/USAGE +2 -2
  4. data/generators/paperclip/paperclip_generator.rb +8 -8
  5. data/lib/generators/paperclip/USAGE +8 -0
  6. data/lib/generators/paperclip/paperclip_generator.rb +31 -0
  7. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  8. data/lib/paperclip/attachment.rb +38 -18
  9. data/lib/paperclip/command_line.rb +80 -0
  10. data/lib/paperclip/geometry.rb +7 -7
  11. data/lib/paperclip/interpolations.rb +8 -2
  12. data/lib/paperclip/iostream.rb +11 -25
  13. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +3 -3
  14. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +0 -1
  15. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +0 -1
  16. data/lib/paperclip/processor.rb +15 -6
  17. data/lib/paperclip/railtie.rb +24 -0
  18. data/lib/paperclip/storage/cloud_files.rb +131 -0
  19. data/lib/paperclip/storage/filesystem.rb +73 -0
  20. data/lib/paperclip/storage/s3.rb +192 -0
  21. data/lib/paperclip/storage.rb +3 -371
  22. data/lib/paperclip/style.rb +11 -11
  23. data/lib/paperclip/thumbnail.rb +16 -15
  24. data/lib/paperclip/upfile.rb +5 -3
  25. data/lib/paperclip/version.rb +3 -0
  26. data/lib/paperclip.rb +78 -92
  27. data/lib/tasks/paperclip.rake +72 -0
  28. data/rails/init.rb +2 -0
  29. data/shoulda_macros/paperclip.rb +1 -2
  30. data/test/attachment_test.rb +74 -28
  31. data/test/command_line_test.rb +133 -0
  32. data/test/geometry_test.rb +2 -2
  33. data/test/helper.rb +22 -24
  34. data/test/integration_test.rb +10 -11
  35. data/test/interpolations_test.rb +7 -4
  36. data/test/iostream_test.rb +6 -13
  37. data/test/matchers/have_attached_file_matcher_test.rb +1 -1
  38. data/test/matchers/validate_attachment_content_type_matcher_test.rb +11 -1
  39. data/test/matchers/validate_attachment_presence_matcher_test.rb +1 -1
  40. data/test/matchers/validate_attachment_size_matcher_test.rb +1 -1
  41. data/test/paperclip_test.rb +54 -80
  42. data/test/processor_test.rb +1 -1
  43. data/test/storage_test.rb +32 -12
  44. data/test/style_test.rb +17 -17
  45. data/test/thumbnail_test.rb +18 -18
  46. data/test/upfile_test.rb +1 -1
  47. metadata +58 -31
  48. data/tasks/paperclip_tasks.rake +0 -79
data/lib/paperclip.rb CHANGED
@@ -26,17 +26,21 @@
26
26
  # See the +has_attached_file+ documentation for more details.
27
27
 
28
28
  require 'erb'
29
+ require 'digest'
29
30
  require 'tempfile'
31
+ require 'paperclip/version'
30
32
  require 'paperclip/upfile'
31
33
  require 'paperclip/iostream'
32
34
  require 'paperclip/geometry'
33
35
  require 'paperclip/processor'
34
36
  require 'paperclip/thumbnail'
35
- require 'paperclip/storage'
36
37
  require 'paperclip/interpolations'
37
38
  require 'paperclip/style'
38
39
  require 'paperclip/attachment'
40
+ require 'paperclip/storage'
39
41
  require 'paperclip/callback_compatability'
42
+ require 'paperclip/command_line'
43
+ require 'paperclip/railtie'
40
44
  if defined?(Rails.root) && Rails.root
41
45
  Dir.glob(File.join(File.expand_path(Rails.root), "lib", "paperclip_processors", "*.rb")).each do |processor|
42
46
  require processor
@@ -47,16 +51,14 @@ end
47
51
  # documentation for Paperclip::ClassMethods for more useful information.
48
52
  module Paperclip
49
53
 
50
- VERSION = "2.3.2"
51
-
52
54
  class << self
53
55
  # Provides configurability to Paperclip. There are a number of options available, such as:
54
- # * whiny: Will raise an error if Paperclip cannot process thumbnails of
56
+ # * whiny: Will raise an error if Paperclip cannot process thumbnails of
55
57
  # an uploaded image. Defaults to true.
56
58
  # * log: Logs progress to the Rails log. Uses ActiveRecord's logger, so honors
57
59
  # log levels, etc. Defaults to true.
58
60
  # * command_path: Defines the path at which to find the command line
59
- # programs if they are not visible to Rails the system's search path. Defaults to
61
+ # programs if they are not visible to Rails the system's search path. Defaults to
60
62
  # nil, which uses the first executable found in the user's search path.
61
63
  # * image_magick_path: Deprecated alias of command_path.
62
64
  def options
@@ -70,12 +72,8 @@ module Paperclip
70
72
  }
71
73
  end
72
74
 
73
- def path_for_command command #:nodoc:
74
- if options[:image_magick_path]
75
- warn("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead")
76
- end
77
- path = [options[:command_path] || options[:image_magick_path], command].compact
78
- File.join(*path)
75
+ def configure
76
+ yield(self) if block_given?
79
77
  end
80
78
 
81
79
  def interpolates key, &block
@@ -95,57 +93,32 @@ module Paperclip
95
93
  #
96
94
  # Paperclip.run("echo", "something", :expected_outcodes => [0,1,2,3])
97
95
  #
98
- # This method can log the command being run when
96
+ # This method can log the command being run when
99
97
  # Paperclip.options[:log_command] is set to true (defaults to false). This
100
98
  # will only log if logging in general is set to true as well.
101
99
  def run cmd, *params
102
- options = params.last.is_a?(Hash) ? params.pop : {}
103
- expected_outcodes = options[:expected_outcodes] || [0]
104
- params = quote_command_options(*params).join(" ")
105
-
106
- command = %Q[#{path_for_command(cmd)} #{params}]
107
- command = "#{command} 2>#{bit_bucket}" if Paperclip.options[:swallow_stderr]
108
- Paperclip.log(command) if Paperclip.options[:log_command]
109
-
110
- output = `#{command}`
111
- unless expected_outcodes.include?($?.exitstatus)
112
- raise PaperclipCommandLineError,
113
- "Error while running #{cmd}. Expected return code to be #{expected_outcodes.join(", ")} but was #{$?.exitstatus}",
114
- output
115
- end
116
- output
117
- end
118
-
119
- def quote_command_options(*options)
120
- options.map do |option|
121
- option.split("'").map{|m| "'#{m}'" }.join("\\'")
122
- end
123
- end
124
-
125
- def bit_bucket #:nodoc:
126
- File.exists?("/dev/null") ? "/dev/null" : "NUL"
127
- end
128
-
129
- def included base #:nodoc:
130
- base.extend ClassMethods
131
- if base.respond_to?("set_callback")
132
- base.send :include, Paperclip::CallbackCompatability::Rails3
133
- elsif !base.respond_to?("define_callbacks")
134
- base.send :include, Paperclip::CallbackCompatability::Rails20
135
- else
136
- base.send :include, Paperclip::CallbackCompatability::Rails21
100
+ if options[:image_magick_path]
101
+ Paperclip.log("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead")
137
102
  end
103
+ CommandLine.path = options[:command_path] || options[:image_magick_path]
104
+ CommandLine.new(cmd, *params).run
138
105
  end
139
106
 
140
107
  def processor name #:nodoc:
141
108
  name = name.to_s.camelize
142
109
  processor = Paperclip.const_get(name)
143
110
  unless processor.ancestors.include?(Paperclip::Processor)
144
- raise PaperclipError.new("Processor #{name} was not found")
111
+ raise PaperclipError.new("Processor #{name} was not found")
145
112
  end
146
113
  processor
147
114
  end
148
115
 
116
+ def each_instance_with_attachment(klass, name)
117
+ Object.const_get(klass).all.each do |instance|
118
+ yield(instance) if instance.send(:"#{name}?")
119
+ end
120
+ end
121
+
149
122
  # Log a paperclip-specific line. Uses ActiveRecord::Base.logger
150
123
  # by default. Set Paperclip.options[:log] to false to turn off.
151
124
  def log message
@@ -164,7 +137,7 @@ module Paperclip
164
137
  class PaperclipError < StandardError #:nodoc:
165
138
  end
166
139
 
167
- class PaperclipCommandLineError < StandardError #:nodoc:
140
+ class PaperclipCommandLineError < PaperclipError #:nodoc:
168
141
  attr_accessor :output
169
142
  def initialize(msg = nil, output = nil)
170
143
  super(msg)
@@ -172,49 +145,66 @@ module Paperclip
172
145
  end
173
146
  end
174
147
 
148
+ class StorageMethodNotFound < PaperclipError
149
+ end
150
+
151
+ class CommandNotFoundError < PaperclipError
152
+ end
153
+
175
154
  class NotIdentifiedByImageMagickError < PaperclipError #:nodoc:
176
155
  end
177
-
156
+
178
157
  class InfiniteInterpolationError < PaperclipError #:nodoc:
179
158
  end
180
159
 
160
+ module Glue
161
+ def self.included base #:nodoc:
162
+ base.extend ClassMethods
163
+ if base.respond_to?("set_callback")
164
+ base.send :include, Paperclip::CallbackCompatability::Rails3
165
+ else
166
+ base.send :include, Paperclip::CallbackCompatability::Rails21
167
+ end
168
+ end
169
+ end
170
+
181
171
  module ClassMethods
182
172
  # +has_attached_file+ gives the class it is called on an attribute that maps to a file. This
183
- # is typically a file stored somewhere on the filesystem and has been uploaded by a user.
173
+ # is typically a file stored somewhere on the filesystem and has been uploaded by a user.
184
174
  # The attribute returns a Paperclip::Attachment object which handles the management of
185
- # that file. The intent is to make the attachment as much like a normal attribute. The
186
- # thumbnails will be created when the new file is assigned, but they will *not* be saved
187
- # until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is
188
- # called on it, the attachment will *not* be deleted until +save+ is called. See the
189
- # Paperclip::Attachment documentation for more specifics. There are a number of options
175
+ # that file. The intent is to make the attachment as much like a normal attribute. The
176
+ # thumbnails will be created when the new file is assigned, but they will *not* be saved
177
+ # until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is
178
+ # called on it, the attachment will *not* be deleted until +save+ is called. See the
179
+ # Paperclip::Attachment documentation for more specifics. There are a number of options
190
180
  # you can set to change the behavior of a Paperclip attachment:
191
181
  # * +url+: The full URL of where the attachment is publically accessible. This can just
192
182
  # as easily point to a directory served directly through Apache as it can to an action
193
183
  # that can control permissions. You can specify the full domain and path, but usually
194
- # just an absolute path is sufficient. The leading slash *must* be included manually for
195
- # absolute paths. The default value is
184
+ # just an absolute path is sufficient. The leading slash *must* be included manually for
185
+ # absolute paths. The default value is
196
186
  # "/system/:attachment/:id/:style/:filename". See
197
187
  # Paperclip::Attachment#interpolate for more information on variable interpolaton.
198
188
  # :url => "/:class/:attachment/:id/:style_:filename"
199
189
  # :url => "http://some.other.host/stuff/:class/:id_:extension"
200
- # * +default_url+: The URL that will be returned if there is no attachment assigned.
201
- # This field is interpolated just as the url is. The default value is
190
+ # * +default_url+: The URL that will be returned if there is no attachment assigned.
191
+ # This field is interpolated just as the url is. The default value is
202
192
  # "/:attachment/:style/missing.png"
203
193
  # has_attached_file :avatar, :default_url => "/images/default_:style_avatar.png"
204
194
  # User.new.avatar_url(:small) # => "/images/default_small_avatar.png"
205
- # * +styles+: A hash of thumbnail styles and their geometries. You can find more about
206
- # geometry strings at the ImageMagick website
195
+ # * +styles+: A hash of thumbnail styles and their geometries. You can find more about
196
+ # geometry strings at the ImageMagick website
207
197
  # (http://www.imagemagick.org/script/command-line-options.php#resize). Paperclip
208
- # also adds the "#" option (e.g. "50x50#"), which will resize the image to fit maximally
209
- # inside the dimensions and then crop the rest off (weighted at the center). The
198
+ # also adds the "#" option (e.g. "50x50#"), which will resize the image to fit maximally
199
+ # inside the dimensions and then crop the rest off (weighted at the center). The
210
200
  # default value is to generate no thumbnails.
211
- # * +default_style+: The thumbnail style that will be used by default URLs.
201
+ # * +default_style+: The thumbnail style that will be used by default URLs.
212
202
  # Defaults to +original+.
213
203
  # has_attached_file :avatar, :styles => { :normal => "100x100#" },
214
204
  # :default_style => :normal
215
205
  # user.avatar.url # => "/avatars/23/normal_me.png"
216
206
  # * +whiny+: Will raise an error if Paperclip cannot post_process an uploaded file due
217
- # to a command line error. This will override the global setting for this attachment.
207
+ # to a command line error. This will override the global setting for this attachment.
218
208
  # Defaults to true. This option used to be called :whiny_thumbanils, but this is
219
209
  # deprecated.
220
210
  # * +convert_options+: When creating thumbnails, use this free-form options
@@ -289,10 +279,11 @@ module Paperclip
289
279
  message = message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s)
290
280
 
291
281
  validates_inclusion_of :"#{name}_file_size",
292
- :in => range,
293
- :message => message,
294
- :if => options[:if],
295
- :unless => options[:unless]
282
+ :in => range,
283
+ :message => message,
284
+ :if => options[:if],
285
+ :unless => options[:unless],
286
+ :allow_nil => true
296
287
  end
297
288
 
298
289
  # Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true.
@@ -310,19 +301,19 @@ module Paperclip
310
301
  # * +unless+: Same as +if+ but validates if lambda or method returns false.
311
302
  def validates_attachment_presence name, options = {}
312
303
  message = options[:message] || "must be set."
313
- validates_presence_of :"#{name}_file_name",
314
- :message => message,
315
- :if => options[:if],
316
- :unless => options[:unless]
304
+ validates_presence_of :"#{name}_file_name",
305
+ :message => message,
306
+ :if => options[:if],
307
+ :unless => options[:unless]
317
308
  end
318
-
309
+
319
310
  # Places ActiveRecord-style validations on the content type of the file
320
- # assigned. The possible options are:
321
- # * +content_type+: Allowed content types. Can be a single content type
322
- # or an array. Each type can be a String or a Regexp. It should be
323
- # noted that Internet Explorer upload files with content_types that you
324
- # may not expect. For example, JPEG images are given image/pjpeg and
325
- # PNGs are image/x-png, so keep that in mind when determining how you
311
+ # assigned. The possible options are:
312
+ # * +content_type+: Allowed content types. Can be a single content type
313
+ # or an array. Each type can be a String or a Regexp. It should be
314
+ # noted that Internet Explorer upload files with content_types that you
315
+ # may not expect. For example, JPEG images are given image/pjpeg and
316
+ # PNGs are image/x-png, so keep that in mind when determining how you
326
317
  # match. Allows all by default.
327
318
  # * +message+: The message to display when the uploaded file has an invalid
328
319
  # content type.
@@ -333,11 +324,12 @@ module Paperclip
333
324
  # model, content_type validation will work _ONLY upon assignment_ and
334
325
  # re-validation after the instance has been reloaded will always succeed.
335
326
  def validates_attachment_content_type name, options = {}
336
- types = [options.delete(:content_type)].flatten
337
- validates_each(:"#{name}_content_type", options) do |record, attr, value|
338
- unless types.any?{|t| t === value }
327
+ validation_options = options.dup
328
+ allowed_types = [validation_options[:content_type]].flatten
329
+ validates_each(:"#{name}_content_type", validation_options) do |record, attr, value|
330
+ if !allowed_types.any?{|t| t === value } && !(value.nil? || value.blank?)
339
331
  if record.errors.method(:add).arity == -2
340
- message = options[:message] || "is not one of #{types.join(", ")}"
332
+ message = options[:message] || "is not one of #{allowed_types.join(", ")}"
341
333
  record.errors.add(:"#{name}_content_type", message)
342
334
  else
343
335
  record.errors.add(:"#{name}_content_type", :inclusion, :default => options[:message], :value => value)
@@ -358,7 +350,7 @@ module Paperclip
358
350
  @_paperclip_attachments ||= {}
359
351
  @_paperclip_attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name])
360
352
  end
361
-
353
+
362
354
  def each_attachment
363
355
  self.class.attachment_definitions.each do |name, definition|
364
356
  yield(name, attachment_for(name))
@@ -382,9 +374,3 @@ module Paperclip
382
374
  end
383
375
 
384
376
  end
385
-
386
- # Set it all up.
387
- if Object.const_defined?("ActiveRecord")
388
- ActiveRecord::Base.send(:include, Paperclip)
389
- File.send(:include, Paperclip::Upfile)
390
- end
@@ -0,0 +1,72 @@
1
+ def obtain_class
2
+ class_name = ENV['CLASS'] || ENV['class']
3
+ raise "Must specify CLASS" unless class_name
4
+ class_name
5
+ end
6
+
7
+ def obtain_attachments(klass)
8
+ klass = Object.const_get(klass.to_s)
9
+ name = ENV['ATTACHMENT'] || ENV['attachment']
10
+ raise "Class #{klass.name} has no attachments specified" unless klass.respond_to?(:attachment_definitions)
11
+ if !name.blank? && klass.attachment_definitions.keys.include?(name)
12
+ [ name ]
13
+ else
14
+ klass.attachment_definitions.keys
15
+ end
16
+ end
17
+
18
+ namespace :paperclip do
19
+ desc "Refreshes both metadata and thumbnails."
20
+ task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"]
21
+
22
+ namespace :refresh do
23
+ desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)."
24
+ task :thumbnails => :environment do
25
+ errors = []
26
+ klass = obtain_class
27
+ names = obtain_attachments(klass)
28
+ names.each do |name|
29
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
30
+ result = instance.send(name).reprocess!
31
+ errors << [instance.id, instance.errors] unless instance.errors.blank?
32
+ end
33
+ end
34
+ errors.each{|e| puts "#{e.first}: #{e.last.full_messages.inspect}" }
35
+ end
36
+
37
+ desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)."
38
+ task :metadata => :environment do
39
+ klass = obtain_class
40
+ names = obtain_attachments(klass)
41
+ names.each do |name|
42
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
43
+ if file = instance.send(name).to_file
44
+ instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
45
+ instance.send("#{name}_content_type=", file.content_type.strip)
46
+ instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
47
+ instance.save(false)
48
+ else
49
+ true
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ desc "Cleans out invalid attachments. Useful after you've added new validations."
57
+ task :clean => :environment do
58
+ klass = obtain_class
59
+ names = obtain_attachments(klass)
60
+ names.each do |name|
61
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
62
+ instance.send(name).send(:validate)
63
+ if instance.send(name).valid?
64
+ true
65
+ else
66
+ instance.send("#{name}=", nil)
67
+ instance.save
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'paperclip/railtie'
2
+ Paperclip::Railtie.insert
@@ -1,5 +1,4 @@
1
1
  require 'paperclip/matchers'
2
- require 'action_controller'
3
2
 
4
3
  module Paperclip
5
4
  # =Paperclip Shoulda Macros
@@ -46,7 +45,7 @@ module Paperclip
46
45
  end
47
46
 
48
47
  # Tests to ensure that you have file size validations turned on. You
49
- # can pass the same options to this that you can to
48
+ # can pass the same options to this that you can to
50
49
  # validate_attachment_file_size - :less_than, :greater_than, and :in.
51
50
  # :less_than checks that a file is less than a certain size, :greater_than
52
51
  # checks that a file is more than a certain size, and :in takes a Range or
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
- require 'test/helper'
2
+ require './test/helper'
3
3
 
4
4
  class Dummy
5
5
  # This is a dummy class
@@ -53,7 +53,7 @@ class AttachmentTest < Test::Unit::TestCase
53
53
  setup do
54
54
  @dummy = Dummy.new
55
55
  end
56
-
56
+
57
57
  should "return false when asked exists?" do
58
58
  assert !@dummy.avatar.exists?
59
59
  end
@@ -67,7 +67,7 @@ class AttachmentTest < Test::Unit::TestCase
67
67
 
68
68
  Paperclip::Attachment.default_options.keys.each do |key|
69
69
  should "be the default_options for #{key}" do
70
- assert_equal @old_default_options[key],
70
+ assert_equal @old_default_options[key],
71
71
  @attachment.instance_variable_get("@#{key}"),
72
72
  key
73
73
  end
@@ -189,11 +189,11 @@ class AttachmentTest < Test::Unit::TestCase
189
189
  assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
190
190
  end
191
191
  end
192
-
192
+
193
193
  context "An attachment with :path that is a proc" do
194
194
  setup do
195
195
  rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
196
-
196
+
197
197
  @file = File.new(File.join(File.dirname(__FILE__),
198
198
  "fixtures",
199
199
  "5k.png"), 'rb')
@@ -202,31 +202,31 @@ class AttachmentTest < Test::Unit::TestCase
202
202
  @dummyB = Dummy.new(:other => 'b')
203
203
  @dummyB.avatar = @file
204
204
  end
205
-
205
+
206
206
  teardown { @file.close }
207
-
207
+
208
208
  should "return correct path" do
209
209
  assert_equal "path/a.png", @dummyA.avatar.path
210
210
  assert_equal "path/b.png", @dummyB.avatar.path
211
211
  end
212
212
  end
213
-
213
+
214
214
  context "An attachment with :styles that is a proc" do
215
215
  setup do
216
216
  rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} }
217
-
217
+
218
218
  @attachment = Dummy.new.avatar
219
219
  end
220
-
220
+
221
221
  should "have the correct geometry" do
222
222
  assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
223
223
  end
224
224
  end
225
-
225
+
226
226
  context "An attachment with :url that is a proc" do
227
227
  setup do
228
228
  rebuild_model :url => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" }
229
-
229
+
230
230
  @file = File.new(File.join(File.dirname(__FILE__),
231
231
  "fixtures",
232
232
  "5k.png"), 'rb')
@@ -235,16 +235,16 @@ class AttachmentTest < Test::Unit::TestCase
235
235
  @dummyB = Dummy.new(:other => 'b')
236
236
  @dummyB.avatar = @file
237
237
  end
238
-
238
+
239
239
  teardown { @file.close }
240
-
240
+
241
241
  should "return correct url" do
242
242
  assert_equal "path/a.png", @dummyA.avatar.url(:original, false)
243
243
  assert_equal "path/b.png", @dummyB.avatar.url(:original, false)
244
244
  end
245
245
  end
246
246
 
247
- geometry_specs = [
247
+ geometry_specs = [
248
248
  [ lambda{|z| "50x50#" }, :png ],
249
249
  lambda{|z| "50x50#" },
250
250
  { :geometry => lambda{|z| "50x50#" } }
@@ -338,21 +338,41 @@ class AttachmentTest < Test::Unit::TestCase
338
338
  Paperclip::Thumbnail.expects(:make).with(any_parameters).returns(@file)
339
339
  Paperclip::Test.expects(:make).with(any_parameters).returns(@file)
340
340
  end
341
-
341
+
342
342
  before_should "call #make with the right parameters passed as second argument" do
343
343
  expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""})
344
344
  Paperclip::Thumbnail.expects(:make).with(anything, expected_params, anything).returns(@file)
345
345
  end
346
-
346
+
347
347
  before_should "call #make with attachment passed as third argument" do
348
348
  Paperclip::Test.expects(:make).with(anything, anything, @dummy.avatar).returns(@file)
349
349
  end
350
350
  end
351
351
  end
352
352
 
353
+ should "include the filesystem module when loading the filesystem storage" do
354
+ rebuild_model :storage => :filesystem
355
+ @dummy = Dummy.new
356
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
357
+ end
358
+
359
+ should "include the filesystem module even if capitalization is wrong" do
360
+ rebuild_model :storage => :FileSystem
361
+ @dummy = Dummy.new
362
+ assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
363
+ end
364
+
365
+ should "raise an error if you try to include a storage module that doesn't exist" do
366
+ rebuild_model :storage => :not_here
367
+ @dummy = Dummy.new
368
+ assert_raises(Paperclip::StorageMethodNotFound) do
369
+ @dummy.avatar
370
+ end
371
+ end
372
+
353
373
  context "An attachment with styles but no processors defined" do
354
374
  setup do
355
- rebuild_model :processors => [], :styles => {:something => 1}
375
+ rebuild_model :processors => [], :styles => {:something => '1'}
356
376
  @dummy = Dummy.new
357
377
  @file = StringIO.new("...")
358
378
  end
@@ -454,16 +474,15 @@ class AttachmentTest < Test::Unit::TestCase
454
474
  context "Attachment with strange letters" do
455
475
  setup do
456
476
  rebuild_model
457
-
458
- @not_file = mock
459
- @tempfile = mock
477
+
478
+ @not_file = mock("not_file")
479
+ @tempfile = mock("tempfile")
460
480
  @not_file.stubs(:nil?).returns(false)
461
481
  @not_file.expects(:size).returns(10)
462
482
  @tempfile.expects(:size).returns(10)
463
- @not_file.expects(:to_tempfile).returns(@tempfile)
464
483
  @not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n")
465
484
  @not_file.expects(:content_type).returns("image/png\r\n")
466
-
485
+
467
486
  @dummy = Dummy.new
468
487
  @attachment = @dummy.avatar
469
488
  @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
@@ -471,9 +490,12 @@ class AttachmentTest < Test::Unit::TestCase
471
490
  @attachment.expects(:post_process)
472
491
  @attachment.expects(:valid?).returns(true)
473
492
  @attachment.expects(:validate)
493
+ @attachment.expects(:to_tempfile).returns(@tempfile)
494
+ @attachment.expects(:generate_fingerprint).with(@tempfile).returns("12345")
495
+ @attachment.expects(:generate_fingerprint).with(@not_file).returns("12345")
474
496
  @dummy.avatar = @not_file
475
497
  end
476
-
498
+
477
499
  should "not remove strange letters" do
478
500
  assert_equal "sheep_say_bæ.png", @dummy.avatar.original_filename
479
501
  end
@@ -598,7 +620,7 @@ class AttachmentTest < Test::Unit::TestCase
598
620
  [:large, :medium, :small].each do |style|
599
621
  io = @attachment.to_file(style)
600
622
  # p "in commit to disk test, io is #{io.inspect} and @instance.id is #{@instance.id}"
601
- assert File.exists?(io)
623
+ assert File.exists?(io.path)
602
624
  assert ! io.is_a?(::Tempfile)
603
625
  io.close
604
626
  end
@@ -611,7 +633,7 @@ class AttachmentTest < Test::Unit::TestCase
611
633
  cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"]
612
634
  out = `#{cmd}`
613
635
  width, height, size, format = out.split(" ")
614
- assert_equal style[1].to_s, width.to_s
636
+ assert_equal style[1].to_s, width.to_s
615
637
  assert_equal style[2].to_s, height.to_s
616
638
  assert_equal style[3].to_s, format.to_s
617
639
  end
@@ -670,7 +692,7 @@ class AttachmentTest < Test::Unit::TestCase
670
692
  end
671
693
 
672
694
  should "not be able to find the module" do
673
- assert_raise(NameError){ Dummy.new.avatar }
695
+ assert_raise(Paperclip::StorageMethodNotFound){ Dummy.new.avatar }
674
696
  end
675
697
  end
676
698
  end
@@ -695,7 +717,7 @@ class AttachmentTest < Test::Unit::TestCase
695
717
  now = Time.now
696
718
  Time.stubs(:now).returns(now)
697
719
  @dummy.avatar = @file
698
- assert now, @dummy.avatar.updated_at
720
+ assert_equal now.to_i, @dummy.avatar.updated_at.to_i
699
721
  end
700
722
 
701
723
  should "return nil when reloaded and sent #avatar_updated_at" do
@@ -768,5 +790,29 @@ class AttachmentTest < Test::Unit::TestCase
768
790
  assert_equal @file.size, @dummy.avatar.size
769
791
  end
770
792
  end
793
+
794
+ context "and avatar_fingerprint column" do
795
+ setup do
796
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_fingerprint, :string
797
+ rebuild_class
798
+ @dummy = Dummy.new
799
+ end
800
+
801
+ should "not error when assigned an attachment" do
802
+ assert_nothing_raised { @dummy.avatar = @file }
803
+ end
804
+
805
+ should "return the right value when sent #avatar_fingerprint" do
806
+ @dummy.avatar = @file
807
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
808
+ end
809
+
810
+ should "return the right value when saved, reloaded, and sent #avatar_fingerprint" do
811
+ @dummy.avatar = @file
812
+ @dummy.save
813
+ @dummy = Dummy.find(@dummy.id)
814
+ assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
815
+ end
816
+ end
771
817
  end
772
818
  end