paperclip-cloudfiles 2.3.2 → 2.3.8

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.
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