bteitelb-paperclip 2.3.1.13 → 2.3.1.14

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.
data/Rakefile CHANGED
@@ -75,8 +75,8 @@ spec = Gem::Specification.new do |s|
75
75
  s.extra_rdoc_files = FileList["README*"].to_a
76
76
  s.rdoc_options << '--line-numbers' << '--inline-source'
77
77
  s.requirements << "ImageMagick"
78
- s.add_development_dependency 'shoulda'
79
- s.add_development_dependency 'jferris-mocha', '>= 0.9.5.0.1241126838'
78
+ s.add_development_dependency 'thoughtbot-shoulda'
79
+ s.add_development_dependency 'jferris-mocha', '= 0.9.5.0.1241126838'
80
80
  s.add_development_dependency 'aws-s3'
81
81
  s.add_development_dependency 'sqlite3-ruby'
82
82
  s.add_development_dependency 'activerecord'
@@ -34,7 +34,6 @@ require 'paperclip/processor'
34
34
  require 'paperclip/thumbnail'
35
35
  require 'paperclip/storage'
36
36
  require 'paperclip/interpolations'
37
- require 'paperclip/style'
38
37
  require 'paperclip/attachment'
39
38
  if defined? RAILS_ROOT
40
39
  Dir.glob(File.join(File.expand_path(RAILS_ROOT), "lib", "paperclip_processors", "*.rb")).each do |processor|
@@ -240,7 +239,7 @@ module Paperclip
240
239
 
241
240
  validates_each(name) do |record, attr, value|
242
241
  attachment = record.attachment_for(name)
243
- attachment.send(:flush_errors)
242
+ attachment.send(:flush_errors) unless attachment.valid?
244
243
  end
245
244
  end
246
245
 
@@ -258,13 +257,13 @@ module Paperclip
258
257
  max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
259
258
  range = (min..max)
260
259
  message = options[:message] || "file size must be between :min and :max bytes."
261
- message = message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s)
262
260
 
263
- validates_inclusion_of :"#{name}_file_size",
264
- :in => range,
265
- :message => message,
266
- :if => options[:if],
267
- :unless => options[:unless]
261
+ attachment_definitions[name][:validations] << [:size, {:min => min,
262
+ :max => max,
263
+ :range => range,
264
+ :message => message,
265
+ :if => options[:if],
266
+ :unless => options[:unless]}]
268
267
  end
269
268
 
270
269
  # Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true.
@@ -282,10 +281,9 @@ module Paperclip
282
281
  # * +unless+: Same as +if+ but validates if lambda or method returns false.
283
282
  def validates_attachment_presence name, options = {}
284
283
  message = options[:message] || "must be set."
285
- validates_presence_of :"#{name}_file_name",
286
- :message => message,
287
- :if => options[:if],
288
- :unless => options[:unless]
284
+ attachment_definitions[name][:validations] << [:presence, {:message => message,
285
+ :if => options[:if],
286
+ :unless => options[:unless]}]
289
287
  end
290
288
 
291
289
  # Places ActiveRecord-style validations on the content type of the file
@@ -305,12 +303,10 @@ module Paperclip
305
303
  # model, content_type validation will work _ONLY upon assignment_ and
306
304
  # re-validation after the instance has been reloaded will always succeed.
307
305
  def validates_attachment_content_type name, options = {}
308
- types = [options.delete(:content_type)].flatten
309
- validates_each(:"#{name}_content_type", options) do |record, attr, value|
310
- unless types.any?{|t| t === value }
311
- record.errors.add(:"#{name}_content_type", :inclusion, :default => options[:message], :value => value)
312
- end
313
- end
306
+ attachment_definitions[name][:validations] << [:content_type, {:content_type => options[:content_type],
307
+ :message => options[:message],
308
+ :if => options[:if],
309
+ :unless => options[:unless]}]
314
310
  end
315
311
 
316
312
  # Returns the attachment definitions defined by each call to
@@ -9,19 +9,18 @@ module Paperclip
9
9
 
10
10
  def self.default_options
11
11
  @default_options ||= {
12
- :url => "/system/:attachment/:id/:style/:filename",
13
- :path => ":rails_root/public:url",
14
- :styles => {},
15
- :processors => [:thumbnail],
16
- :convert_options => {},
17
- :default_url => "/:attachment/:style/missing.png",
18
- :default_style => :original,
19
- :storage => :filesystem,
20
- :whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails]
12
+ :url => "/system/:attachment/:id/:style/:filename",
13
+ :path => ":rails_root/public:url",
14
+ :styles => {},
15
+ :default_url => "/:attachment/:style/missing.png",
16
+ :default_style => :original,
17
+ :validations => [],
18
+ :storage => :filesystem,
19
+ :whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails]
21
20
  }
22
21
  end
23
22
 
24
- attr_reader :name, :instance, :default_style, :convert_options, :queued_for_write, :whiny, :options
23
+ attr_reader :name, :instance, :styles, :default_style, :convert_options, :queued_for_write, :options
25
24
 
26
25
  # Creates an Attachment object. +name+ is the name of the attachment,
27
26
  # +instance+ is the ActiveRecord object instance it's attached to, and
@@ -37,13 +36,14 @@ module Paperclip
37
36
  @path = options[:path]
38
37
  @path = @path.call(self) if @path.is_a?(Proc)
39
38
  @styles = options[:styles]
40
- @normalized_styles = nil
39
+ @styles = @styles.call(self) if @styles.is_a?(Proc)
41
40
  @default_url = options[:default_url]
41
+ @validations = options[:validations]
42
42
  @default_style = options[:default_style]
43
43
  @storage = options[:storage]
44
44
  @whiny = options[:whiny_thumbnails] || options[:whiny]
45
- @convert_options = options[:convert_options]
46
- @processors = options[:processors]
45
+ @convert_options = options[:convert_options] || {}
46
+ @processors = options[:processors] || [:thumbnail]
47
47
  @options = options
48
48
  @queued_for_delete = []
49
49
  @queued_for_write = {}
@@ -52,29 +52,18 @@ module Paperclip
52
52
  @validation_errors = nil
53
53
  @dirty = false
54
54
 
55
+ normalize_style_definition
55
56
  initialize_storage
56
57
  end
57
-
58
- def styles
59
- unless @normalized_styles
60
- @normalized_styles = {}
61
- (@styles.respond_to?(:call) ? @styles.call(self) : @styles).each do |name, args|
62
- @normalized_styles[name] = Paperclip::Style.new(name, args, self)
63
- end
64
- end
65
- @normalized_styles
66
- end
67
-
68
- def processors
69
- @processors.respond_to?(:call) ? @processors.call(instance) : @processors
70
- end
71
58
 
72
59
  # What gets called when you call instance.attachment = File. It clears
73
- # errors, assigns attributes, and processes the file. It
60
+ # errors, assigns attributes, processes the file, and runs validations. It
74
61
  # also queues up the previous file for deletion, to be flushed away on
75
62
  # #save of its host. In addition to form uploads, you can also assign
76
63
  # another Paperclip attachment:
77
64
  # new_user.avatar = old_user.avatar
65
+ # If the file that is assigned is not valid, the processing (i.e.
66
+ # thumbnailing, etc) will NOT be run.
78
67
  def assign uploaded_file
79
68
  ensure_required_accessors!
80
69
 
@@ -104,7 +93,7 @@ module Paperclip
104
93
 
105
94
  @dirty = true
106
95
 
107
- post_process
96
+ post_process if valid?
108
97
 
109
98
  # Reset the file size if the original file was reprocessed.
110
99
  instance_write(:file_size, @queued_for_write[:original].size.to_i)
@@ -126,6 +115,7 @@ module Paperclip
126
115
  end
127
116
  ensure
128
117
  uploaded_file.close if close_uploaded_file
118
+ validate
129
119
  end
130
120
 
131
121
  # Returns the public URL of the attachment, with a given style. Note that
@@ -135,8 +125,8 @@ module Paperclip
135
125
  # security, however, for performance reasons. set
136
126
  # include_updated_timestamp to false if you want to stop the attachment
137
127
  # update time appended to the url
138
- def url style_name = default_style, include_updated_timestamp = true
139
- url = original_filename.nil? ? interpolate(@default_url, style_name) : interpolate(@url, style_name)
128
+ def url style = default_style, include_updated_timestamp = true
129
+ url = original_filename.nil? ? interpolate(@default_url, style) : interpolate(@url, style)
140
130
  include_updated_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url
141
131
  end
142
132
 
@@ -144,13 +134,19 @@ module Paperclip
144
134
  # file is stored in the filesystem the path refers to the path of the file
145
135
  # on disk. If the file is stored in S3, the path is the "key" part of the
146
136
  # URL, and the :bucket option refers to the S3 bucket.
147
- def path style_name = default_style
148
- original_filename.nil? ? nil : interpolate(@path, style_name)
137
+ def path style = default_style
138
+ original_filename.nil? ? nil : interpolate(@path, style)
149
139
  end
150
140
 
151
141
  # Alias to +url+
152
- def to_s style_name = nil
153
- url(style_name)
142
+ def to_s style = nil
143
+ url(style)
144
+ end
145
+
146
+ # Returns true if there are no errors on this attachment.
147
+ def valid?
148
+ validate
149
+ errors.empty?
154
150
  end
155
151
 
156
152
  # Returns an array containing the errors on this attachment.
@@ -166,10 +162,15 @@ module Paperclip
166
162
  # Saves the file, if there are no errors. If there are, it flushes them to
167
163
  # the instance's errors and returns false, cancelling the save.
168
164
  def save
169
- flush_deletes
170
- flush_writes
171
- @dirty = false
172
- true
165
+ if valid?
166
+ flush_deletes
167
+ flush_writes
168
+ @dirty = false
169
+ true
170
+ else
171
+ flush_errors
172
+ false
173
+ end
173
174
  end
174
175
 
175
176
  # Clears out the attachment. Has the same effect as previously assigning
@@ -178,6 +179,7 @@ module Paperclip
178
179
  def clear
179
180
  queue_existing_for_delete
180
181
  @errors = {}
182
+ @validation_errors = nil
181
183
  end
182
184
 
183
185
  # Destroys the attachment. Has the same effect as previously assigning
@@ -309,6 +311,82 @@ module Paperclip
309
311
  file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type))
310
312
  end
311
313
 
314
+ def validate #:nodoc:
315
+ unless @validation_errors
316
+ @validation_errors = @validations.inject({}) do |errors, validation|
317
+ name, options = validation
318
+ errors[name] = send(:"validate_#{name}", options) if allow_validation?(options)
319
+ errors
320
+ end
321
+ @validation_errors.reject!{|k,v| v == nil }
322
+ @errors.merge!(@validation_errors)
323
+ end
324
+ @validation_errors
325
+ end
326
+
327
+ def allow_validation? options #:nodoc:
328
+ (options[:if].nil? || check_guard(options[:if])) && (options[:unless].nil? || !check_guard(options[:unless]))
329
+ end
330
+
331
+ def check_guard guard #:nodoc:
332
+ if guard.respond_to? :call
333
+ guard.call(instance)
334
+ elsif ! guard.blank?
335
+ instance.send(guard.to_s)
336
+ end
337
+ end
338
+
339
+ def validate_size options #:nodoc:
340
+ if file? && !options[:range].include?(size.to_i)
341
+ options[:message].gsub(/:min/, options[:min].to_s).gsub(/:max/, options[:max].to_s)
342
+ end
343
+ end
344
+
345
+ def validate_presence options #:nodoc:
346
+ options[:message] unless file?
347
+ end
348
+
349
+ def validate_content_type options #:nodoc:
350
+ valid_types = [options[:content_type]].flatten
351
+ unless original_filename.blank?
352
+ unless valid_types.blank?
353
+ content_type = instance_read(:content_type)
354
+ unless valid_types.any?{|t| content_type.nil? || t === content_type }
355
+ options[:message] || "is not one of the allowed file types."
356
+ end
357
+ end
358
+ end
359
+ end
360
+
361
+ def normalize_style_definition #:nodoc:
362
+ @styles.each do |name, args|
363
+ unless args.is_a? Hash
364
+ dimensions, format = [args, nil].flatten[0..1]
365
+ format = nil if format.blank?
366
+ @styles[name] = {
367
+ :processors => @processors,
368
+ :geometry => dimensions,
369
+ :format => format,
370
+ :whiny => @whiny,
371
+ :convert_options => extra_options_for(name)
372
+ }
373
+ else
374
+ @styles[name] = {
375
+ :processors => @processors,
376
+ :whiny => @whiny,
377
+ :convert_options => extra_options_for(name)
378
+ }.merge(@styles[name])
379
+ end
380
+ end
381
+ end
382
+
383
+ def solidify_style_definitions #:nodoc:
384
+ @styles.each do |name, args|
385
+ @styles[name][:geometry] = @styles[name][:geometry].call(instance) if @styles[name][:geometry].respond_to?(:call)
386
+ @styles[name][:processors] = @styles[name][:processors].call(instance) if @styles[name][:processors].respond_to?(:call)
387
+ end
388
+ end
389
+
312
390
  def initialize_storage #:nodoc:
313
391
  @storage_module = Paperclip::Storage.const_get(@storage.to_s.capitalize)
314
392
  self.extend(@storage_module)
@@ -325,6 +403,7 @@ module Paperclip
325
403
 
326
404
  def post_process #:nodoc:
327
405
  return if @queued_for_write[:original].nil?
406
+ solidify_style_definitions
328
407
  return if fire_events(:before)
329
408
  post_process_styles
330
409
  return if fire_events(:after)
@@ -340,11 +419,11 @@ module Paperclip
340
419
  end
341
420
 
342
421
  def post_process_styles #:nodoc:
343
- styles.each do |name, style|
422
+ @styles.each do |name, args|
344
423
  begin
345
- raise RuntimeError.new("Style #{name} has no processors defined.") if style.processors.blank?
346
- @queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
347
- Paperclip.processor(processor).make(file, style.processor_options, self)
424
+ raise RuntimeError.new("Style #{name} has no processors defined.") if args[:processors].blank?
425
+ @queued_for_write[name] = args[:processors].inject(@queued_for_write[:original]) do |file, processor|
426
+ Paperclip.processor(processor).make(file, args, self)
348
427
  end
349
428
  rescue PaperclipError => e
350
429
  log("An error was received while processing: #{e.inspect}")
@@ -353,8 +432,8 @@ module Paperclip
353
432
  end
354
433
  end
355
434
 
356
- def interpolate pattern, style_name = default_style #:nodoc:
357
- Paperclip::Interpolations.interpolate(pattern, self, style_name)
435
+ def interpolate pattern, style = default_style #:nodoc:
436
+ Paperclip::Interpolations.interpolate(pattern, self, style)
358
437
  end
359
438
 
360
439
  def mime_type
@@ -381,7 +460,7 @@ module Paperclip
381
460
 
382
461
  def queue_existing_for_delete #:nodoc:
383
462
  return unless file?
384
- @queued_for_delete += [:original, *styles.keys].uniq.map do |style|
463
+ @queued_for_delete += [:original, *@styles.keys].uniq.map do |style|
385
464
  path(style) if exists?(style)
386
465
  end.compact
387
466
  instance_write(:file_name, nil)
@@ -34,30 +34,30 @@ module Paperclip
34
34
  end
35
35
 
36
36
  # Returns the filename, the same way as ":basename.:extension" would.
37
- def filename attachment, style_name
38
- "#{basename(attachment, style_name)}.#{extension(attachment, style_name)}"
37
+ def filename attachment, style
38
+ "#{basename(attachment, style)}.#{extension(attachment, style)}"
39
39
  end
40
40
 
41
41
  # Returns the interpolated URL. Will raise an error if the url itself
42
42
  # contains ":url" to prevent infinite recursion. This interpolation
43
43
  # is used in the default :path to ease default specifications.
44
- def url attachment, style_name
44
+ def url attachment, style
45
45
  raise InfiniteInterpolationError if attachment.options[:url].include?(":url")
46
- attachment.url(style_name, false)
46
+ attachment.url(style, false)
47
47
  end
48
48
 
49
49
  # Returns the timestamp as defined by the <attachment>_updated_at field
50
- def timestamp attachment, style_name
50
+ def timestamp attachment, style
51
51
  attachment.instance_read(:updated_at).to_s
52
52
  end
53
53
 
54
54
  # Returns the RAILS_ROOT constant.
55
- def rails_root attachment, style_name
55
+ def rails_root attachment, style
56
56
  RAILS_ROOT
57
57
  end
58
58
 
59
59
  # Returns the RAILS_ENV constant.
60
- def rails_env attachment, style_name
60
+ def rails_env attachment, style
61
61
  RAILS_ENV
62
62
  end
63
63
 
@@ -65,44 +65,44 @@ module Paperclip
65
65
  # e.g. "users" for the User class.
66
66
  # NOTE: The arguments need to be optional, because some tools fetch
67
67
  # all class names. Calling #class will return the expected class.
68
- def class attachment = nil, style_name = nil
69
- return super() if attachment.nil? && style_name.nil?
68
+ def class attachment = nil, style = nil
69
+ return super() if attachment.nil? && style.nil?
70
70
  attachment.instance.class.to_s.underscore.pluralize
71
71
  end
72
72
 
73
73
  # Returns the basename of the file. e.g. "file" for "file.jpg"
74
- def basename attachment, style_name
74
+ def basename attachment, style
75
75
  attachment.original_filename.gsub(/#{File.extname(attachment.original_filename)}$/, "")
76
76
  end
77
77
 
78
78
  # Returns the extension of the file. e.g. "jpg" for "file.jpg"
79
79
  # If the style has a format defined, it will return the format instead
80
80
  # of the actual extension.
81
- def extension attachment, style_name
82
- ((style = attachment.styles[style_name]) && style[:format]) ||
81
+ def extension attachment, style
82
+ ((style = attachment.styles[style]) && style[:format]) ||
83
83
  File.extname(attachment.original_filename).gsub(/^\.+/, "")
84
84
  end
85
85
 
86
86
  # Returns the id of the instance.
87
- def id attachment, style_name
87
+ def id attachment, style
88
88
  attachment.instance.id
89
89
  end
90
90
 
91
91
  # Returns the id of the instance in a split path form. e.g. returns
92
92
  # 000/001/234 for an id of 1234.
93
- def id_partition attachment, style_name
93
+ def id_partition attachment, style
94
94
  ("%09d" % attachment.instance.id).scan(/\d{3}/).join("/")
95
95
  end
96
96
 
97
97
  # Returns the pluralized form of the attachment name. e.g.
98
98
  # "avatars" for an attachment of :avatar
99
- def attachment attachment, style_name
99
+ def attachment attachment, style
100
100
  attachment.name.to_s.downcase.pluralize
101
101
  end
102
102
 
103
103
  # Returns the style, or the default style if nil is supplied.
104
- def style attachment, style_name
105
- style_name || attachment.default_style
104
+ def style attachment, style
105
+ style || attachment.default_style
106
106
  end
107
107
  end
108
108
  end
@@ -4,8 +4,7 @@ module IOStream
4
4
 
5
5
  # Returns a Tempfile containing the contents of the readable object.
6
6
  def to_tempfile
7
- name = respond_to?(:original_filename) ? original_filename : (respond_to?(:path) ? path : "stream")
8
- tempfile = Paperclip::Tempfile.new(File.basename(name))
7
+ tempfile = Tempfile.new("stream")
9
8
  tempfile.binmode
10
9
  self.stream_to(tempfile)
11
10
  end
@@ -46,8 +46,9 @@ module Paperclip
46
46
  types.all? do |type|
47
47
  file = StringIO.new(".")
48
48
  file.content_type = type
49
- (subject = @subject.new).attachment_for(@attachment_name).assign(file)
50
- subject.valid? && subject.errors.on(:"#{@attachment_name}_content_type").blank?
49
+ attachment = @subject.new.attachment_for(@attachment_name)
50
+ attachment.assign(file)
51
+ attachment.errors[:content_type].nil?
51
52
  end
52
53
  end
53
54
 
@@ -30,16 +30,16 @@ module Paperclip
30
30
  protected
31
31
 
32
32
  def error_when_not_valid?
33
- (subject = @subject.new).send(@attachment_name).assign(nil)
34
- subject.valid?
35
- not subject.errors.on(:"#{@attachment_name}_file_name").blank?
33
+ @attachment = @subject.new.send(@attachment_name)
34
+ @attachment.assign(nil)
35
+ not @attachment.errors[:presence].nil?
36
36
  end
37
37
 
38
38
  def no_error_when_valid?
39
39
  @file = StringIO.new(".")
40
- (subject = @subject.new).send(@attachment_name).assign(@file)
41
- subject.valid?
42
- subject.errors.on(:"#{@attachment_name}_file_name").blank?
40
+ @attachment = @subject.new.send(@attachment_name)
41
+ @attachment.assign(@file)
42
+ @attachment.errors[:presence].nil?
43
43
  end
44
44
  end
45
45
  end
@@ -54,11 +54,9 @@ module Paperclip
54
54
  def passes_validation_with_size(new_size)
55
55
  file = StringIO.new(".")
56
56
  override_method(file, :size){ new_size }
57
- override_method(file, :to_tempfile){ file }
58
-
59
- (subject = @subject.new).send(@attachment_name).assign(file)
60
- subject.valid?
61
- subject.errors.on(:"#{@attachment_name}_file_size").blank?
57
+ attachment = @subject.new.attachment_for(@attachment_name)
58
+ attachment.assign(file)
59
+ attachment.errors[:size].nil?
62
60
  end
63
61
 
64
62
  def lower_than_low?
@@ -20,9 +20,9 @@ module Paperclip
20
20
  def self.extended base
21
21
  end
22
22
 
23
- def exists?(style_name = default_style)
23
+ def exists?(style = default_style)
24
24
  if original_filename
25
- File.exist?(path(style_name))
25
+ File.exist?(path(style))
26
26
  else
27
27
  false
28
28
  end
@@ -30,17 +30,17 @@ module Paperclip
30
30
 
31
31
  # Returns representation of the data of the file assigned to the given
32
32
  # style, in the format most representative of the current storage.
33
- def to_file style_name = default_style
34
- @queued_for_write[style_name] || (File.new(path(style_name), 'rb') if exists?(style_name))
33
+ def to_file style = default_style
34
+ @queued_for_write[style] || (File.new(path(style), 'rb') if exists?(style))
35
35
  end
36
36
 
37
37
  def flush_writes #:nodoc:
38
- @queued_for_write.each do |style_name, file|
38
+ @queued_for_write.each do |style, file|
39
39
  file.close
40
- FileUtils.mkdir_p(File.dirname(path(style_name)))
41
- log("saving #{path(style_name)}")
42
- FileUtils.mv(file.path, path(style_name))
43
- FileUtils.chmod(0644, path(style_name))
40
+ FileUtils.mkdir_p(File.dirname(path(style)))
41
+ log("saving #{path(style)}")
42
+ FileUtils.mv(file.path, path(style))
43
+ FileUtils.chmod(0644, path(style))
44
44
  end
45
45
  @queued_for_write = {}
46
46
  end
@@ -159,10 +159,6 @@ module Paperclip
159
159
  "#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}"
160
160
  end
161
161
  end
162
-
163
- def expiring_url(time = 3600)
164
- AWS::S3::S3Object.url_for(path, bucket_name, :expires_in => time )
165
- end
166
162
 
167
163
  def bucket_name
168
164
  @bucket
@@ -12,7 +12,6 @@ module Paperclip
12
12
  # set, the options will be appended to the convert command upon image conversion
13
13
  def initialize file, options = {}, attachment = nil
14
14
  super
15
-
16
15
  geometry = options[:geometry]
17
16
  @file = file
18
17
  @crop = geometry[-1,1] == '#'
@@ -25,7 +24,6 @@ module Paperclip
25
24
 
26
25
  @current_format = File.extname(@file.path)
27
26
  @basename = File.basename(@file.path, @current_format)
28
-
29
27
  end
30
28
 
31
29
  # Returns true if the +target_geometry+ is meant to crop.
@@ -14,6 +14,18 @@ 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 "call a proc sent to check_guard" do
18
+ @dummy = Dummy.new
19
+ @dummy.expects(:one).returns(:one)
20
+ assert_equal :one, @dummy.avatar.send(:check_guard, lambda{|x| x.one })
21
+ end
22
+
23
+ should "call a method name sent to check_guard" do
24
+ @dummy = Dummy.new
25
+ @dummy.expects(:one).returns(:one)
26
+ assert_equal :one, @dummy.avatar.send(:check_guard, :one)
27
+ end
28
+
17
29
  context "Attachment default_options" do
18
30
  setup do
19
31
  rebuild_model
@@ -121,7 +133,7 @@ class AttachmentTest < Test::Unit::TestCase
121
133
  :styles => { :default => ["100x100", :png] },
122
134
  :default_style => :default
123
135
  @file = StringIO.new("...")
124
- @file.stubs(:original_filename).returns("file.jpg")
136
+ @file.expects(:original_filename).returns("file.jpg")
125
137
  end
126
138
  should "return the right extension for the path" do
127
139
  @attachment.assign(@file)
@@ -150,6 +162,11 @@ class AttachmentTest < Test::Unit::TestCase
150
162
  should "report the correct options when sent #extra_options_for(:large)" do
151
163
  assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
152
164
  end
165
+
166
+ before_should "call extra_options_for(:thumb/:large)" do
167
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb)
168
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large)
169
+ end
153
170
  end
154
171
 
155
172
  context "An attachment with :convert_options that is a proc" do
@@ -177,6 +194,11 @@ class AttachmentTest < Test::Unit::TestCase
177
194
  should "report the correct options when sent #extra_options_for(:large)" do
178
195
  assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
179
196
  end
197
+
198
+ before_should "call extra_options_for(:thumb/:large)" do
199
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb)
200
+ Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large)
201
+ end
180
202
  end
181
203
 
182
204
  context "An attachment with :path that is a proc" do
@@ -245,6 +267,10 @@ class AttachmentTest < Test::Unit::TestCase
245
267
  @attachment = Dummy.new.avatar
246
268
  end
247
269
 
270
+ should "not run the procs immediately" do
271
+ assert_kind_of Proc, @attachment.styles[:normal][:geometry]
272
+ end
273
+
248
274
  context "when assigned" do
249
275
  setup do
250
276
  @file = StringIO.new(".")
@@ -281,6 +307,10 @@ class AttachmentTest < Test::Unit::TestCase
281
307
  @attachment = Dummy.new.avatar
282
308
  end
283
309
 
310
+ should "not run the proc immediately" do
311
+ assert_kind_of Proc, @attachment.styles[:normal][:processors]
312
+ end
313
+
284
314
  context "when assigned" do
285
315
  setup do
286
316
  @attachment.assign(StringIO.new("."))
@@ -324,22 +354,19 @@ class AttachmentTest < Test::Unit::TestCase
324
354
  setup { @dummy.avatar = @file }
325
355
 
326
356
  before_should "call #make on all specified processors" do
327
- Paperclip::Thumbnail.expects(:make).with(any_parameters).returns(@file)
328
- Paperclip::Test.expects(:make).with(any_parameters).returns(@file)
329
- end
330
-
331
- before_should "call #make with the right parameters passed as second argument" do
332
357
  expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""})
333
- Paperclip::Thumbnail.expects(:make).with(anything, expected_params, anything).returns(@file)
358
+ Paperclip::Thumbnail.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file)
359
+ Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file)
334
360
  end
335
361
 
336
362
  before_should "call #make with attachment passed as third argument" do
337
- Paperclip::Test.expects(:make).with(anything, anything, @dummy.avatar).returns(@file)
363
+ expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""})
364
+ Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file)
338
365
  end
339
366
  end
340
367
  end
341
368
 
342
- context "An attachment with styles but no processors defined" do
369
+ context "An attachment with no processors defined" do
343
370
  setup do
344
371
  rebuild_model :processors => [], :styles => {:something => 1}
345
372
  @dummy = Dummy.new
@@ -350,17 +377,6 @@ class AttachmentTest < Test::Unit::TestCase
350
377
  end
351
378
  end
352
379
 
353
- context "An attachment without styles and with no processors defined" do
354
- setup do
355
- rebuild_model :processors => [], :styles => {}
356
- @dummy = Dummy.new
357
- @file = StringIO.new("...")
358
- end
359
- should "not raise when assigned to" do
360
- @dummy.avatar = @file
361
- end
362
- end
363
-
364
380
  context "Assigning an attachment with post_process hooks" do
365
381
  setup do
366
382
  rebuild_model :styles => { :something => "100x100#" }
@@ -462,6 +478,8 @@ class AttachmentTest < Test::Unit::TestCase
462
478
  @attachment.expects(:valid_assignment?).with(@not_file).returns(true)
463
479
  @attachment.expects(:queue_existing_for_delete)
464
480
  @attachment.expects(:post_process)
481
+ @attachment.expects(:valid?).returns(true)
482
+ @attachment.expects(:validate)
465
483
  @dummy.avatar = @not_file
466
484
  end
467
485
 
@@ -480,7 +498,6 @@ class AttachmentTest < Test::Unit::TestCase
480
498
  FileUtils.rm_rf("tmp")
481
499
  rebuild_model
482
500
  @instance = Dummy.new
483
- @instance.stubs(:id).returns 123
484
501
  @attachment = Paperclip::Attachment.new(:avatar, @instance)
485
502
  @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
486
503
  end
@@ -589,7 +606,6 @@ class AttachmentTest < Test::Unit::TestCase
589
606
  should "commit the files to disk" do
590
607
  [:large, :medium, :small].each do |style|
591
608
  io = @attachment.to_file(style)
592
- # p "in commit to disk test, io is #{io.inspect} and @instance.id is #{@instance.id}"
593
609
  assert File.exists?(io)
594
610
  assert ! io.is_a?(::Tempfile)
595
611
  io.close
@@ -3,7 +3,7 @@ require 'test/unit'
3
3
  require 'shoulda'
4
4
  require 'tempfile'
5
5
 
6
- gem 'jferris-mocha'
6
+ gem 'jferris-mocha', '0.9.5.0.1241126838'
7
7
  require 'mocha'
8
8
 
9
9
  gem 'sqlite3-ruby'
@@ -58,15 +58,8 @@ class IOStreamTest < Test::Unit::TestCase
58
58
  assert @tempfile = @file.to_tempfile
59
59
  end
60
60
 
61
- should "convert it to a Paperclip Tempfile" do
62
- assert @tempfile.is_a?(Paperclip::Tempfile)
63
- end
64
-
65
- should "have the name be based on the original_filename" do
66
- name = File.basename(@file.path)
67
- extension = File.extname(name)
68
- basename = File.basename(name, extension)
69
- assert_match %r[^#{Regexp.quote(basename)}.*?#{Regexp.quote(extension)}], File.basename(@tempfile.path)
61
+ should "convert it to a Tempfile" do
62
+ assert @tempfile.is_a?(Tempfile)
70
63
  end
71
64
 
72
65
  should "have the Tempfile contain the same data as the file" do
@@ -5,7 +5,6 @@ class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase
5
5
  setup do
6
6
  reset_table("dummies") do |d|
7
7
  d.string :avatar_file_name
8
- d.string :avatar_content_type
9
8
  end
10
9
  @dummy_class = reset_class "Dummy"
11
10
  @dummy_class.has_attached_file :avatar
@@ -3,9 +3,7 @@ require 'test/helper'
3
3
  class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase
4
4
  context "validate_attachment_presence" do
5
5
  setup do
6
- reset_table("dummies") do |d|
7
- d.string :avatar_file_name
8
- end
6
+ reset_table("dummies"){|d| d.string :avatar_file_name }
9
7
  @dummy_class = reset_class "Dummy"
10
8
  @dummy_class.has_attached_file :avatar
11
9
  @matcher = self.class.validate_attachment_presence(:avatar)
@@ -5,7 +5,6 @@ class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase
5
5
  setup do
6
6
  reset_table("dummies") do |d|
7
7
  d.string :avatar_file_name
8
- d.integer :avatar_file_size
9
8
  end
10
9
  @dummy_class = reset_class "Dummy"
11
10
  @dummy_class.has_attached_file :avatar
@@ -185,23 +185,45 @@ class PaperclipTest < Test::Unit::TestCase
185
185
  should "be valid" do
186
186
  assert @dummy.valid?
187
187
  end
188
+
189
+ context "then has a validation added that makes it invalid" do
190
+ setup do
191
+ assert @dummy.save
192
+ Dummy.class_eval do
193
+ validates_attachment_content_type :avatar, :content_type => ["text/plain"]
194
+ end
195
+ @dummy2 = Dummy.find(@dummy.id)
196
+ end
197
+
198
+ should "be invalid when reloaded" do
199
+ assert ! @dummy2.valid?, @dummy2.errors.inspect
200
+ end
201
+
202
+ should "be able to call #valid? twice without having duplicate errors" do
203
+ @dummy2.avatar.valid?
204
+ first_errors = @dummy2.avatar.errors
205
+ @dummy2.avatar.valid?
206
+ assert_equal first_errors, @dummy2.avatar.errors
207
+ end
208
+ end
188
209
  end
189
210
 
190
211
  context "a validation with an if guard clause" do
191
212
  setup do
192
213
  Dummy.send(:"validates_attachment_presence", :avatar, :if => lambda{|i| i.foo })
193
214
  @dummy = Dummy.new
194
- @dummy.stubs(:avatar_file_name).returns(nil)
195
215
  end
196
216
 
197
217
  should "attempt validation if the guard returns true" do
198
218
  @dummy.expects(:foo).returns(true)
199
- assert ! @dummy.valid?
219
+ @dummy.avatar.expects(:validate_presence).returns(nil)
220
+ @dummy.valid?
200
221
  end
201
222
 
202
223
  should "not attempt validation if the guard returns false" do
203
224
  @dummy.expects(:foo).returns(false)
204
- assert @dummy.valid?
225
+ @dummy.avatar.expects(:validate_presence).never
226
+ @dummy.valid?
205
227
  end
206
228
  end
207
229
 
@@ -209,17 +231,18 @@ class PaperclipTest < Test::Unit::TestCase
209
231
  setup do
210
232
  Dummy.send(:"validates_attachment_presence", :avatar, :unless => lambda{|i| i.foo })
211
233
  @dummy = Dummy.new
212
- @dummy.stubs(:avatar_file_name).returns(nil)
213
234
  end
214
235
 
215
236
  should "attempt validation if the guard returns true" do
216
237
  @dummy.expects(:foo).returns(false)
217
- assert ! @dummy.valid?
238
+ @dummy.avatar.expects(:validate_presence).returns(nil)
239
+ @dummy.valid?
218
240
  end
219
241
 
220
242
  should "not attempt validation if the guard returns false" do
221
243
  @dummy.expects(:foo).returns(true)
222
- assert @dummy.valid?
244
+ @dummy.avatar.expects(:validate_presence).never
245
+ @dummy.valid?
223
246
  end
224
247
  end
225
248
 
@@ -236,11 +259,11 @@ class PaperclipTest < Test::Unit::TestCase
236
259
  end
237
260
  if validation == :presence
238
261
  should "have an error on the attachment" do
239
- assert @dummy.errors.on(:avatar_file_name)
262
+ assert @dummy.errors.on(:avatar)
240
263
  end
241
264
  else
242
265
  should "not have an error on the attachment" do
243
- assert_nil @dummy.errors.on(:avatar_file_name), @dummy.errors.full_messages.join(", ")
266
+ assert_nil @dummy.errors.on(:avatar)
244
267
  end
245
268
  end
246
269
  end
@@ -250,7 +273,10 @@ class PaperclipTest < Test::Unit::TestCase
250
273
  @dummy.valid?
251
274
  end
252
275
  should "not have an error when assigned a valid file" do
253
- assert_equal 0, @dummy.errors.length, @dummy.errors.full_messages.join(", ")
276
+ assert ! @dummy.avatar.errors.key?(validation)
277
+ end
278
+ should "not have an error on the attachment" do
279
+ assert_nil @dummy.errors.on(:avatar)
254
280
  end
255
281
  end
256
282
  context "and assigned an invalid file" do
@@ -259,14 +285,17 @@ class PaperclipTest < Test::Unit::TestCase
259
285
  @dummy.valid?
260
286
  end
261
287
  should "have an error when assigned a valid file" do
262
- assert @dummy.errors.length > 0
288
+ assert_not_nil @dummy.avatar.errors[validation]
289
+ end
290
+ should "have an error on the attachment" do
291
+ assert @dummy.errors.on(:avatar)
263
292
  end
264
293
  end
265
294
  end
266
295
  end
267
296
 
268
297
  [[:presence, {}, "5k.png", nil],
269
- [:size, {:in => 1..10240}, "5k.png", "12k.png"],
298
+ [:size, {:in => 1..10240}, nil, "12k.png"],
270
299
  [:size, {:less_than => 10240}, "5k.png", "12k.png"],
271
300
  [:size, {:greater_than => 8096}, "12k.png", "5k.png"],
272
301
  [:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"],
@@ -289,7 +318,7 @@ class PaperclipTest < Test::Unit::TestCase
289
318
  end
290
319
 
291
320
  should "have a file size min/max error message" do
292
- assert_match %r/between 0 and 10240 bytes/, @dummy.errors.on(:avatar_file_size)
321
+ assert_match /between 0 and 10240 bytes/, @dummy.errors.on(:avatar)
293
322
  end
294
323
  end
295
324
  end
@@ -96,33 +96,6 @@ class StorageTest < Test::Unit::TestCase
96
96
  assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url
97
97
  end
98
98
  end
99
-
100
- context "Generating a url with an expiration" do
101
- setup do
102
- AWS::S3::Base.stubs(:establish_connection!)
103
- rebuild_model :storage => :s3,
104
- :s3_credentials => {
105
- :production => { :bucket => "prod_bucket" },
106
- :development => { :bucket => "dev_bucket" }
107
- },
108
- :s3_host_alias => "something.something.com",
109
- :path => ":attachment/:basename.:extension",
110
- :url => ":s3_alias_url"
111
-
112
- rails_env("production")
113
-
114
- @dummy = Dummy.new
115
- @dummy.avatar = StringIO.new(".")
116
-
117
- AWS::S3::S3Object.expects(:url_for).with("avatars/stringio.txt", "prod_bucket", { :expires_in => 3600 })
118
-
119
- @dummy.avatar.expiring_url
120
- end
121
-
122
- should "should succeed" do
123
- assert true
124
- end
125
- end
126
99
 
127
100
  context "Parsing S3 credentials with a bucket in them" do
128
101
  setup do
@@ -200,7 +200,7 @@ class ThumbnailTest < Test::Unit::TestCase
200
200
  teardown { @file.close }
201
201
 
202
202
  should "start with two pages with dimensions 612x792" do
203
- cmd = %Q[identify -format "%wx%h" "#{@file.path}"]
203
+ cmd = %Q[identify -format "%wx%h" "#{@file.path}"]
204
204
  assert_equal "612x792"*2, `#{cmd}`.chomp
205
205
  end
206
206
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bteitelb-paperclip
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.1.13
4
+ version: 2.3.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Yurek
@@ -100,7 +100,6 @@ files:
100
100
  - lib/paperclip/matchers.rb
101
101
  - lib/paperclip/processor.rb
102
102
  - lib/paperclip/storage.rb
103
- - lib/paperclip/style.rb
104
103
  - lib/paperclip/thumbnail.rb
105
104
  - lib/paperclip/upfile.rb
106
105
  - lib/paperclip.rb
@@ -1,90 +0,0 @@
1
- # encoding: utf-8
2
- module Paperclip
3
- # The Style class holds the definition of a thumbnail style, applying
4
- # whatever processing is required to normalize the definition and delaying
5
- # the evaluation of block parameters until useful context is available.
6
-
7
- class Style
8
-
9
- attr_reader :name, :attachment, :format
10
-
11
- # Creates a Style object. +name+ is the name of the attachment,
12
- # +definition+ is the style definition from has_attached_file, which
13
- # can be string, array or hash
14
- def initialize name, definition, attachment
15
- @name = name
16
- @attachment = attachment
17
- if definition.is_a? Hash
18
- @geometry = definition.delete(:geometry)
19
- @format = definition.delete(:format)
20
- @processors = definition.delete(:processors)
21
- @other_args = definition
22
- else
23
- @geometry, @format = [definition, nil].flatten[0..1]
24
- @other_args = {}
25
- end
26
- @format = nil if @format.blank?
27
- end
28
-
29
- # retrieves from the attachment the processors defined in the has_attached_file call
30
- # (which method (in the attachment) will call any supplied procs)
31
- # There is an important change of interface here: a style rule can set its own processors
32
- # by default we behave as before, though.
33
- def processors
34
- @processors || attachment.processors
35
- end
36
-
37
- # retrieves from the attachment the whiny setting
38
- def whiny
39
- attachment.whiny
40
- end
41
-
42
- # returns true if we're inclined to grumble
43
- def whiny?
44
- !!whiny
45
- end
46
-
47
- def convert_options
48
- attachment.send(:extra_options_for, name)
49
- end
50
-
51
- # returns the geometry string for this style
52
- # if a proc has been supplied, we call it here
53
- def geometry
54
- @geometry.respond_to?(:call) ? @geometry.call(attachment.instance) : @geometry
55
- end
56
-
57
- # Supplies the hash of options that processors expect to receive as their second argument
58
- # Arguments other than the standard geometry, format etc are just passed through from
59
- # initialization and any procs are called here, just before post-processing.
60
- def processor_options
61
- args = {}
62
- @other_args.each do |k,v|
63
- args[k] = v.respond_to?(:call) ? v.call(attachment) : v
64
- end
65
- [:processors, :geometry, :format, :whiny, :convert_options].each do |k|
66
- (arg = send(k)) && args[k] = arg
67
- end
68
- args
69
- end
70
-
71
- # Supports getting and setting style properties with hash notation to ensure backwards-compatibility
72
- # eg. @attachment.styles[:large][:geometry]@ will still work
73
- def [](key)
74
- if [:name, :convert_options, :whiny, :processors, :geometry, :format].include?(key)
75
- send(key)
76
- elsif defined? @other_args[key]
77
- @other_args[key]
78
- end
79
- end
80
-
81
- def []=(key, value)
82
- if [:name, :convert_options, :whiny, :processors, :geometry, :format].include?(key)
83
- send("#{key}=".intern, value)
84
- else
85
- @other_args[key] = value
86
- end
87
- end
88
-
89
- end
90
- end