paperclip-v2_7-patched-ruby-1_8_6 2.7.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +14 -0
  4. data/Appraisals +20 -0
  5. data/CONTRIBUTING.md +38 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE +26 -0
  8. data/NEWS +69 -0
  9. data/README.md +444 -0
  10. data/Rakefile +41 -0
  11. data/cucumber/paperclip_steps.rb +6 -0
  12. data/features/basic_integration.feature +48 -0
  13. data/features/rake_tasks.feature +68 -0
  14. data/features/step_definitions/attachment_steps.rb +65 -0
  15. data/features/step_definitions/html_steps.rb +15 -0
  16. data/features/step_definitions/rails_steps.rb +193 -0
  17. data/features/step_definitions/s3_steps.rb +14 -0
  18. data/features/step_definitions/web_steps.rb +209 -0
  19. data/features/support/env.rb +8 -0
  20. data/features/support/fakeweb.rb +3 -0
  21. data/features/support/fixtures/.boot_config.rb.swo +0 -0
  22. data/features/support/fixtures/boot_config.txt +15 -0
  23. data/features/support/fixtures/gemfile.txt +5 -0
  24. data/features/support/fixtures/preinitializer.txt +20 -0
  25. data/features/support/paths.rb +28 -0
  26. data/features/support/rails.rb +46 -0
  27. data/features/support/selectors.rb +19 -0
  28. data/gemfiles/rails2.gemfile +9 -0
  29. data/gemfiles/rails3.gemfile +9 -0
  30. data/gemfiles/rails3_1.gemfile +9 -0
  31. data/gemfiles/rails3_2.gemfile +9 -0
  32. data/generators/paperclip/USAGE +5 -0
  33. data/generators/paperclip/paperclip_generator.rb +27 -0
  34. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  35. data/init.rb +4 -0
  36. data/lib/generators/paperclip/USAGE +8 -0
  37. data/lib/generators/paperclip/paperclip_generator.rb +33 -0
  38. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  39. data/lib/paperclip.rb +493 -0
  40. data/lib/paperclip/attachment.rb +491 -0
  41. data/lib/paperclip/attachment_options.rb +10 -0
  42. data/lib/paperclip/callback_compatibility.rb +61 -0
  43. data/lib/paperclip/geometry.rb +120 -0
  44. data/lib/paperclip/interpolations.rb +174 -0
  45. data/lib/paperclip/iostream.rb +45 -0
  46. data/lib/paperclip/matchers.rb +64 -0
  47. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  48. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
  49. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  50. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  51. data/lib/paperclip/missing_attachment_styles.rb +87 -0
  52. data/lib/paperclip/processor.rb +58 -0
  53. data/lib/paperclip/railtie.rb +35 -0
  54. data/lib/paperclip/schema.rb +39 -0
  55. data/lib/paperclip/storage.rb +3 -0
  56. data/lib/paperclip/storage/filesystem.rb +81 -0
  57. data/lib/paperclip/storage/fog.rb +191 -0
  58. data/lib/paperclip/storage/s3.rb +351 -0
  59. data/lib/paperclip/style.rb +103 -0
  60. data/lib/paperclip/thumbnail.rb +105 -0
  61. data/lib/paperclip/upfile.rb +64 -0
  62. data/lib/paperclip/url_generator.rb +64 -0
  63. data/lib/paperclip/version.rb +3 -0
  64. data/lib/tasks/paperclip.rake +101 -0
  65. data/paperclip.gemspec +41 -0
  66. data/rails/init.rb +2 -0
  67. data/shoulda_macros/paperclip.rb +124 -0
  68. data/test/attachment_options_test.rb +40 -0
  69. data/test/attachment_test.rb +1211 -0
  70. data/test/database.yml +4 -0
  71. data/test/fixtures/12k.png +0 -0
  72. data/test/fixtures/50x50.png +0 -0
  73. data/test/fixtures/5k.png +0 -0
  74. data/test/fixtures/animated.gif +0 -0
  75. data/test/fixtures/bad.png +1 -0
  76. data/test/fixtures/fog.yml +8 -0
  77. data/test/fixtures/s3.yml +8 -0
  78. data/test/fixtures/spaced file.png +0 -0
  79. data/test/fixtures/text.txt +1 -0
  80. data/test/fixtures/twopage.pdf +0 -0
  81. data/test/fixtures/uppercase.PNG +0 -0
  82. data/test/geometry_test.rb +206 -0
  83. data/test/helper.rb +181 -0
  84. data/test/integration_test.rb +652 -0
  85. data/test/interpolations_test.rb +219 -0
  86. data/test/iostream_test.rb +71 -0
  87. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  88. data/test/matchers/validate_attachment_content_type_matcher_test.rb +110 -0
  89. data/test/matchers/validate_attachment_presence_matcher_test.rb +47 -0
  90. data/test/matchers/validate_attachment_size_matcher_test.rb +72 -0
  91. data/test/paperclip_missing_attachment_styles_test.rb +96 -0
  92. data/test/paperclip_test.rb +409 -0
  93. data/test/processor_test.rb +10 -0
  94. data/test/schema_test.rb +98 -0
  95. data/test/storage/filesystem_test.rb +62 -0
  96. data/test/storage/fog_test.rb +280 -0
  97. data/test/storage/s3_live_test.rb +138 -0
  98. data/test/storage/s3_test.rb +1093 -0
  99. data/test/style_test.rb +215 -0
  100. data/test/support/mock_attachment.rb +22 -0
  101. data/test/support/mock_interpolator.rb +24 -0
  102. data/test/support/mock_model.rb +2 -0
  103. data/test/support/mock_url_generator_builder.rb +27 -0
  104. data/test/thumbnail_test.rb +396 -0
  105. data/test/upfile_test.rb +53 -0
  106. data/test/url_generator_test.rb +187 -0
  107. metadata +374 -0
@@ -0,0 +1,491 @@
1
+ # encoding: utf-8
2
+ require 'uri'
3
+ require 'paperclip/url_generator'
4
+
5
+ module Paperclip
6
+ # The Attachment class manages the files for a given attachment. It saves
7
+ # when the model saves, deletes when the model is destroyed, and processes
8
+ # the file upon assignment.
9
+ class Attachment
10
+ include IOStream
11
+
12
+ def self.default_options
13
+ @default_options ||= {
14
+ :convert_options => {},
15
+ :default_style => :original,
16
+ :default_url => "/:attachment/:style/missing.png",
17
+ :escape_url => true,
18
+ :restricted_characters => /[&$+,\/:;=?@<>\[\]\{\}\|\\\^~%# ]/,
19
+ :hash_data => ":class/:attachment/:id/:style/:updated_at",
20
+ :hash_digest => "SHA1",
21
+ :interpolator => Paperclip::Interpolations,
22
+ :only_process => [],
23
+ :path => ":rails_root/public:url",
24
+ :preserve_files => false,
25
+ :processors => [:thumbnail],
26
+ :source_file_options => {},
27
+ :storage => :filesystem,
28
+ :styles => {},
29
+ :url => "/system/:attachment/:id/:style/:filename",
30
+ :url_generator => Paperclip::UrlGenerator,
31
+ :use_default_time_zone => true,
32
+ :use_timestamp => true,
33
+ :whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails]
34
+ }
35
+ end
36
+
37
+ attr_reader :name, :instance, :default_style, :convert_options, :queued_for_write, :whiny,
38
+ :options, :interpolator, :source_file_options, :whiny
39
+ attr_accessor :post_processing
40
+
41
+ # Creates an Attachment object. +name+ is the name of the attachment,
42
+ # +instance+ is the ActiveRecord object instance it's attached to, and
43
+ # +options+ is the same as the hash passed to +has_attached_file+.
44
+ #
45
+ # Options include:
46
+ #
47
+ # +url+ - a relative URL of the attachment. This is interpolated using +interpolator+
48
+ # +path+ - where on the filesystem to store the attachment. This is interpolated using +interpolator+
49
+ # +styles+ - a hash of options for processing the attachment. See +has_attached_file+ for the details
50
+ # +only_process+ - style args to be run through the post-processor. This defaults to the empty list
51
+ # +default_url+ - a URL for the missing image
52
+ # +default_style+ - the style to use when don't specify an argument to e.g. #url, #path
53
+ # +storage+ - the storage mechanism. Defaults to :filesystem
54
+ # +use_timestamp+ - whether to append an anti-caching timestamp to image URLs. Defaults to true
55
+ # +whiny+, +whiny_thumbnails+ - whether to raise when thumbnailing fails
56
+ # +use_default_time_zone+ - related to +use_timestamp+. Defaults to true
57
+ # +hash_digest+ - a string representing a class that will be used to hash URLs for obfuscation
58
+ # +hash_data+ - the relative URL for the hash data. This is interpolated using +interpolator+
59
+ # +hash_secret+ - a secret passed to the +hash_digest+
60
+ # +convert_options+ - flags passed to the +convert+ command for processing
61
+ # +source_file_options+ - flags passed to the +convert+ command that controls how the file is read
62
+ # +processors+ - classes that transform the attachment. Defaults to [:thumbnail]
63
+ # +preserve_files+ - whether to keep files on the filesystem when deleting to clearing the attachment. Defaults to false
64
+ # +interpolator+ - the object used to interpolate filenames and URLs. Defaults to Paperclip::Interpolations
65
+ # +url_generator+ - the object used to generate URLs, using the interpolator. Defaults to Paperclip::UrlGenerator
66
+ # +escape_url+ - Perform URI escaping to URLs. Defaults to true
67
+ def initialize(name, instance, options = {})
68
+ @name = name
69
+ @instance = instance
70
+
71
+ options = self.class.default_options.merge(options)
72
+
73
+ @options = options
74
+ @post_processing = true
75
+ @queued_for_delete = []
76
+ @queued_for_write = {}
77
+ @errors = {}
78
+ @dirty = false
79
+ @interpolator = options[:interpolator]
80
+ @url_generator = options[:url_generator].new(self, @options)
81
+ @source_file_options = options[:source_file_options]
82
+ @whiny = options[:whiny]
83
+
84
+ initialize_storage
85
+ end
86
+
87
+ # What gets called when you call instance.attachment = File. It clears
88
+ # errors, assigns attributes, and processes the file. It
89
+ # also queues up the previous file for deletion, to be flushed away on
90
+ # #save of its host. In addition to form uploads, you can also assign
91
+ # another Paperclip attachment:
92
+ # new_user.avatar = old_user.avatar
93
+ def assign uploaded_file
94
+ ensure_required_accessors!
95
+
96
+ if uploaded_file.is_a?(Paperclip::Attachment)
97
+ uploaded_filename = uploaded_file.original_filename
98
+ uploaded_file = uploaded_file.to_file(:original)
99
+ close_uploaded_file = uploaded_file.respond_to?(:close)
100
+ else
101
+ instance_write(:uploaded_file, uploaded_file) if uploaded_file
102
+ end
103
+
104
+ return nil unless valid_assignment?(uploaded_file)
105
+
106
+ uploaded_file.binmode if uploaded_file.respond_to? :binmode
107
+ self.clear
108
+
109
+ return nil if uploaded_file.nil?
110
+
111
+ uploaded_filename ||= uploaded_file.original_filename
112
+ stores_fingerprint = @instance.respond_to?("#{name}_fingerprint".to_sym)
113
+ @queued_for_write[:original] = to_tempfile(uploaded_file)
114
+ instance_write(:file_name, cleanup_filename(uploaded_filename.strip))
115
+ instance_write(:content_type, uploaded_file.content_type.to_s.strip)
116
+ instance_write(:file_size, uploaded_file.size.to_i)
117
+ instance_write(:fingerprint, generate_fingerprint(uploaded_file)) if stores_fingerprint
118
+ instance_write(:updated_at, Time.now)
119
+
120
+ @dirty = true
121
+
122
+ post_process(*@options[:only_process]) if post_processing
123
+
124
+ # Reset the file size if the original file was reprocessed.
125
+ instance_write(:file_size, @queued_for_write[:original].size.to_i)
126
+ instance_write(:fingerprint, generate_fingerprint(@queued_for_write[:original])) if stores_fingerprint
127
+ ensure
128
+ uploaded_file.close if close_uploaded_file
129
+ end
130
+
131
+ # Returns the public URL of the attachment with a given style. This does
132
+ # not necessarily need to point to a file that your Web server can access
133
+ # and can instead point to an action in your app, for example for fine grained
134
+ # security; this has a serious performance tradeoff.
135
+ #
136
+ # Options:
137
+ #
138
+ # +timestamp+ - Add a timestamp to the end of the URL. Default: true.
139
+ # +escape+ - Perform URI escaping to the URL. Default: true.
140
+ #
141
+ # Global controls (set on has_attached_file):
142
+ #
143
+ # +interpolator+ - The object that fills in a URL pattern's variables.
144
+ # +default_url+ - The image to show when the attachment has no image.
145
+ # +url+ - The URL for a saved image.
146
+ # +url_generator+ - The object that generates a URL. Default: Paperclip::UrlGenerator.
147
+ #
148
+ # As mentioned just above, the object that generates this URL can be passed
149
+ # in, for finer control. This object must respond to two methods:
150
+ #
151
+ # +#new(Paperclip::Attachment, options_hash)+
152
+ # +#for(style_name, options_hash)+
153
+ def url(style_name = default_style, options = {})
154
+ default_options = {:timestamp => @options[:use_timestamp], :escape => @options[:escape_url]}
155
+
156
+ if options == true || options == false # Backwards compatibility.
157
+ @url_generator.for(style_name, default_options.merge(:timestamp => options))
158
+ else
159
+ @url_generator.for(style_name, default_options.merge(options))
160
+ end
161
+ end
162
+
163
+ # Returns the path of the attachment as defined by the :path option. If the
164
+ # file is stored in the filesystem the path refers to the path of the file
165
+ # on disk. If the file is stored in S3, the path is the "key" part of the
166
+ # URL, and the :bucket option refers to the S3 bucket.
167
+ def path(style_name = default_style)
168
+ path = original_filename.nil? ? nil : interpolate(path_option, style_name)
169
+ path.respond_to?(:unescape) ? path.unescape : path
170
+ end
171
+
172
+ # Alias to +url+
173
+ def to_s style_name = default_style
174
+ url(style_name)
175
+ end
176
+
177
+ def default_style
178
+ @options[:default_style]
179
+ end
180
+
181
+ def styles
182
+ styling_option = @options[:styles]
183
+ if styling_option.respond_to?(:call) || !@normalized_styles
184
+ @normalized_styles = ActiveSupport::OrderedHash.new
185
+ (styling_option.respond_to?(:call) ? styling_option.call(self) : styling_option).each do |name, args|
186
+ @normalized_styles[name] = Paperclip::Style.new(name, args.dup, self)
187
+ end
188
+ end
189
+ @normalized_styles
190
+ end
191
+
192
+ def processors
193
+ processing_option = @options[:processors]
194
+
195
+ if processing_option.respond_to?(:call)
196
+ processing_option.call(instance)
197
+ else
198
+ processing_option
199
+ end
200
+ end
201
+
202
+ # Returns an array containing the errors on this attachment.
203
+ def errors
204
+ @errors
205
+ end
206
+
207
+ # Returns true if there are changes that need to be saved.
208
+ def dirty?
209
+ @dirty
210
+ end
211
+
212
+ # Saves the file, if there are no errors. If there are, it flushes them to
213
+ # the instance's errors and returns false, cancelling the save.
214
+ def save
215
+ flush_deletes unless @options[:keep_old_files]
216
+ flush_writes
217
+ @dirty = false
218
+ true
219
+ end
220
+
221
+ # Clears out the attachment. Has the same effect as previously assigning
222
+ # nil to the attachment. Does NOT save. If you wish to clear AND save,
223
+ # use #destroy.
224
+ def clear
225
+ queue_existing_for_delete
226
+ @queued_for_write = {}
227
+ @errors = {}
228
+ end
229
+
230
+ # Destroys the attachment. Has the same effect as previously assigning
231
+ # nil to the attachment *and saving*. This is permanent. If you wish to
232
+ # wipe out the existing attachment but not save, use #clear.
233
+ def destroy
234
+ unless @options[:preserve_files]
235
+ clear
236
+ save
237
+ end
238
+ end
239
+
240
+ # Returns the uploaded file if present.
241
+ def uploaded_file
242
+ instance_read(:uploaded_file)
243
+ end
244
+
245
+ # Returns the name of the file as originally assigned, and lives in the
246
+ # <attachment>_file_name attribute of the model.
247
+ def original_filename
248
+ instance_read(:file_name)
249
+ end
250
+
251
+ # Returns the size of the file as originally assigned, and lives in the
252
+ # <attachment>_file_size attribute of the model.
253
+ def size
254
+ instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size)
255
+ end
256
+
257
+ # Returns the hash of the file as originally assigned, and lives in the
258
+ # <attachment>_fingerprint attribute of the model.
259
+ def fingerprint
260
+ if instance_read(:fingerprint)
261
+ instance_read(:fingerprint)
262
+ elsif @instance.respond_to?("#{name}_fingerprint".to_sym)
263
+ @queued_for_write[:original] && generate_fingerprint(@queued_for_write[:original])
264
+ else
265
+ nil
266
+ end
267
+ end
268
+
269
+ # Returns the content_type of the file as originally assigned, and lives
270
+ # in the <attachment>_content_type attribute of the model.
271
+ def content_type
272
+ instance_read(:content_type)
273
+ end
274
+
275
+ # Returns the last modified time of the file as originally assigned, and
276
+ # lives in the <attachment>_updated_at attribute of the model.
277
+ def updated_at
278
+ time = instance_read(:updated_at)
279
+ time && time.to_f.to_i
280
+ end
281
+
282
+ # The time zone to use for timestamp interpolation. Using the default
283
+ # time zone ensures that results are consistent across all threads.
284
+ def time_zone
285
+ @options[:use_default_time_zone] ? Time.zone_default : Time.zone
286
+ end
287
+
288
+ # Returns a unique hash suitable for obfuscating the URL of an otherwise
289
+ # publicly viewable attachment.
290
+ def hash_key(style_name = default_style)
291
+ raise ArgumentError, "Unable to generate hash without :hash_secret" unless @options[:hash_secret]
292
+ require 'openssl' unless defined?(OpenSSL)
293
+ data = interpolate(@options[:hash_data], style_name)
294
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@options[:hash_digest]).new, @options[:hash_secret], data)
295
+ end
296
+
297
+ def generate_fingerprint(source)
298
+ if source.respond_to?(:path) && source.path && !source.path.blank?
299
+ Digest::MD5.file(source.path).to_s
300
+ else
301
+ data = source.read
302
+ source.rewind if source.respond_to?(:rewind)
303
+ Digest::MD5.hexdigest(data)
304
+ end
305
+ end
306
+
307
+ # Paths and URLs can have a number of variables interpolated into them
308
+ # to vary the storage location based on name, id, style, class, etc.
309
+ # This method is a deprecated access into supplying and retrieving these
310
+ # interpolations. Future access should use either Paperclip.interpolates
311
+ # or extend the Paperclip::Interpolations module directly.
312
+ def self.interpolations
313
+ warn('[DEPRECATION] Paperclip::Attachment.interpolations is deprecated ' +
314
+ 'and will be removed from future versions. ' +
315
+ 'Use Paperclip.interpolates instead')
316
+ Paperclip::Interpolations
317
+ end
318
+
319
+ # This method really shouldn't be called that often. It's expected use is
320
+ # in the paperclip:refresh rake task and that's it. It will regenerate all
321
+ # thumbnails forcefully, by reobtaining the original file and going through
322
+ # the post-process again.
323
+ def reprocess!(*style_args)
324
+ new_original = Tempfile.new("paperclip-reprocess")
325
+ new_original.binmode
326
+ if old_original = to_file(:original)
327
+ new_original.write( old_original.respond_to?(:get) ? old_original.get : old_original.read )
328
+ new_original.rewind
329
+
330
+ @queued_for_write = { :original => new_original }
331
+ instance_write(:updated_at, Time.now)
332
+ post_process(*style_args)
333
+
334
+ old_original.close if old_original.respond_to?(:close)
335
+ old_original.unlink if old_original.respond_to?(:unlink)
336
+
337
+ save
338
+ else
339
+ true
340
+ end
341
+ rescue Errno::EACCES => e
342
+ warn "#{e} - skipping file"
343
+ false
344
+ end
345
+
346
+ # Returns true if a file has been assigned.
347
+ def file?
348
+ !original_filename.blank?
349
+ end
350
+
351
+ alias :present? :file?
352
+
353
+ # Writes the attachment-specific attribute on the instance. For example,
354
+ # instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's
355
+ # "avatar_file_name" field (assuming the attachment is called avatar).
356
+ def instance_write(attr, value)
357
+ setter = :"#{name}_#{attr}="
358
+ responds = instance.respond_to?(setter)
359
+ self.instance_variable_set("@_#{setter.to_s.chop}", value)
360
+ instance.send(setter, value) if responds || attr.to_s == "file_name"
361
+ end
362
+
363
+ # Reads the attachment-specific attribute on the instance. See instance_write
364
+ # for more details.
365
+ def instance_read(attr)
366
+ getter = :"#{name}_#{attr}"
367
+ responds = instance.respond_to?(getter)
368
+ cached = self.instance_variable_get("@_#{getter}")
369
+ return cached if cached
370
+ instance.send(getter) if responds || attr.to_s == "file_name"
371
+ end
372
+
373
+ private
374
+
375
+ def path_option
376
+ @options[:path].respond_to?(:call) ? @options[:path].call(self) : @options[:path]
377
+ end
378
+
379
+ def ensure_required_accessors! #:nodoc:
380
+ %w(file_name).each do |field|
381
+ unless @instance.respond_to?("#{name}_#{field}") && @instance.respond_to?("#{name}_#{field}=")
382
+ raise PaperclipError.new("#{@instance.class} model missing required attr_accessor for '#{name}_#{field}'")
383
+ end
384
+ end
385
+ end
386
+
387
+ def log message #:nodoc:
388
+ Paperclip.log(message)
389
+ end
390
+
391
+ def valid_assignment? file #:nodoc:
392
+ file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type))
393
+ end
394
+
395
+ def initialize_storage #:nodoc:
396
+ storage_class_name = @options[:storage].to_s.downcase.camelize
397
+ begin
398
+ storage_module = Paperclip::Storage.const_get(storage_class_name)
399
+ rescue NameError
400
+ raise StorageMethodNotFound, "Cannot load storage module '#{storage_class_name}'"
401
+ end
402
+ self.extend(storage_module)
403
+ end
404
+
405
+ def extra_options_for(style) #:nodoc:
406
+ all_options = @options[:convert_options][:all]
407
+ all_options = all_options.call(instance) if all_options.respond_to?(:call)
408
+ style_options = @options[:convert_options][style]
409
+ style_options = style_options.call(instance) if style_options.respond_to?(:call)
410
+
411
+ [ style_options, all_options ].compact.join(" ")
412
+ end
413
+
414
+ def extra_source_file_options_for(style) #:nodoc:
415
+ all_options = @options[:source_file_options][:all]
416
+ all_options = all_options.call(instance) if all_options.respond_to?(:call)
417
+ style_options = @options[:source_file_options][style]
418
+ style_options = style_options.call(instance) if style_options.respond_to?(:call)
419
+
420
+ [ style_options, all_options ].compact.join(" ")
421
+ end
422
+
423
+ def post_process(*style_args) #:nodoc:
424
+ return if @queued_for_write[:original].nil?
425
+ instance.run_paperclip_callbacks(:post_process) do
426
+ instance.run_paperclip_callbacks(:"#{name}_post_process") do
427
+ post_process_styles(*style_args)
428
+ end
429
+ end
430
+ end
431
+
432
+ def post_process_styles(*style_args) #:nodoc:
433
+ post_process_style(:original, styles[:original]) if styles.include?(:original) && process_style?(:original, style_args)
434
+ styles.reject{ |name, style| name == :original }.each do |name, style|
435
+ post_process_style(name, style) if process_style?(name, style_args)
436
+ end
437
+ end
438
+
439
+ def post_process_style(name, style) #:nodoc:
440
+ begin
441
+ raise RuntimeError.new("Style #{name} has no processors defined.") if style.processors.blank?
442
+ @queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
443
+ Paperclip.processor(processor).make(file, style.processor_options, self)
444
+ end
445
+ rescue PaperclipError => e
446
+ log("An error was received while processing: #{e.inspect}")
447
+ (@errors[:processing] ||= []) << e.message if @options[:whiny]
448
+ end
449
+ end
450
+
451
+ def process_style?(style_name, style_args) #:nodoc:
452
+ style_args.empty? || style_args.include?(style_name)
453
+ end
454
+
455
+ def interpolate(pattern, style_name = default_style) #:nodoc:
456
+ interpolator.interpolate(pattern, self, style_name)
457
+ end
458
+
459
+ def queue_existing_for_delete #:nodoc:
460
+ return if @options[:preserve_files] || !file?
461
+ @queued_for_delete += [:original, *styles.keys].uniq.map do |style|
462
+ path(style) if exists?(style)
463
+ end.compact
464
+ instance_write(:file_name, nil)
465
+ instance_write(:content_type, nil)
466
+ instance_write(:file_size, nil)
467
+ instance_write(:fingerprint, nil)
468
+ instance_write(:updated_at, nil)
469
+ end
470
+
471
+ def flush_errors #:nodoc:
472
+ @errors.each do |error, message|
473
+ [message].flatten.each {|m| instance.errors.add(name, m) }
474
+ end
475
+ end
476
+
477
+ # called by storage after the writes are flushed and before @queued_for_writes is cleared
478
+ def after_flush_writes
479
+ @queued_for_write.each do |style, file|
480
+ file.close unless file.closed?
481
+ file.unlink if file.respond_to?(:unlink) && file.path.present? && File.exist?(file.path)
482
+ end
483
+ end
484
+
485
+ def cleanup_filename(filename)
486
+ if @options[:restricted_characters]
487
+ filename.gsub(@options[:restricted_characters], '_')
488
+ end
489
+ end
490
+ end
491
+ end