Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Paperclip as a submodule

  • Loading branch information...
commit 4436148411ed33c55091c9d046b25f220b409cce 1 parent 61c246f
Juan Schwindt authored April 14, 2009

Showing 50 changed files with 29 additions and 4,288 deletions. Show diff stats Hide diff stats

  1. 0  app/controllers/{application.rb → application_controller.rb}
  2. 5  app/models/user.rb
  3. 2  config/environment.rb
  4. 11  db/schema.rb
  5. 22  lib/paperclip_processors/jcropper.rb
  6. 26  vendor/plugins/paperclip/LICENSE
  7. 172  vendor/plugins/paperclip/README.rdoc
  8. 77  vendor/plugins/paperclip/Rakefile
  9. 5  vendor/plugins/paperclip/generators/paperclip/USAGE
  10. 27  vendor/plugins/paperclip/generators/paperclip/paperclip_generator.rb
  11. 19  vendor/plugins/paperclip/generators/paperclip/templates/paperclip_migration.rb.erb
  12. 1  vendor/plugins/paperclip/init.rb
  13. 318  vendor/plugins/paperclip/lib/paperclip.rb
  14. 396  vendor/plugins/paperclip/lib/paperclip/attachment.rb
  15. 33  vendor/plugins/paperclip/lib/paperclip/callback_compatability.rb
  16. 115  vendor/plugins/paperclip/lib/paperclip/geometry.rb
  17. 58  vendor/plugins/paperclip/lib/paperclip/iostream.rb
  18. 47  vendor/plugins/paperclip/lib/paperclip/processor.rb
  19. 220  vendor/plugins/paperclip/lib/paperclip/storage.rb
  20. 70  vendor/plugins/paperclip/lib/paperclip/thumbnail.rb
  21. 48  vendor/plugins/paperclip/lib/paperclip/upfile.rb
  22. 40  vendor/plugins/paperclip/paperclip.gemspec
  23. 4  vendor/plugins/paperclip/shoulda_macros/matchers.rb
  24. 49  vendor/plugins/paperclip/shoulda_macros/matchers/have_attached_file_matcher.rb
  25. 66  vendor/plugins/paperclip/shoulda_macros/matchers/validate_attachment_content_type_matcher.rb
  26. 48  vendor/plugins/paperclip/shoulda_macros/matchers/validate_attachment_presence_matcher.rb
  27. 83  vendor/plugins/paperclip/shoulda_macros/matchers/validate_attachment_size_matcher.rb
  28. 68  vendor/plugins/paperclip/shoulda_macros/paperclip.rb
  29. 79  vendor/plugins/paperclip/tasks/paperclip_tasks.rake
  30. 1  vendor/plugins/paperclip/test/.gitignore
  31. 627  vendor/plugins/paperclip/test/attachment_test.rb
  32. 4  vendor/plugins/paperclip/test/database.yml
  33. BIN  vendor/plugins/paperclip/test/fixtures/12k.png
  34. BIN  vendor/plugins/paperclip/test/fixtures/50x50.png
  35. BIN  vendor/plugins/paperclip/test/fixtures/5k.png
  36. 1  vendor/plugins/paperclip/test/fixtures/bad.png
  37. 0  vendor/plugins/paperclip/test/fixtures/text.txt
  38. BIN  vendor/plugins/paperclip/test/fixtures/twopage.pdf
  39. 168  vendor/plugins/paperclip/test/geometry_test.rb
  40. 82  vendor/plugins/paperclip/test/helper.rb
  41. 493  vendor/plugins/paperclip/test/integration_test.rb
  42. 71  vendor/plugins/paperclip/test/iostream_test.rb
  43. 21  vendor/plugins/paperclip/test/matchers/have_attached_file_matcher_test.rb
  44. 30  vendor/plugins/paperclip/test/matchers/validate_attachment_content_type_matcher_test.rb
  45. 21  vendor/plugins/paperclip/test/matchers/validate_attachment_presence_matcher_test.rb
  46. 50  vendor/plugins/paperclip/test/matchers/validate_attachment_size_matcher_test.rb
  47. 237  vendor/plugins/paperclip/test/paperclip_test.rb
  48. 10  vendor/plugins/paperclip/test/processor_test.rb
  49. 215  vendor/plugins/paperclip/test/storage_test.rb
  50. 177  vendor/plugins/paperclip/test/thumbnail_test.rb
0  app/controllers/application.rb → app/controllers/application_controller.rb
File renamed without changes
5  app/models/user.rb
@@ -6,10 +6,7 @@ class User < ActiveRecord::Base
6 6
   
7 7
   has_attached_file :avatar,
8 8
         :styles => { :normal => ["#{AVATAR_NW}x#{AVATAR_NH}>", :jpg],
9  
-                     :small => ["#{AVATAR_SW}x#{AVATAR_SH}", :jpg] },
10  
-        :convert_options => { :all => "-strip",
11  
-                              :normal => proc { |m| m.avatar_crop_str },
12  
-                              :small => proc { |m| m.avatar_crop_str } },
  9
+                     :small => ["#{AVATAR_SW}x#{AVATAR_SH}#", :jpg] },
13 10
         :processors => [:jcropper],
14 11
         :default_url => "/images/default_avatar.png"
15 12
 
2  config/environment.rb
@@ -5,7 +5,7 @@
5 5
 # ENV['RAILS_ENV'] ||= 'production'
6 6
 
7 7
 # Specifies gem version of Rails to use when vendor/rails is not present
8  
-RAILS_GEM_VERSION = '2.2.2' unless defined? RAILS_GEM_VERSION
  8
+RAILS_GEM_VERSION = '2.3.2' unless defined? RAILS_GEM_VERSION
9 9
 
10 10
 # Bootstrap the Rails environment, frameworks, and default configuration
11 11
 require File.join(File.dirname(__FILE__), 'boot')
11  db/schema.rb
@@ -9,6 +9,15 @@
9 9
 #
10 10
 # It's strongly recommended to check this file into your version control system.
11 11
 
12  
-ActiveRecord::Schema.define(:version => 0) do
  12
+ActiveRecord::Schema.define(:version => 20090208152022) do
  13
+
  14
+  create_table "users", :force => true do |t|
  15
+    t.string   "name"
  16
+    t.string   "avatar_file_name"
  17
+    t.string   "avatar_content_type"
  18
+    t.integer  "avatar_file_size"
  19
+    t.datetime "created_at"
  20
+    t.datetime "updated_at"
  21
+  end
13 22
 
14 23
 end
22  lib/paperclip_processors/jcropper.rb
@@ -7,15 +7,27 @@ module Paperclip
7 7
   # Handles thumbnailing images that are uploaded.
8 8
   class Jcropper < Thumbnail
9 9
   
10  
-    # Returns the command ImageMagick's +convert+ needs to transform the image
11  
-    # into the thumbnail.
12 10
     def transformation_command
13 11
       scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
14 12
       trans = ''
15  
-      trans << " #{convert_options}" if convert_options?
16  
-      trans << " -resize \"#{scale}\""
17  
-      trans << " -crop \"#{crop}\" +repage" if crop
  13
+      if crop_string?
  14
+        trans << " #{image_crop_string}"
  15
+        trans << " -resize \"#{scale}\""
  16
+      else
  17
+        trans << " -resize \"#{scale}\""
  18
+        trans << " -crop \"#{crop}\" +repage" if crop
  19
+      end
18 20
       trans
19 21
     end
  22
+
  23
+    def crop_string
  24
+      @attachment.instance.crop_str
  25
+    end
  26
+
  27
+    def crop_string?
  28
+      not crop_string.blank?
  29
+    end
  30
+
20 31
   end
  32
+   
21 33
 end
26  vendor/plugins/paperclip/LICENSE
... ...
@@ -1,26 +0,0 @@
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  
-
172  vendor/plugins/paperclip/README.rdoc
Source Rendered
... ...
@@ -1,172 +0,0 @@
1  
-=Paperclip
2  
-
3  
-Paperclip is intended as an easy file attachment library for ActiveRecord. The
4  
-intent behind it was to keep setup as easy as possible and to treat files as
5  
-much like other attributes as possible. This means they aren't saved to their
6  
-final locations on disk, nor are they deleted if set to nil, until
7  
-ActiveRecord::Base#save is called. It manages validations based on size and
8  
-presence, if required. It can transform its assigned image into thumbnails if
9  
-needed, and the prerequisites are as simple as installing ImageMagick (which,
10  
-for most modern Unix-based systems, is as easy as installing the right
11  
-packages). Attached files are saved to the filesystem and referenced in the
12  
-browser by an easily understandable specification, which has sensible and
13  
-useful defaults.
14  
-
15  
-See the documentation for +has_attached_file+ in Paperclip::ClassMethods for
16  
-more detailed options.
17  
-
18  
-==Quick Start
19  
-
20  
-In your model:
21  
-
22  
-  class User < ActiveRecord::Base
23  
-    has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }
24  
-  end
25  
-
26  
-In your migrations:
27  
-
28  
-  class AddAvatarColumnsToUser < ActiveRecord::Migration
29  
-    def self.up
30  
-      add_column :users, :avatar_file_name,    :string
31  
-      add_column :users, :avatar_content_type, :string
32  
-      add_column :users, :avatar_file_size,    :integer
33  
-      add_column :users, :avatar_updated_at,   :datetime
34  
-    end
35  
-
36  
-    def self.down
37  
-      remove_column :users, :avatar_file_name
38  
-      remove_column :users, :avatar_content_type
39  
-      remove_column :users, :avatar_file_size
40  
-      remove_column :users, :avatar_updated_at
41  
-    end
42  
-  end
43  
-
44  
-In your edit and new views:
45  
-
46  
-  <% form_for :user, @user, :url => user_path, :html => { :multipart => true } do |form| %>
47  
-    <%= form.file_field :avatar %>
48  
-  <% end %>
49  
-
50  
-In your controller:
51  
-
52  
-  def create
53  
-    @user = User.create( params[:user] )
54  
-  end
55  
-
56  
-In your show view:
57  
-
58  
-  <%= image_tag @user.avatar.url %>
59  
-  <%= image_tag @user.avatar.url(:medium) %>
60  
-  <%= image_tag @user.avatar.url(:thumb) %>
61  
-
62  
-==Usage
63  
-
64  
-The basics of paperclip are quite simple: Declare that your model has an
65  
-attachment with the has_attached_file method, and give it a name. Paperclip
66  
-will wrap up up to four attributes (all prefixed with that attachment's name,
67  
-so you can have multiple attachments per model if you wish) and give the a
68  
-friendly front end. The attributes are <attachment>_file_name,
69  
-<attachment>_file_size, <attachment>_content_type, and <attachment>_updated_at.
70  
-Only <attachment>_file_name is required for paperclip to operate. More
71  
-information about the options to has_attached_file is available in the
72  
-documentation of Paperclip::ClassMethods.
73  
-
74  
-Attachments can be validated with Paperclip's validation methods,
75  
-validates_attachment_presence, validates_attachment_content_type, and
76  
-validates_attachment_size.
77  
-
78  
-==Storage
79  
-
80  
-The files that are assigned as attachments are, by default, placed in the
81  
-directory specified by the :path option to has_attached_file. By default, this
82  
-location is
83  
-":rails_root/public/system/:attachment/:id/:style/:basename.:extension". This
84  
-location was chosen because on standard Capistrano deployments, the
85  
-public/system directory is symlinked to the app's shared directory, meaning it
86  
-will survive between deployments. For example, using that :path, you may have a
87  
-file at
88  
-
89  
-  /data/myapp/releases/20081229172410/public/system/avatars/13/small/my_pic.png
90  
-
91  
-NOTE: This is a change from previous versions of Paperclip, but is overall a
92  
-safer choice for the defaul file store.
93  
-
94  
-You may also choose to store your files using Amazon's S3 service. You can find
95  
-more information about S3 storage at the description for
96  
-Paperclip::Storage::S3.
97  
-
98  
-Files on the local filesystem (and in the Rails app's public directory) will be
99  
-available to the internet at large. If you require access control, it's
100  
-possible to place your files in a different location. You will need to change
101  
-both the :path and :url options in order to make sure the files are unavailable
102  
-to the public. Both :path and :url allow the same set of interpolated
103  
-variables.
104  
-
105  
-==Post Processing
106  
-
107  
-Paperclip supports an extendible selection of post-processors. When you define
108  
-a set of styles for an attachment, by default it is expected that those
109  
-"styles" are actually "thumbnails". However, you can do more than just
110  
-thumbnail images. By defining a subclass of Paperclip::Processor, you can
111  
-perform any processing you want on the files that are attached. Any file in
112  
-your Rails app's lib/paperclip_processors directory is automatically loaded by
113  
-paperclip, allowing you to easily define custom processors. You can specify a
114  
-processor with the :processors option to has_attached_file:
115  
-
116  
-  has_attached_file :scan, :styles => { :text => { :quality => :better } },
117  
-                           :processors => [:ocr]
118  
-
119  
-This would load the hypothetical class Paperclip::Ocr, which would have the
120  
-hash "{ :quality => :better }" passed to it along with the uploaded file. For
121  
-more information about defining processors, see Paperclip::Processor.
122  
-
123  
-The default processor is Paperclip::Thumbnail. For backwards compatability
124  
-reasons, you can pass a single geometry string or an array containing a
125  
-geometry and a format, which the file will be converted to, like so:
126  
-
127  
-  has_attached_file :avatar, :styles => { :thumb => ["32x32#", :png] }
128  
-
129  
-This will convert the "thumb" style to a 32x32 square in png format, regardless
130  
-of what was uploaded. If the format is not specified, it is kept the same (i.e.
131  
-jpgs will remain jpgs).
132  
-
133  
-Multiple processors can be specified, and they will be invoked in the order
134  
-they are defined in the :processors array. Each successive processor will
135  
-be given the result of the previous processor's execution. All processors will
136  
-receive the same parameters, which are what you define in the :styles hash.
137  
-For example, assuming we had this definition:
138  
-
139  
-  has_attached_file :scan, :styles => { :text => { :quality => :better } },
140  
-                           :processors => [:rotator, :ocr]
141  
-
142  
-then both the :rotator processor and the :ocr processor would receive the 
143  
-options "{ :quality => :better }". This parameter may not mean anything to one
144  
-or more or the processors, and they are free to ignore it.
145  
-
146  
-==Events
147  
-
148  
-Before and after the Post Processing step, Paperclip calls back to the model
149  
-with a few callbacks, allowing the model to change or cancel the processing
150  
-step. The callbacks are "before_post_process" and "after_post_process" (which
151  
-are called before and after the processing of each attachment), and the
152  
-attachment-specific "before_<attachment>_post_process" and
153  
-"after_<attachment>_post_process". The callbacks are intended to be as close to
154  
-normal ActiveRecord callbacks as possible, so if you return false (specifically
155  
-- returning nil is not the same) in a before_ filter, the post processing step
156  
-will halt. Returning false in an after_ filter will not halt anything, but you
157  
-can access the model and the attachment if necessary.
158  
-
159  
-NOTE: Post processing will not even *start* if the attachment is not valid
160  
-according to the validations. Your callbacks (and processors) will only be
161  
-called with valid attachments.
162  
-
163  
-==Contributing
164  
-
165  
-If you'd like to contribute a feature or bugfix: Thanks! To make sure your
166  
-fix/feature has a high chance of being included, please read the following
167  
-guidelines:
168  
-
169  
-1. Ask on the mailing list, or post a ticket in Lighthouse.
170  
-2. Make sure there are tests! We will not accept any patch that is not tested.
171  
-   It's a rare time when explicit tests aren't needed. If you have questions 
172  
-   about writing tests for paperclip, please ask the mailing list.
77  vendor/plugins/paperclip/Rakefile
... ...
@@ -1,77 +0,0 @@
1  
-require 'rake'
2  
-require 'rake/testtask'
3  
-require 'rake/rdoctask'
4  
-
5  
-$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
6  
-require 'paperclip'
7  
-
8  
-desc 'Default: run unit tests.'
9  
-task :default => [:clean, :test]
10  
-
11  
-desc 'Test the paperclip plugin.'
12  
-Rake::TestTask.new(:test) do |t|
13  
-  t.libs << 'lib' << 'profile'
14  
-  t.pattern = 'test/**/*_test.rb'
15  
-  t.verbose = true
16  
-end
17  
-
18  
-desc 'Start an IRB session with all necessary files required.'
19  
-task :shell do |t|
20  
-  chdir File.dirname(__FILE__)
21  
-  exec 'irb -I lib/ -I lib/paperclip -r rubygems -r active_record -r tempfile -r init'
22  
-end
23  
-
24  
-desc 'Generate documentation for the paperclip plugin.'
25  
-Rake::RDocTask.new(:rdoc) do |rdoc|
26  
-  rdoc.rdoc_dir = 'doc'
27  
-  rdoc.title    = 'Paperclip'
28  
-  rdoc.options << '--line-numbers' << '--inline-source'
29  
-  rdoc.rdoc_files.include('README*')
30  
-  rdoc.rdoc_files.include('lib/**/*.rb')
31  
-end
32  
-
33  
-desc 'Update documentation on website'
34  
-task :sync_docs => 'rdoc' do
35  
-  `rsync -ave ssh doc/ dev@dev.thoughtbot.com:/home/dev/www/dev.thoughtbot.com/paperclip`
36  
-end
37  
-
38  
-desc 'Clean up files.'
39  
-task :clean do |t|
40  
-  FileUtils.rm_rf "doc"
41  
-  FileUtils.rm_rf "tmp"
42  
-  FileUtils.rm_rf "pkg"
43  
-  FileUtils.rm "test/debug.log" rescue nil
44  
-  FileUtils.rm "test/paperclip.db" rescue nil
45  
-end
46  
-
47  
-spec = Gem::Specification.new do |s| 
48  
-  s.name              = "paperclip"
49  
-  s.version           = Paperclip::VERSION
50  
-  s.author            = "Jon Yurek"
51  
-  s.email             = "jyurek@thoughtbot.com"
52  
-  s.homepage          = "http://www.thoughtbot.com/projects/paperclip"
53  
-  s.platform          = Gem::Platform::RUBY
54  
-  s.summary           = "File attachments as attributes for ActiveRecord"
55  
-  s.files             = FileList["README*",
56  
-                                 "LICENSE",
57  
-                                 "Rakefile",
58  
-                                 "init.rb",
59  
-                                 "{generators,lib,tasks,test,shoulda_macros}/**/*"].to_a
60  
-  s.require_path      = "lib"
61  
-  s.test_files        = FileList["test/**/test_*.rb"].to_a
62  
-  s.rubyforge_project = "paperclip"
63  
-  s.has_rdoc          = true
64  
-  s.extra_rdoc_files  = FileList["README*"].to_a
65  
-  s.rdoc_options << '--line-numbers' << '--inline-source'
66  
-  s.requirements << "ImageMagick"
67  
-  s.add_runtime_dependency 'right_aws'
68  
-  s.add_development_dependency 'thoughtbot-shoulda'
69  
-  s.add_development_dependency 'mocha'
70  
-end
71  
- 
72  
-desc "Generate a gemspec file for GitHub"
73  
-task :gemspec do
74  
-  File.open("#{spec.name}.gemspec", 'w') do |f|
75  
-    f.write spec.to_ruby
76  
-  end
77  
-end
5  vendor/plugins/paperclip/generators/paperclip/USAGE
... ...
@@ -1,5 +0,0 @@
1  
-Usage:
2  
-
3  
-  script/generate paperclip Class attachment1 (attachment2 ...)
4  
-  
5  
-This will create a migration that will add the proper columns to your class's table.
27  vendor/plugins/paperclip/generators/paperclip/paperclip_generator.rb
... ...
@@ -1,27 +0,0 @@
1  
-class PaperclipGenerator < Rails::Generator::NamedBase
2  
-  attr_accessor :attachments, :migration_name
3  
- 
4  
-  def initialize(args, options = {})
5  
-    super
6  
-    @class_name, @attachments = args[0], args[1..-1]
7  
-  end
8  
- 
9  
-  def manifest    
10  
-    file_name = generate_file_name
11  
-    @migration_name = file_name.camelize
12  
-    record do |m|
13  
-      m.migration_template "paperclip_migration.rb.erb",
14  
-                           File.join('db', 'migrate'),
15  
-                           :migration_file_name => file_name
16  
-    end
17  
-  end 
18  
-  
19  
-  private 
20  
-  
21  
-  def generate_file_name
22  
-    names = attachments.map{|a| a.underscore }
23  
-    names = names[0..-2] + ["and", names[-1]] if names.length > 1
24  
-    "add_attachments_#{names.join("_")}_to_#{@class_name.underscore}"
25  
-  end
26  
- 
27  
-end
19  vendor/plugins/paperclip/generators/paperclip/templates/paperclip_migration.rb.erb
... ...
@@ -1,19 +0,0 @@
1  
-class <%= migration_name %> < ActiveRecord::Migration
2  
-  def self.up
3  
-<% attachments.each do |attachment| -%>
4  
-    add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name, :string
5  
-    add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type, :string
6  
-    add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_size, :integer
7  
-    add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_updated_at, :datetime
8  
-<% end -%>
9  
-  end
10  
-
11  
-  def self.down
12  
-<% attachments.each do |attachment| -%>
13  
-    remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name
14  
-    remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type
15  
-    remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_size
16  
-    remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_updated_at
17  
-<% end -%>
18  
-  end
19  
-end
1  vendor/plugins/paperclip/init.rb
... ...
@@ -1 +0,0 @@
1  
-require File.join(File.dirname(__FILE__), "lib", "paperclip")
318  vendor/plugins/paperclip/lib/paperclip.rb
... ...
@@ -1,318 +0,0 @@
1  
-# Paperclip allows file attachments that are stored in the filesystem. All graphical
2  
-# transformations are done using the Graphics/ImageMagick command line utilities and
3  
-# are stored in Tempfiles until the record is saved. Paperclip does not require a
4  
-# separate model for storing the attachment's information, instead adding a few simple
5  
-# columns to your table.
6  
-#
7  
-# Author:: Jon Yurek
8  
-# Copyright:: Copyright (c) 2008 thoughtbot, inc.
9  
-# License:: MIT License (http://www.opensource.org/licenses/mit-license.php)
10  
-#
11  
-# Paperclip defines an attachment as any file, though it makes special considerations
12  
-# for image files. You can declare that a model has an attached file with the
13  
-# +has_attached_file+ method:
14  
-#
15  
-#   class User < ActiveRecord::Base
16  
-#     has_attached_file :avatar, :styles => { :thumb => "100x100" }
17  
-#   end
18  
-#
19  
-#   user = User.new
20  
-#   user.avatar = params[:user][:avatar]
21  
-#   user.avatar.url
22  
-#   # => "/users/avatars/4/original_me.jpg"
23  
-#   user.avatar.url(:thumb)
24  
-#   # => "/users/avatars/4/thumb_me.jpg"
25  
-#
26  
-# See the +has_attached_file+ documentation for more details.
27  
-
28  
-require 'tempfile'
29  
-require 'paperclip/upfile'
30  
-require 'paperclip/iostream'
31  
-require 'paperclip/geometry'
32  
-require 'paperclip/processor'
33  
-require 'paperclip/thumbnail'
34  
-require 'paperclip/storage'
35  
-require 'paperclip/attachment'
36  
-if defined? RAILS_ROOT
37  
-  Dir.glob(File.join(File.expand_path(RAILS_ROOT), "lib", "paperclip_processors", "*.rb")).each do |processor|
38  
-    require processor
39  
-  end
40  
-end
41  
-
42  
-# The base module that gets included in ActiveRecord::Base. See the
43  
-# documentation for Paperclip::ClassMethods for more useful information.
44  
-module Paperclip
45  
-
46  
-  VERSION = "2.2.3"
47  
-
48  
-  class << self
49  
-    # Provides configurability to Paperclip. There are a number of options available, such as:
50  
-    # * whiny_thumbnails: Will raise an error if Paperclip cannot process thumbnails of 
51  
-    #   an uploaded image. Defaults to true.
52  
-    # * log: Logs progress to the Rails log. Uses ActiveRecord's logger, so honors
53  
-    #   log levels, etc. Defaults to true.
54  
-    # * command_path: Defines the path at which to find the command line
55  
-    #   programs if they are not visible to Rails the system's search path. Defaults to 
56  
-    #   nil, which uses the first executable found in the user's search path.
57  
-    # * image_magick_path: Deprecated alias of command_path.
58  
-    def options
59  
-      @options ||= {
60  
-        :whiny_thumbnails  => true,
61  
-        :image_magick_path => nil,
62  
-        :command_path      => nil,
63  
-        :log               => true,
64  
-        :swallow_stderr    => true
65  
-      }
66  
-    end
67  
-
68  
-    def path_for_command command #:nodoc:
69  
-      if options[:image_magick_path]
70  
-        warn("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead")
71  
-      end
72  
-      path = [options[:command_path] || options[:image_magick_path], command].compact
73  
-      File.join(*path)
74  
-    end
75  
-
76  
-    def interpolates key, &block
77  
-      Paperclip::Attachment.interpolations[key] = block
78  
-    end
79  
-
80  
-    # The run method takes a command to execute and a string of parameters
81  
-    # that get passed to it. The command is prefixed with the :command_path
82  
-    # option from Paperclip.options. If you have many commands to run and
83  
-    # they are in different paths, the suggested course of action is to
84  
-    # symlink them so they are all in the same directory.
85  
-    #
86  
-    # If the command returns with a result code that is not one of the
87  
-    # expected_outcodes, a PaperclipCommandLineError will be raised. Generally
88  
-    # a code of 0 is expected, but a list of codes may be passed if necessary.
89  
-    def run cmd, params = "", expected_outcodes = 0
90  
-      command = %Q<#{%Q[#{path_for_command(cmd)} #{params}].gsub(/\s+/, " ")}>
91  
-      command = "#{command} 2>#{bit_bucket}" if Paperclip.options[:swallow_stderr]
92  
-      output = `#{command}`
93  
-      unless [expected_outcodes].flatten.include?($?.exitstatus)
94  
-        raise PaperclipCommandLineError, "Error while running #{cmd}"
95  
-      end
96  
-      output
97  
-    end
98  
-
99  
-    def bit_bucket #:nodoc:
100  
-      File.exists?("/dev/null") ? "/dev/null" : "NUL"
101  
-    end
102  
-
103  
-    def included base #:nodoc:
104  
-      base.extend ClassMethods
105  
-      unless base.respond_to?(:define_callbacks)
106  
-        base.send(:include, Paperclip::CallbackCompatability)
107  
-      end
108  
-    end
109  
-
110  
-    def processor name #:nodoc:
111  
-      name = name.to_s.camelize
112  
-      processor = Paperclip.const_get(name)
113  
-      unless processor.ancestors.include?(Paperclip::Processor)
114  
-        raise PaperclipError.new("Processor #{name} was not found") 
115  
-      end
116  
-      processor
117  
-    end
118  
-  end
119  
-
120  
-  class PaperclipError < StandardError #:nodoc:
121  
-  end
122  
-
123  
-  class PaperclipCommandLineError < StandardError #:nodoc:
124  
-  end
125  
-
126  
-  class NotIdentifiedByImageMagickError < PaperclipError #:nodoc:
127  
-  end
128  
-
129  
-  module ClassMethods
130  
-    # +has_attached_file+ gives the class it is called on an attribute that maps to a file. This
131  
-    # is typically a file stored somewhere on the filesystem and has been uploaded by a user. 
132  
-    # The attribute returns a Paperclip::Attachment object which handles the management of
133  
-    # that file. The intent is to make the attachment as much like a normal attribute. The 
134  
-    # thumbnails will be created when the new file is assigned, but they will *not* be saved 
135  
-    # until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is 
136  
-    # called on it, the attachment will *not* be deleted until +save+ is called. See the 
137  
-    # Paperclip::Attachment documentation for more specifics. There are a number of options 
138  
-    # you can set to change the behavior of a Paperclip attachment:
139  
-    # * +url+: The full URL of where the attachment is publically accessible. This can just
140  
-    #   as easily point to a directory served directly through Apache as it can to an action
141  
-    #   that can control permissions. You can specify the full domain and path, but usually
142  
-    #   just an absolute path is sufficient. The leading slash *must* be included manually for 
143  
-    #   absolute paths. The default value is 
144  
-    #   "/system/:attachment/:id/:style/:basename.:extension". See
145  
-    #   Paperclip::Attachment#interpolate for more information on variable interpolaton.
146  
-    #     :url => "/:class/:attachment/:id/:style_:basename.:extension"
147  
-    #     :url => "http://some.other.host/stuff/:class/:id_:extension"
148  
-    # * +default_url+: The URL that will be returned if there is no attachment assigned. 
149  
-    #   This field is interpolated just as the url is. The default value is 
150  
-    #   "/:attachment/:style/missing.png"
151  
-    #     has_attached_file :avatar, :default_url => "/images/default_:style_avatar.png"
152  
-    #     User.new.avatar_url(:small) # => "/images/default_small_avatar.png"
153  
-    # * +styles+: A hash of thumbnail styles and their geometries. You can find more about 
154  
-    #   geometry strings at the ImageMagick website 
155  
-    #   (http://www.imagemagick.org/script/command-line-options.php#resize). Paperclip
156  
-    #   also adds the "#" option (e.g. "50x50#"), which will resize the image to fit maximally 
157  
-    #   inside the dimensions and then crop the rest off (weighted at the center). The 
158  
-    #   default value is to generate no thumbnails.
159  
-    # * +default_style+: The thumbnail style that will be used by default URLs. 
160  
-    #   Defaults to +original+.
161  
-    #     has_attached_file :avatar, :styles => { :normal => "100x100#" },
162  
-    #                       :default_style => :normal
163  
-    #     user.avatar.url # => "/avatars/23/normal_me.png"
164  
-    # * +whiny_thumbnails+: Will raise an error if Paperclip cannot post_process an uploaded file due
165  
-    #   to a command line error. This will override the global setting for this attachment. 
166  
-    #   Defaults to true. 
167  
-    # * +convert_options+: When creating thumbnails, use this free-form options
168  
-    #   field to pass in various convert command options.  Typical options are "-strip" to
169  
-    #   remove all Exif data from the image (save space for thumbnails and avatars) or
170  
-    #   "-depth 8" to specify the bit depth of the resulting conversion.  See ImageMagick
171  
-    #   convert documentation for more options: (http://www.imagemagick.org/script/convert.php)
172  
-    #   Note that this option takes a hash of options, each of which correspond to the style
173  
-    #   of thumbnail being generated. You can also specify :all as a key, which will apply
174  
-    #   to all of the thumbnails being generated. If you specify options for the :original,
175  
-    #   it would be best if you did not specify destructive options, as the intent of keeping
176  
-    #   the original around is to regenerate all the thumbnails when requirements change.
177  
-    #     has_attached_file :avatar, :styles => { :large => "300x300", :negative => "100x100" }
178  
-    #                                :convert_options => {
179  
-    #                                  :all => "-strip",
180  
-    #                                  :negative => "-negate"
181  
-    #                                }
182  
-    # * +storage+: Chooses the storage backend where the files will be stored. The current
183  
-    #   choices are :filesystem and :s3. The default is :filesystem. Make sure you read the
184  
-    #   documentation for Paperclip::Storage::Filesystem and Paperclip::Storage::S3
185  
-    #   for backend-specific options.
186  
-    def has_attached_file name, options = {}
187  
-      include InstanceMethods
188  
-
189  
-      write_inheritable_attribute(:attachment_definitions, {}) if attachment_definitions.nil?
190  
-      attachment_definitions[name] = {:validations => {}}.merge(options)
191  
-
192  
-      after_save :save_attached_files
193  
-      before_destroy :destroy_attached_files
194  
-
195  
-      define_callbacks :before_post_process, :after_post_process
196  
-      define_callbacks :"before_#{name}_post_process", :"after_#{name}_post_process"
197  
-     
198  
-      define_method name do |*args|
199  
-        a = attachment_for(name)
200  
-        (args.length > 0) ? a.to_s(args.first) : a
201  
-      end
202  
-
203  
-      define_method "#{name}=" do |file|
204  
-        attachment_for(name).assign(file)
205  
-      end
206  
-
207  
-      define_method "#{name}?" do
208  
-        attachment_for(name).file?
209  
-      end
210  
-
211  
-      validates_each(name) do |record, attr, value|
212  
-        attachment = record.attachment_for(name)
213  
-        attachment.send(:flush_errors) unless attachment.valid?
214  
-      end
215  
-    end
216  
-
217  
-    # Places ActiveRecord-style validations on the size of the file assigned. The
218  
-    # possible options are:
219  
-    # * +in+: a Range of bytes (i.e. +1..1.megabyte+),
220  
-    # * +less_than+: equivalent to :in => 0..options[:less_than]
221  
-    # * +greater_than+: equivalent to :in => options[:greater_than]..Infinity
222  
-    # * +message+: error message to display, use :min and :max as replacements
223  
-    def validates_attachment_size name, options = {}
224  
-      min     = options[:greater_than] || (options[:in] && options[:in].first) || 0
225  
-      max     = options[:less_than]    || (options[:in] && options[:in].last)  || (1.0/0)
226  
-      range   = (min..max)
227  
-      message = options[:message] || "file size must be between :min and :max bytes."
228  
-
229  
-      attachment_definitions[name][:validations][:size] = lambda do |attachment, instance|
230  
-        if attachment.file? && !range.include?(attachment.size.to_i)
231  
-          message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s)
232  
-        end
233  
-      end
234  
-    end
235  
-
236  
-    # Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true.
237  
-    def validates_attachment_thumbnails name, options = {}
238  
-      attachment_definitions[name][:whiny_thumbnails] = true
239  
-    end
240  
-
241  
-    # Places ActiveRecord-style validations on the presence of a file.
242  
-    def validates_attachment_presence name, options = {}
243  
-      message = options[:message] || "must be set."
244  
-      attachment_definitions[name][:validations][:presence] = lambda do |attachment, instance|
245  
-        message unless attachment.file?
246  
-      end
247  
-    end
248  
-    
249  
-    # Places ActiveRecord-style validations on the content type of the file
250  
-    # assigned. The possible options are: 
251  
-    # * +content_type+: Allowed content types.  Can be a single content type 
252  
-    #   or an array.  Each type can be a String or a Regexp. It should be 
253  
-    #   noted that Internet Explorer upload files with content_types that you 
254  
-    #   may not expect. For example, JPEG images are given image/pjpeg and 
255  
-    #   PNGs are image/x-png, so keep that in mind when determining how you 
256  
-    #   match.  Allows all by default.
257  
-    # * +message+: The message to display when the uploaded file has an invalid
258  
-    #   content type.
259  
-    # NOTE: If you do not specify an [attachment]_content_type field on your
260  
-    # model, content_type validation will work _ONLY upon assignment_ and
261  
-    # re-validation after the instance has been reloaded will always succeed.
262  
-    def validates_attachment_content_type name, options = {}
263  
-      attachment_definitions[name][:validations][:content_type] = lambda do |attachment, instance|
264  
-        valid_types = [options[:content_type]].flatten
265  
-        
266  
-        unless attachment.original_filename.blank?
267  
-          unless valid_types.blank?
268  
-            content_type = attachment.instance_read(:content_type)
269  
-            unless valid_types.any?{|t| content_type.nil? || t === content_type }
270  
-              options[:message] || "is not one of the allowed file types."
271  
-            end
272  
-          end
273  
-        end
274  
-      end
275  
-    end
276  
-
277  
-    # Returns the attachment definitions defined by each call to
278  
-    # has_attached_file.
279  
-    def attachment_definitions
280  
-      read_inheritable_attribute(:attachment_definitions)
281  
-    end
282  
-  end
283  
-
284  
-  module InstanceMethods #:nodoc:
285  
-    def attachment_for name
286  
-      @_paperclip_attachments ||= {}
287  
-      @_paperclip_attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name])
288  
-    end
289  
-    
290  
-    def each_attachment
291  
-      self.class.attachment_definitions.each do |name, definition|
292  
-        yield(name, attachment_for(name))
293  
-      end
294  
-    end
295  
-
296  
-    def save_attached_files
297  
-      logger.info("[paperclip] Saving attachments.")
298  
-      each_attachment do |name, attachment|
299  
-        attachment.send(:save)
300  
-      end
301  
-    end
302  
-
303  
-    def destroy_attached_files
304  
-      logger.info("[paperclip] Deleting attachments.")
305  
-      each_attachment do |name, attachment|
306  
-        attachment.send(:queue_existing_for_delete)
307  
-        attachment.send(:flush_deletes)
308  
-      end
309  
-    end
310  
-  end
311  
-
312  
-end
313  
-
314  
-# Set it all up.
315  
-if Object.const_defined?("ActiveRecord")
316  
-  ActiveRecord::Base.send(:include, Paperclip)
317  
-  File.send(:include, Paperclip::Upfile)
318  
-end
396  vendor/plugins/paperclip/lib/paperclip/attachment.rb
... ...
@@ -1,396 +0,0 @@
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/:basename.:extension",
10  
-        :path          => ":rails_root/public/system/:attachment/:id/:style/:basename.:extension",
11  
-        :styles        => {},
12  
-        :default_url   => "/:attachment/:style/missing.png",
13  
-        :default_style => :original,
14  
-        :validations   => {},
15  
-        :storage       => :filesystem
16  
-      }
17  
-    end
18  
-
19  
-    attr_reader :name, :instance, :styles, :default_style, :convert_options, :queued_for_write
20  
-
21  
-    # Creates an Attachment object. +name+ is the name of the attachment,
22  
-    # +instance+ is the ActiveRecord object instance it's attached to, and
23  
-    # +options+ is the same as the hash passed to +has_attached_file+.
24  
-    def initialize name, instance, options = {}
25  
-      @name              = name
26  
-      @instance          = instance
27  
-
28  
-      options = self.class.default_options.merge(options)
29  
-
30  
-      @url               = options[:url]
31  
-      @path              = options[:path]
32  
-      @styles            = options[:styles]
33  
-      @default_url       = options[:default_url]
34  
-      @validations       = options[:validations]
35  
-      @default_style     = options[:default_style]
36  
-      @storage           = options[:storage]
37  
-      @whiny             = options[:whiny_thumbnails]
38  
-      @convert_options   = options[:convert_options] || {}
39  
-      @processors        = options[:processors] || [:thumbnail]
40  
-      @options           = options
41  
-      @queued_for_delete = []
42  
-      @queued_for_write  = {}
43  
-      @errors            = {}
44  
-      @validation_errors = nil
45  
-      @dirty             = false
46  
-
47  
-      normalize_style_definition
48  
-      initialize_storage
49  
-
50  
-      log("Paperclip attachment #{name} on #{instance.class} initialized.")
51  
-    end
52  
-
53  
-    # What gets called when you call instance.attachment = File. It clears
54  
-    # errors, assigns attributes, processes the file, and runs validations. It
55  
-    # also queues up the previous file for deletion, to be flushed away on
56  
-    # #save of its host.  In addition to form uploads, you can also assign
57  
-    # another Paperclip attachment: 
58  
-    #   new_user.avatar = old_user.avatar
59  
-    # If the file that is assigned is not valid, the processing (i.e.
60  
-    # thumbnailing, etc) will NOT be run.
61  
-    def assign uploaded_file
62  
-      %w(file_name).each do |field|
63  
-        unless @instance.class.column_names.include?("#{name}_#{field}")
64  
-          raise PaperclipError.new("#{@instance.class} model does not have required column '#{name}_#{field}'")
65  
-        end
66  
-      end
67  
-
68  
-      if uploaded_file.is_a?(Paperclip::Attachment)
69  
-        uploaded_file = uploaded_file.to_file(:original)
70  
-        close_uploaded_file = uploaded_file.respond_to?(:close)
71  
-      end
72  
-
73  
-      return nil unless valid_assignment?(uploaded_file)
74  
-      log("Assigning #{uploaded_file.inspect} to #{name}")
75  
-
76  
-      uploaded_file.binmode if uploaded_file.respond_to? :binmode
77  
-      queue_existing_for_delete
78  
-      @errors            = {}
79  
-      @validation_errors = nil
80  
-
81  
-      return nil if uploaded_file.nil?
82  
-
83  
-      log("Writing attributes for #{name}")
84  
-      @queued_for_write[:original]   = uploaded_file.to_tempfile
85  
-      instance_write(:file_name,       uploaded_file.original_filename.strip.gsub(/[^\w\d\.\-]+/, '_'))
86  
-      instance_write(:content_type,    uploaded_file.content_type.to_s.strip)
87  
-      instance_write(:file_size,       uploaded_file.size.to_i)
88  
-      instance_write(:updated_at,      Time.now)
89  
-
90  
-      @dirty = true
91  
-
92  
-      solidify_style_definitions
93  
-      post_process if valid?
94  
- 
95  
-      # Reset the file size if the original file was reprocessed.
96  
-      instance_write(:file_size, @queued_for_write[:original].size.to_i)
97  
-    ensure
98  
-      uploaded_file.close if close_uploaded_file
99  
-      validate
100  
-    end
101  
-
102  
-    # Returns the public URL of the attachment, with a given style. Note that
103  
-    # this does not necessarily need to point to a file that your web server
104  
-    # can access and can point to an action in your app, if you need fine
105  
-    # grained security.  This is not recommended if you don't need the
106  
-    # security, however, for performance reasons.  set
107  
-    # include_updated_timestamp to false if you want to stop the attachment
108  
-    # update time appended to the url
109  
-    def url style = default_style, include_updated_timestamp = true
110  
-      url = original_filename.nil? ? interpolate(@default_url, style) : interpolate(@url, style)
111  
-      include_updated_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url
112  
-    end
113  
-
114  
-    # Returns the path of the attachment as defined by the :path option. If the
115  
-    # file is stored in the filesystem the path refers to the path of the file
116  
-    # on disk. If the file is stored in S3, the path is the "key" part of the
117  
-    # URL, and the :bucket option refers to the S3 bucket.
118  
-    def path style = nil #:nodoc:
119  
-      original_filename.nil? ? nil : interpolate(@path, style)
120  
-    end
121  
-
122  
-    # Alias to +url+
123  
-    def to_s style = nil
124  
-      url(style)
125  
-    end
126  
-
127  
-    # Returns true if there are no errors on this attachment.
128  
-    def valid?
129  
-      validate
130  
-      errors.empty?
131  
-    end
132  
-
133  
-    # Returns an array containing the errors on this attachment.
134  
-    def errors
135  
-      @errors
136  
-    end
137  
-
138  
-    # Returns true if there are changes that need to be saved.
139  
-    def dirty?
140  
-      @dirty
141  
-    end
142  
-
143  
-    # Saves the file, if there are no errors. If there are, it flushes them to
144  
-    # the instance's errors and returns false, cancelling the save.
145  
-    def save
146  
-      if valid?
147  
-        log("Saving files for #{name}")
148  
-        flush_deletes
149  
-        flush_writes
150  
-        @dirty = false
151  
-        true
152  
-      else
153  
-        log("Errors on #{name}. Not saving.")
154  
-        flush_errors
155  
-        false
156  
-      end
157  
-    end
158  
-
159  
-    # Returns the name of the file as originally assigned, and lives in the
160  
-    # <attachment>_file_name attribute of the model.
161  
-    def original_filename
162  
-      instance_read(:file_name)
163  
-    end
164  
-
165  
-    # Returns the size of the file as originally assigned, and lives in the
166  
-    # <attachment>_file_size attribute of the model.
167  
-    def size
168  
-      instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size)
169  
-    end
170  
-
171  
-    # Returns the content_type of the file as originally assigned, and lives
172  
-    # in the <attachment>_content_type attribute of the model.
173  
-    def content_type
174  
-      instance_read(:content_type)
175  
-    end
176  
-    
177  
-    # Returns the last modified time of the file as originally assigned, and 
178  
-    # lives in the <attachment>_updated_at attribute of the model.
179  
-    def updated_at
180  
-      time = instance_read(:updated_at)
181  
-      time && time.to_i
182  
-    end
183  
-
184  
-    # A hash of procs that are run during the interpolation of a path or url.
185  
-    # A variable of the format :name will be replaced with the return value of
186  
-    # the proc named ":name". Each lambda takes the attachment and the current
187  
-    # style as arguments. This hash can be added to with your own proc if
188  
-    # necessary.
189  
-    def self.interpolations
190  
-      @interpolations ||= {
191  
-        :rails_root   => lambda{|attachment,style| RAILS_ROOT },
192  
-        :rails_env    => lambda{|attachment,style| RAILS_ENV },
193  
-        :class        => lambda do |attachment,style|
194  
-                           attachment.instance.class.name.underscore.pluralize
195  
-                         end,
196  
-        :basename     => lambda do |attachment,style|
197  
-                           attachment.original_filename.gsub(/#{File.extname(attachment.original_filename)}$/, "")
198  
-                         end,
199  
-        :extension    => lambda do |attachment,style| 
200  
-                           ((style = attachment.styles[style]) && style[:format]) ||
201  
-                           File.extname(attachment.original_filename).gsub(/^\.+/, "")
202  
-                         end,
203  
-        :id           => lambda{|attachment,style| attachment.instance.id },
204  
-        :id_partition => lambda do |attachment, style|
205  
-                           ("%09d" % attachment.instance.id).scan(/\d{3}/).join("/")
206  
-                         end,
207  
-        :attachment   => lambda{|attachment,style| attachment.name.to_s.downcase.pluralize },
208  
-        :style        => lambda{|attachment,style| style || attachment.default_style },
209  
-      }
210  
-    end
211  
-
212  
-    # This method really shouldn't be called that often. It's expected use is
213  
-    # in the paperclip:refresh rake task and that's it. It will regenerate all
214  
-    # thumbnails forcefully, by reobtaining the original file and going through
215  
-    # the post-process again.
216  
-    def reprocess!
217  
-      new_original = Tempfile.new("paperclip-reprocess")
218  
-      new_original.binmode
219  
-      if old_original = to_file(:original)
220  
-        new_original.write( old_original.read )
221  
-        new_original.rewind
222  
-
223  
-        @queued_for_write = { :original => new_original }
224  
-        post_process
225  
-
226  
-        old_original.close if old_original.respond_to?(:close)
227  
-
228  
-        save
229  
-      else
230  
-        true
231  
-      end
232  
-    end
233  
-    
234  
-    # Returns true if a file has been assigned.
235  
-    def file?
236  
-      !original_filename.blank?
237  
-    end
238  
-
239  
-    # Writes the attachment-specific attribute on the instance. For example,
240  
-    # instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's
241  
-    # "avatar_file_name" field (assuming the attachment is called avatar).
242  
-    def instance_write(attr, value)
243  
-      setter = :"#{name}_#{attr}="
244  
-      responds = instance.respond_to?(setter)
245  
-      self.instance_variable_set("@_#{setter.to_s.chop}", value)
246  
-      instance.send(setter, value) if responds || attr.to_s == "file_name"
247  
-    end
248  
-
249  
-    # Reads the attachment-specific attribute on the instance. See instance_write
250  
-    # for more details.
251  
-    def instance_read(attr)
252  
-      getter = :"#{name}_#{attr}"
253  
-      responds = instance.respond_to?(getter)
254  
-      cached = self.instance_variable_get("@_#{getter}")
255  
-      return cached if cached
256  
-      instance.send(getter) if responds || attr.to_s == "file_name"
257  
-    end
258  
-
259  
-    private
260  
-
261  
-    def logger #:nodoc:
262  
-      instance.logger
263  
-    end
264  
-
265  
-    def log message #:nodoc:
266  
-      logger.info("[paperclip] #{message}") if logging?
267  
-    end
268  
-
269  
-    def logging? #:nodoc:
270  
-      Paperclip.options[:log]
271  
-    end
272  
-
273  
-    def valid_assignment? file #:nodoc:
274  
-      file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type))
275  
-    end
276  
-
277  
-    def validate #:nodoc:
278  
-      unless @validation_errors
279  
-        @validation_errors = @validations.inject({}) do |errors, validation|
280  
-          name, block = validation
281  
-          errors[name] = block.call(self, instance) if block
282  
-          errors
283  
-        end
284  
-        @validation_errors.reject!{|k,v| v == nil }
285  
-        @errors.merge!(@validation_errors)
286  
-      end
287  
-      @validation_errors
288  
-    end
289  
-
290  
-    def normalize_style_definition #:nodoc:
291  
-      @styles.each do |name, args|
292  
-        unless args.is_a? Hash
293  
-          dimensions, format = [args, nil].flatten[0..1]
294  
-          format             = nil if format.blank?
295  
-          @styles[name]      = {
296  
-            :processors      => @processors,
297  
-            :geometry        => dimensions,
298  
-            :format          => format,
299  
-            :whiny           => @whiny,
300  
-            :convert_options => extra_options_for(name)
301  
-          }
302  
-        else
303  
-          @styles[name] = {
304  
-            :processors => @processors,
305  
-            :whiny => @whiny,
306  
-            :convert_options => extra_options_for(name)
307  
-          }.merge(@styles[name])
308  
-        end
309  
-      end
310  
-    end
311  
-
312  
-    def solidify_style_definitions #:nodoc:
313  
-      @styles.each do |name, args|
314  
-        if @styles[name][:geometry].respond_to?(:call)
315  
-          @styles[name][:geometry] = @styles[name][:geometry].call(instance) 
316  
-        end
317  
-      end
318  
-    end
319  
-
320  
-    def initialize_storage #:nodoc:
321  
-      @storage_module = Paperclip::Storage.const_get(@storage.to_s.capitalize)
322  
-      self.extend(@storage_module)
323  
-    end
324  
-
325  
-    def extra_options_for(style) #:nodoc:
326  
-      all_options   = convert_options[:all]
327  
-      all_options   = all_options.call(instance)   if all_options.respond_to?(:call)
328  
-      style_options = convert_options[style]
329  
-      style_options = style_options.call(instance) if style_options.respond_to?(:call)
330  
-
331  
-      [ style_options, all_options ].compact.join(" ")
332  
-    end