ripta-dm-paperclip 2.2.9.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+
2
+ LICENSE
3
+
4
+ The MIT License
5
+
6
+ Copyright (c) 2008 Jon Yurek and thoughtbot, inc.
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ THE SOFTWARE.
25
+
26
+
data/README.rdoc ADDED
@@ -0,0 +1,105 @@
1
+ =DataMapper Paperclip
2
+
3
+ DM-Paperclip is a port of Thoughtbot's Paperclip plugin to work with DataMapper 0.9. This plugin is fully compatible with
4
+ the original ActiveRecord-oriented Paperclip. You could take an existing ActiveRecord database and use it with DataMapper.
5
+ The module also includes updates validation handling and automatic including of the necessary 'property' fields into
6
+ your model.
7
+
8
+ To use it within your models, you need to ensure the three database fields are included. They are {name}_file_name,
9
+ {name}_content_type, and {name}_file_size. The first two are strings, the final _file_size column is an integer. So
10
+ if your user model has an avatar field, then you would add avatar_file_name, avatar_content_type, and avatar_file_size.
11
+
12
+ As with the original Paperclip plugin, it allows processing of thumbnails at the time the record is saved though ImageMagick.
13
+ It processes the thumbnails through the command-line applications instead of using RMagick.
14
+
15
+ See the documentation for the +has_attached_file+ method for options.
16
+
17
+ ==Code
18
+
19
+ The code DM-Paperclip is available at Github:
20
+
21
+ git clone git://github.com/krobertson/dm-paperclip.git
22
+
23
+ It is regularly updated to keep in sync with the latest from Thoughtbot.
24
+
25
+ Releases are tagged within the repository and versioned the same as the original model. You can also get the latest release
26
+ packaged as a gem through Rubyforge:
27
+
28
+ sudo gem install dm-paperclip
29
+
30
+ ==Usage
31
+
32
+ In your model:
33
+
34
+ class User
35
+ include DataMapper::Resource
36
+ include Paperclip::Resource
37
+ property :id, Serial
38
+ property :username, String
39
+ has_attached_file :avatar,
40
+ :styles => { :medium => "300x300>",
41
+ :thumb => "100x100>" }
42
+ end
43
+
44
+ Your database will need to add four columns, avatar_file_name (varchar), avatar_content_type (varchar), and
45
+ avatar_file_size (integer), and avatar_updated_at (datetime). You can either add these manually, auto-
46
+ migrate, or use the following migration:
47
+
48
+ migration( 1, :add_user_paperclip_fields ) do
49
+ up do
50
+ modify_table :users do
51
+ add_column :avatar_file_name, "varchar(255)"
52
+ add_column :avatar_content_type, "varchar(255)"
53
+ add_column :avatar_file_size, "integer"
54
+ add_column :avatar_updated_at, "datetime"
55
+ end
56
+ end
57
+ down do
58
+ modify_table :users do
59
+ drop_columns :avatar_file_name, :avatar_content_type, :avatar_file_size, :avatar_updated_at
60
+ end
61
+ end
62
+ end
63
+
64
+ In your edit and new views:
65
+
66
+ <% form_for @user, { :action => url(:user), :multipart => true } do %>
67
+ <%= file_field :name => 'avatar' %>
68
+ <% end %>
69
+
70
+ In your controller:
71
+
72
+ def create
73
+ ...
74
+ @user.avatar = params[:avatar]
75
+ end
76
+
77
+ In your show view:
78
+
79
+ <%= image_tag @user.avatar.url %>
80
+ <%= image_tag @user.avatar.url(:medium) %>
81
+ <%= image_tag @user.avatar.url(:thumb) %>
82
+
83
+ The following validations are available:
84
+
85
+ validates_attachment_presence :avatar
86
+ validates_attachment_content_type :avatar, :content_type => "image/png"
87
+ validates_attachment_size :avatar, :in => 1..10240
88
+ validates_attachment_thumbnails :avatar
89
+
90
+ In order to use validations, you must have loaded the 'dm-validations' gem into your app
91
+ (available as a part of dm-more). If the gem isn't loaded before DM-Paperclip is loaded,
92
+ the validation methods will be excluded. You will also need to include DataMapper::Validate
93
+ into your mode:
94
+
95
+ class User
96
+ include DataMapper::Resource
97
+ include DataMapper::Validate
98
+ include Paperclip::Resource
99
+ property :id, Serial
100
+ property :username, String
101
+ has_attached_file :avatar,
102
+ :styles => { :medium => "300x300>",
103
+ :thumb => "100x100>" }
104
+ validates_attachment_size :avatar, :in => 1..5120
105
+ end
data/Rakefile ADDED
@@ -0,0 +1,100 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
7
+ require 'dm-core'
8
+ require 'dm-validations'
9
+ require 'dm-paperclip'
10
+
11
+ desc 'Default: run unit tests.'
12
+ task :default => [:clean, :test]
13
+
14
+ # Test tasks
15
+ desc 'Test the DM-Paperclip library.'
16
+ Rake::TestTask.new(:test) do |t|
17
+ t.libs << 'dm-paperclip'
18
+ t.pattern = 'test/**/*_test.rb'
19
+ t.verbose = true
20
+ end
21
+
22
+ # Console
23
+ desc "Open an irb session preloaded with this library"
24
+ task :console do
25
+ sh "irb -rubygems -r dm-validations -r dm-migrations -r ./lib/dm-paperclip.rb"
26
+ end
27
+
28
+ # Rdoc
29
+ desc 'Generate documentation for the paperclip plugin.'
30
+ Rake::RDocTask.new(:doc) do |rdoc|
31
+ rdoc.rdoc_dir = 'doc'
32
+ rdoc.title = 'DM-Paperclip'
33
+ rdoc.options << '--line-numbers' << '--inline-source'
34
+ rdoc.rdoc_files.include('README.rdoc')
35
+ rdoc.rdoc_files.include('lib/**/*.rb')
36
+ end
37
+
38
+ # Code coverage
39
+ task :coverage do
40
+ system("rm -fr coverage")
41
+ system("rcov test/test_*.rb")
42
+ system("open coverage/index.html")
43
+ end
44
+
45
+ # Clean house
46
+ desc 'Clean up files.'
47
+ task :clean do |t|
48
+ FileUtils.rm_rf "doc"
49
+ FileUtils.rm_rf "coverage"
50
+ FileUtils.rm_rf "tmp"
51
+ FileUtils.rm_rf "pkg"
52
+ FileUtils.rm_rf "log"
53
+ end
54
+
55
+ spec = Gem::Specification.new do |s|
56
+ s.name = "ripta-dm-paperclip"
57
+ s.version = Paperclip::VERSION
58
+ s.author = "Ken Robertson"
59
+ s.email = "ken@invalidlogic.com"
60
+ s.homepage = "http://invalidlogic.com/dm-paperclip/"
61
+ s.platform = Gem::Platform::RUBY
62
+ s.summary = "File attachments as attributes for DataMapper, based on the original Paperclip by Jon Yurek at Thoughtbot"
63
+ s.files = FileList["README.rdoc",
64
+ "LICENSE",
65
+ "Rakefile",
66
+ "init.rb",
67
+ "{lib,tasks,test}/**/*"].to_a
68
+ s.require_path = "lib"
69
+ s.test_files = FileList["test/**/test_*.rb"].to_a
70
+ s.rubyforge_project = "dm-paperclip"
71
+ s.has_rdoc = true
72
+ s.extra_rdoc_files = ["README.rdoc"]
73
+ s.rdoc_options << '--line-numbers' << '--inline-source'
74
+ s.requirements << "ImageMagick"
75
+ s.requirements << "data_mapper"
76
+ end
77
+
78
+ Rake::GemPackageTask.new(spec) do |pkg|
79
+ pkg.need_tar = true
80
+ end
81
+
82
+ WIN32 = (PLATFORM =~ /win32|cygwin/) rescue nil
83
+ SUDO = WIN32 ? '' : ('sudo' unless ENV['SUDOLESS'])
84
+
85
+ desc "Install #{spec.name} #{spec.version}"
86
+ task :install => [ :package ] do
87
+ sh "#{SUDO} gem install pkg/#{spec.name}-#{spec.version} --no-update-sources", :verbose => false
88
+ end
89
+
90
+ desc "Release new version"
91
+ task :release => [:test, :gem] do
92
+ require 'rubygems'
93
+ require 'rubyforge'
94
+ r = RubyForge.new
95
+ r.login
96
+ r.add_release spec.rubyforge_project,
97
+ spec.name,
98
+ spec.version,
99
+ File.join("pkg", "#{spec.name}-#{spec.version}.gem")
100
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), 'lib', 'dm-paperclip')
@@ -0,0 +1,413 @@
1
+ module Paperclip
2
+ # The Attachment class manages the files for a given attachment. It saves
3
+ # when the model saves, deletes when the model is destroyed, and processes
4
+ # the file upon assignment.
5
+ class Attachment
6
+
7
+ def self.default_options
8
+ @default_options ||= {
9
+ :url => "/system/:attachment/:id/:style/:filename",
10
+ :path => ":web_root/public:url",
11
+ :styles => {},
12
+ :default_url => "/:attachment/:style/missing.png",
13
+ :default_style => :original,
14
+ :validations => [],
15
+ :storage => :filesystem,
16
+ :whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails]
17
+ }
18
+ end
19
+
20
+ attr_reader :name, :instance, :styles, :default_style, :convert_options, :queued_for_write, :options
21
+
22
+ # Creates an Attachment object. +name+ is the name of the attachment,
23
+ # +instance+ is the ActiveRecord object instance it's attached to, and
24
+ # +options+ is the same as the hash passed to +has_attached_file+.
25
+ def initialize name, instance, options = {}
26
+ @name = name
27
+ @instance = instance
28
+
29
+ options = self.class.default_options.merge(options)
30
+
31
+ @url = options[:url]
32
+ @url = @url.call(self) if @url.is_a?(Proc)
33
+ @path = options[:path]
34
+ @path = @path.call(self) if @path.is_a?(Proc)
35
+ @styles = options[:styles]
36
+ @styles = @styles.call(self) if @styles.is_a?(Proc)
37
+ @default_url = options[:default_url]
38
+ @validations = options[:validations]
39
+ @default_style = options[:default_style]
40
+ @storage = options[:storage]
41
+ @whiny = options[:whiny_thumbnails] || options[:whiny]
42
+ @convert_options = options[:convert_options] || {}
43
+ @processors = options[:processors] || [:thumbnail]
44
+ @options = options
45
+ @queued_for_delete = []
46
+ @queued_for_write = {}
47
+ @errors = {}
48
+ @validation_errors = nil
49
+ @dirty = false
50
+
51
+ normalize_style_definition
52
+ initialize_storage
53
+ end
54
+
55
+ # What gets called when you call instance.attachment = File. It clears
56
+ # errors, assigns attributes, processes the file, and runs validations. It
57
+ # also queues up the previous file for deletion, to be flushed away on
58
+ # #save of its host. In addition to form uploads, you can also assign
59
+ # another Paperclip attachment:
60
+ # new_user.avatar = old_user.avatar
61
+ # If the file that is assigned is not valid, the processing (i.e.
62
+ # thumbnailing, etc) will NOT be run.
63
+ def assign uploaded_file
64
+
65
+ ensure_required_accessors!
66
+
67
+ if uploaded_file.is_a?(Paperclip::Attachment)
68
+ uploaded_file = uploaded_file.to_file(:original)
69
+ close_uploaded_file = uploaded_file.respond_to?(:close)
70
+ end
71
+
72
+ return nil unless valid_assignment?(uploaded_file)
73
+
74
+ uploaded_file.binmode if uploaded_file.respond_to? :binmode
75
+ self.clear
76
+
77
+ return nil if uploaded_file.nil?
78
+
79
+ if uploaded_file.respond_to?(:[])
80
+ @queued_for_write[:original] = uploaded_file['tempfile']
81
+ instance_write(:file_name, uploaded_file['filename'].strip.gsub(/[^\w\d\.\-]+/, '_')[/[^\\]+$/])
82
+ instance_write(:content_type, uploaded_file['content_type'].strip)
83
+ instance_write(:file_size, uploaded_file['size'].to_i)
84
+ instance_write(:updated_at, Time.now)
85
+ else
86
+ @queued_for_write[:original] = uploaded_file.to_tempfile
87
+ instance_write(:file_name, uploaded_file.original_filename.strip.gsub(/[^\w\d\.\-]+/, '_')[/[^\\]+$/])
88
+ instance_write(:content_type, uploaded_file.content_type.to_s.strip)
89
+ instance_write(:file_size, uploaded_file.size.to_i)
90
+ instance_write(:updated_at, Time.now)
91
+ end
92
+
93
+ @dirty = true
94
+
95
+ post_process if valid?
96
+
97
+ # Reset the file size if the original file was reprocessed.
98
+ instance_write(:file_size, @queued_for_write[:original].size.to_i)
99
+
100
+ ensure
101
+ uploaded_file.close if close_uploaded_file
102
+ validate
103
+ end
104
+
105
+ # Returns the public URL of the attachment, with a given style. Note that
106
+ # this does not necessarily need to point to a file that your web server
107
+ # can access and can point to an action in your app, if you need fine
108
+ # grained security. This is not recommended if you don't need the
109
+ # security, however, for performance reasons. set
110
+ # include_updated_timestamp to false if you want to stop the attachment
111
+ # update time appended to the url
112
+ def url style = default_style, include_updated_timestamp = true
113
+ the_url = original_filename.nil? ? interpolate(@default_url, style) : interpolate(@url, style)
114
+ include_updated_timestamp && updated_at ? [the_url, updated_at].compact.join(the_url.include?("?") ? "&" : "?") : the_url
115
+ end
116
+
117
+ # Returns the path of the attachment as defined by the :path option. If the
118
+ # file is stored in the filesystem the path refers to the path of the file
119
+ # on disk. If the file is stored in S3, the path is the "key" part of the
120
+ # URL, and the :bucket option refers to the S3 bucket.
121
+ def path style = default_style
122
+ original_filename.nil? ? nil : interpolate(@path, style)
123
+ end
124
+
125
+ # Alias to +url+
126
+ def to_s style = nil
127
+ url(style)
128
+ end
129
+
130
+ # Returns true if there are no errors on this attachment.
131
+ def valid?
132
+ validate
133
+ errors.empty?
134
+ end
135
+
136
+ # Returns an array containing the errors on this attachment.
137
+ def errors
138
+ @errors
139
+ end
140
+
141
+ # Returns true if there are changes that need to be saved.
142
+ def dirty?
143
+ @dirty
144
+ end
145
+
146
+ # Saves the file, if there are no errors. If there are, it flushes them to
147
+ # the instance's errors and returns false, cancelling the save.
148
+ def save
149
+ if valid?
150
+ flush_deletes
151
+ flush_writes
152
+ @dirty = false
153
+ true
154
+ else
155
+ flush_errors
156
+ false
157
+ end
158
+ end
159
+
160
+ # Clears out the attachment. Has the same effect as previously assigning
161
+ # nil to the attachment. Does NOT save. If you wish to clear AND save,
162
+ # use #destroy.
163
+ def clear
164
+ queue_existing_for_delete
165
+ @errors = {}
166
+ @validation_errors = nil
167
+ end
168
+
169
+ # Destroys the attachment. Has the same effect as previously assigning
170
+ # nil to the attachment *and saving*. This is permanent. If you wish to
171
+ # wipe out the existing attachment but not save, use #clear.
172
+ def destroy
173
+ clear
174
+ save
175
+ end
176
+
177
+ # Returns the name of the file as originally assigned, and lives in the
178
+ # <attachment>_file_name attribute of the model.
179
+ def original_filename
180
+ instance_read(:file_name)
181
+ end
182
+
183
+ # Returns the size of the file as originally assigned, and lives in the
184
+ # <attachment>_file_size attribute of the model.
185
+ def size
186
+ instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size)
187
+ end
188
+
189
+ # Returns the content_type of the file as originally assigned, and lives
190
+ # in the <attachment>_content_type attribute of the model.
191
+ def content_type
192
+ instance_read(:content_type)
193
+ end
194
+
195
+ # Returns the last modified time of the file as originally assigned, and
196
+ # lives in the <attachment>_updated_at attribute of the model.
197
+ def updated_at
198
+ instance_read(:updated_at)
199
+ end
200
+
201
+ # Paths and URLs can have a number of variables interpolated into them
202
+ # to vary the storage location based on name, id, style, class, etc.
203
+ # This method is a deprecated access into supplying and retrieving these
204
+ # interpolations. Future access should use either Paperclip.interpolates
205
+ # or extend the Paperclip::Interpolations module directly.
206
+ def self.interpolations
207
+ warn('[DEPRECATION] Paperclip::Attachment.interpolations is deprecated ' +
208
+ 'and will be removed from future versions. ' +
209
+ 'Use Paperclip.interpolates instead')
210
+ Paperclip::Interpolations
211
+ end
212
+
213
+ # This method really shouldn't be called that often. It's expected use is
214
+ # in the paperclip:refresh rake task and that's it. It will regenerate all
215
+ # thumbnails forcefully, by reobtaining the original file and going through
216
+ # the post-process again.
217
+ def reprocess!
218
+ new_original = Tempfile.new("paperclip-reprocess")
219
+ new_original.binmode
220
+ if old_original = to_file(:original)
221
+ new_original.write( old_original.read )
222
+ new_original.rewind
223
+
224
+ @queued_for_write = { :original => new_original }
225
+ post_process
226
+
227
+ old_original.close if old_original.respond_to?(:close)
228
+
229
+ save
230
+ else
231
+ true
232
+ end
233
+ end
234
+
235
+ # Returns true if a file has been assigned.
236
+ def file?
237
+ !original_filename.blank?
238
+ end
239
+
240
+ # Writes the attachment-specific attribute on the instance. For example,
241
+ # instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's
242
+ # "avatar_file_name" field (assuming the attachment is called avatar).
243
+ def instance_write(attr, value)
244
+ setter = :"#{name}_#{attr}="
245
+ responds = instance.respond_to?(setter)
246
+ self.instance_variable_set("@_#{setter.to_s.chop}", value)
247
+ instance.send(setter, value) if responds || attr.to_s == "file_name"
248
+ end
249
+
250
+ # Reads the attachment-specific attribute on the instance. See instance_write
251
+ # for more details.
252
+ def instance_read(attr)
253
+ getter = :"#{name}_#{attr}"
254
+ responds = instance.respond_to?(getter)
255
+ cached = self.instance_variable_get("@_#{getter}")
256
+ return cached if cached
257
+ instance.send(getter) if responds || attr.to_s == "file_name"
258
+ end
259
+
260
+ private
261
+
262
+ def ensure_required_accessors! #:nodoc:
263
+ %w(file_name).each do |field|
264
+ unless @instance.respond_to?("#{name}_#{field}") && @instance.respond_to?("#{name}_#{field}=")
265
+ raise PaperclipError.new("#{@instance.class} model missing required attr_accessor for '#{name}_#{field}'")
266
+ end
267
+ end
268
+ end
269
+
270
+ def log message #:nodoc:
271
+ Paperclip.log(message)
272
+ end
273
+
274
+ def valid_assignment? file #:nodoc:
275
+ if file.respond_to?(:[])
276
+ file[:filename] && file[:content_type]
277
+ else
278
+ file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type))
279
+ end
280
+ end
281
+
282
+ def validate #:nodoc:
283
+ unless @validation_errors
284
+ @validation_errors = @validations.inject({}) do |errors, validation|
285
+ name, options = validation
286
+ errors[name] = send(:"validate_#{name}", options) if allow_validation?(options)
287
+ errors
288
+ end
289
+ @validation_errors.reject!{|k,v| v == nil }
290
+ @errors.merge!(@validation_errors)
291
+ end
292
+ @validation_errors
293
+ end
294
+
295
+ def allow_validation? options #:nodoc:
296
+ (options[:if].nil? || check_guard(options[:if])) && (options[:unless].nil? || !check_guard(options[:unless]))
297
+ end
298
+
299
+ def check_guard guard #:nodoc:
300
+ if guard.respond_to? :call
301
+ guard.call(instance)
302
+ elsif ! guard.blank?
303
+ instance.send(guard.to_s)
304
+ end
305
+ end
306
+
307
+ def validate_size options #:nodoc:
308
+ if file? && !options[:range].include?(size.to_i)
309
+ options[:message].gsub(/:min/, options[:min].to_s).gsub(/:max/, options[:max].to_s)
310
+ end
311
+ end
312
+
313
+ def validate_presence options #:nodoc:
314
+ options[:message] unless file?
315
+ end
316
+
317
+ def validate_content_type options #:nodoc:
318
+ valid_types = [options[:content_type]].flatten
319
+ unless original_filename.blank?
320
+ unless valid_types.blank?
321
+ content_type = instance_read(:content_type)
322
+ unless valid_types.any?{|t| content_type.nil? || t === content_type }
323
+ options[:message] || "is not one of the allowed file types."
324
+ end
325
+ end
326
+ end
327
+ end
328
+
329
+ def normalize_style_definition #:nodoc:
330
+ @styles.each do |name, args|
331
+ unless args.is_a? Hash
332
+ dimensions, format = [args, nil].flatten[0..1]
333
+ format = nil if format.blank?
334
+ @styles[name] = {
335
+ :processors => @processors,
336
+ :geometry => dimensions,
337
+ :format => format,
338
+ :whiny => @whiny,
339
+ :convert_options => extra_options_for(name)
340
+ }
341
+ else
342
+ @styles[name] = {
343
+ :processors => @processors,
344
+ :whiny => @whiny,
345
+ :convert_options => extra_options_for(name)
346
+ }.merge(@styles[name])
347
+ end
348
+ end
349
+ end
350
+
351
+ def solidify_style_definitions #:nodoc:
352
+ @styles.each do |name, args|
353
+ @styles[name][:geometry] = @styles[name][:geometry].call(instance) if @styles[name][:geometry].respond_to?(:call)
354
+ @styles[name][:processors] = @styles[name][:processors].call(instance) if @styles[name][:processors].respond_to?(:call)
355
+ end
356
+ end
357
+
358
+ def initialize_storage #:nodoc:
359
+ @storage_module = Paperclip::Storage.const_get(@storage.to_s.capitalize)
360
+ self.extend(@storage_module)
361
+ end
362
+
363
+ def extra_options_for(style) #:nodoc:
364
+ all_options = convert_options[:all]
365
+ all_options = all_options.call(instance) if all_options.respond_to?(:call)
366
+ style_options = convert_options[style]
367
+ style_options = style_options.call(instance) if style_options.respond_to?(:call)
368
+
369
+ [ style_options, all_options ].compact.join(" ")
370
+ end
371
+
372
+ def post_process #:nodoc:
373
+ return if @queued_for_write[:original].nil?
374
+ solidify_style_definitions
375
+ post_process_styles
376
+ end
377
+
378
+ def post_process_styles #:nodoc:
379
+ @styles.each do |name, args|
380
+ begin
381
+ raise RuntimeError.new("Style #{name} has no processors defined.") if args[:processors].blank?
382
+ @queued_for_write[name] = args[:processors].inject(@queued_for_write[:original]) do |file, processor|
383
+ Paperclip.processor(processor).make(file, args, self)
384
+ end
385
+ rescue PaperclipError => e
386
+ log("An error was received while processing: #{e.inspect}")
387
+ (@errors[:processing] ||= []) << e.message if @whiny
388
+ end
389
+ end
390
+ end
391
+
392
+ def interpolate pattern, style = default_style #:nodoc:
393
+ Paperclip::Interpolations.interpolate(pattern, self, style)
394
+ end
395
+
396
+ def queue_existing_for_delete #:nodoc:
397
+ return unless file?
398
+ @queued_for_delete += [:original, *@styles.keys].uniq.map do |style|
399
+ path(style) if exists?(style)
400
+ end.compact
401
+ instance_write(:file_name, nil)
402
+ instance_write(:content_type, nil)
403
+ instance_write(:file_size, nil)
404
+ instance_write(:updated_at, nil)
405
+ end
406
+
407
+ def flush_errors #:nodoc:
408
+ @errors.each do |error, message|
409
+ [message].flatten.each {|m| instance.errors.add(name, m) }
410
+ end
411
+ end
412
+ end
413
+ end
@@ -0,0 +1,33 @@
1
+ module Paperclip
2
+ # This module is intended as a compatability shim for the differences in
3
+ # callbacks between Rails 2.0 and Rails 2.1.
4
+ module CallbackCompatability
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ base.send(:include, InstanceMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ # The implementation of this method is taken from the Rails 1.2.6 source,
12
+ # from rails/activerecord/lib/active_record/callbacks.rb, line 192.
13
+ def define_callbacks(*args)
14
+ args.each do |method|
15
+ self.class_eval <<-"end_eval"
16
+ def self.#{method}(*callbacks, &block)
17
+ callbacks << block if block_given?
18
+ write_inheritable_array(#{method.to_sym.inspect}, callbacks)
19
+ end
20
+ end_eval
21
+ end
22
+ end
23
+ end
24
+
25
+ module InstanceMethods
26
+ # The callbacks in < 2.1 don't worry about the extra options or the
27
+ # block, so just run what we have available.
28
+ def run_callbacks(meth, opts = nil, &blk)
29
+ callback(meth)
30
+ end
31
+ end
32
+ end
33
+ end