ripta-dm-paperclip 2.2.9.2

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