bteitelb-paperclip 2.3.1.13 → 2.3.1.14

Sign up to get free protection for your applications and to get access to all the features.
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