Commit eb5546cefff84ef53c305e3dd52d0bb5e0d29ddc
1 parent
8a3201bc
Exists in
master
and in
1 other branch
replaced thoughtbot-paperclip with tristandunn-paperclip
Showing
94 changed files
with
5038 additions
and
4959 deletions
Show diff stats
vendor/gems/thoughtbot-paperclip-2.2.9.2/.specification
| ... | ... | @@ -1,126 +0,0 @@ |
| 1 | ---- !ruby/object:Gem::Specification | |
| 2 | -name: thoughtbot-paperclip | |
| 3 | -version: !ruby/object:Gem::Version | |
| 4 | - version: 2.2.9.2 | |
| 5 | -platform: ruby | |
| 6 | -authors: | |
| 7 | -- Jon Yurek | |
| 8 | -autorequire: | |
| 9 | -bindir: bin | |
| 10 | -cert_chain: [] | |
| 11 | - | |
| 12 | -date: 2009-06-18 00:00:00 -04:00 | |
| 13 | -default_executable: | |
| 14 | -dependencies: | |
| 15 | -- !ruby/object:Gem::Dependency | |
| 16 | - name: thoughtbot-shoulda | |
| 17 | - type: :development | |
| 18 | - version_requirement: | |
| 19 | - version_requirements: !ruby/object:Gem::Requirement | |
| 20 | - requirements: | |
| 21 | - - - ">=" | |
| 22 | - - !ruby/object:Gem::Version | |
| 23 | - version: "0" | |
| 24 | - version: | |
| 25 | -- !ruby/object:Gem::Dependency | |
| 26 | - name: mocha | |
| 27 | - type: :development | |
| 28 | - version_requirement: | |
| 29 | - version_requirements: !ruby/object:Gem::Requirement | |
| 30 | - requirements: | |
| 31 | - - - ">=" | |
| 32 | - - !ruby/object:Gem::Version | |
| 33 | - version: "0" | |
| 34 | - version: | |
| 35 | -description: | |
| 36 | -email: jyurek@thoughtbot.com | |
| 37 | -executables: [] | |
| 38 | - | |
| 39 | -extensions: [] | |
| 40 | - | |
| 41 | -extra_rdoc_files: | |
| 42 | -- README.rdoc | |
| 43 | -files: | |
| 44 | -- README.rdoc | |
| 45 | -- LICENSE | |
| 46 | -- Rakefile | |
| 47 | -- init.rb | |
| 48 | -- generators/paperclip | |
| 49 | -- generators/paperclip/paperclip_generator.rb | |
| 50 | -- generators/paperclip/templates | |
| 51 | -- generators/paperclip/templates/paperclip_migration.rb.erb | |
| 52 | -- generators/paperclip/USAGE | |
| 53 | -- lib/paperclip | |
| 54 | -- lib/paperclip/attachment.rb | |
| 55 | -- lib/paperclip/callback_compatability.rb | |
| 56 | -- lib/paperclip/geometry.rb | |
| 57 | -- lib/paperclip/interpolations.rb | |
| 58 | -- lib/paperclip/iostream.rb | |
| 59 | -- lib/paperclip/matchers | |
| 60 | -- lib/paperclip/matchers/have_attached_file_matcher.rb | |
| 61 | -- lib/paperclip/matchers/validate_attachment_content_type_matcher.rb | |
| 62 | -- lib/paperclip/matchers/validate_attachment_presence_matcher.rb | |
| 63 | -- lib/paperclip/matchers/validate_attachment_size_matcher.rb | |
| 64 | -- lib/paperclip/matchers.rb | |
| 65 | -- lib/paperclip/processor.rb | |
| 66 | -- lib/paperclip/storage.rb | |
| 67 | -- lib/paperclip/thumbnail.rb | |
| 68 | -- lib/paperclip/upfile.rb | |
| 69 | -- lib/paperclip.rb | |
| 70 | -- tasks/paperclip_tasks.rake | |
| 71 | -- test/attachment_test.rb | |
| 72 | -- test/database.yml | |
| 73 | -- test/fixtures | |
| 74 | -- test/fixtures/12k.png | |
| 75 | -- test/fixtures/50x50.png | |
| 76 | -- test/fixtures/5k.png | |
| 77 | -- test/fixtures/bad.png | |
| 78 | -- test/fixtures/s3.yml | |
| 79 | -- test/fixtures/text.txt | |
| 80 | -- test/fixtures/twopage.pdf | |
| 81 | -- test/geometry_test.rb | |
| 82 | -- test/helper.rb | |
| 83 | -- test/integration_test.rb | |
| 84 | -- test/interpolations_test.rb | |
| 85 | -- test/iostream_test.rb | |
| 86 | -- test/matchers | |
| 87 | -- test/matchers/have_attached_file_matcher_test.rb | |
| 88 | -- test/matchers/validate_attachment_content_type_matcher_test.rb | |
| 89 | -- test/matchers/validate_attachment_presence_matcher_test.rb | |
| 90 | -- test/matchers/validate_attachment_size_matcher_test.rb | |
| 91 | -- test/paperclip_test.rb | |
| 92 | -- test/processor_test.rb | |
| 93 | -- test/storage_test.rb | |
| 94 | -- test/thumbnail_test.rb | |
| 95 | -- shoulda_macros/paperclip.rb | |
| 96 | -has_rdoc: true | |
| 97 | -homepage: http://www.thoughtbot.com/projects/paperclip | |
| 98 | -licenses: [] | |
| 99 | - | |
| 100 | -post_install_message: | |
| 101 | -rdoc_options: | |
| 102 | -- --line-numbers | |
| 103 | -- --inline-source | |
| 104 | -require_paths: | |
| 105 | -- lib | |
| 106 | -required_ruby_version: !ruby/object:Gem::Requirement | |
| 107 | - requirements: | |
| 108 | - - - ">=" | |
| 109 | - - !ruby/object:Gem::Version | |
| 110 | - version: "0" | |
| 111 | - version: | |
| 112 | -required_rubygems_version: !ruby/object:Gem::Requirement | |
| 113 | - requirements: | |
| 114 | - - - ">=" | |
| 115 | - - !ruby/object:Gem::Version | |
| 116 | - version: "0" | |
| 117 | - version: | |
| 118 | -requirements: | |
| 119 | -- ImageMagick | |
| 120 | -rubyforge_project: paperclip | |
| 121 | -rubygems_version: 1.3.4 | |
| 122 | -signing_key: | |
| 123 | -specification_version: 2 | |
| 124 | -summary: File attachments as attributes for ActiveRecord | |
| 125 | -test_files: [] | |
| 126 | - |
vendor/gems/thoughtbot-paperclip-2.2.9.2/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 | - |
vendor/gems/thoughtbot-paperclip-2.2.9.2/README.rdoc
| ... | ... | @@ -1,174 +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 ":rails_root/public/system/:attachment/:id/:style/:filename". This | |
| 83 | -location was chosen because on standard Capistrano deployments, the | |
| 84 | -public/system directory is symlinked to the app's shared directory, meaning it | |
| 85 | -will survive between deployments. For example, using that :path, you may have a | |
| 86 | -file at | |
| 87 | - | |
| 88 | - /data/myapp/releases/20081229172410/public/system/avatars/13/small/my_pic.png | |
| 89 | - | |
| 90 | -NOTE: This is a change from previous versions of Paperclip, but is overall a | |
| 91 | -safer choice for the default file store. | |
| 92 | - | |
| 93 | -You may also choose to store your files using Amazon's S3 service. You can find | |
| 94 | -more information about S3 storage at the description for | |
| 95 | -Paperclip::Storage::S3. | |
| 96 | - | |
| 97 | -Files on the local filesystem (and in the Rails app's public directory) will be | |
| 98 | -available to the internet at large. If you require access control, it's | |
| 99 | -possible to place your files in a different location. You will need to change | |
| 100 | -both the :path and :url options in order to make sure the files are unavailable | |
| 101 | -to the public. Both :path and :url allow the same set of interpolated | |
| 102 | -variables. | |
| 103 | - | |
| 104 | -==Post Processing | |
| 105 | - | |
| 106 | -Paperclip supports an extensible selection of post-processors. When you define | |
| 107 | -a set of styles for an attachment, by default it is expected that those | |
| 108 | -"styles" are actually "thumbnails". However, you can do much more than just | |
| 109 | -thumbnail images. By defining a subclass of Paperclip::Processor, you can | |
| 110 | -perform any processing you want on the files that are attached. Any file in | |
| 111 | -your Rails app's lib/paperclip_processors directory is automatically loaded by | |
| 112 | -paperclip, allowing you to easily define custom processors. You can specify a | |
| 113 | -processor with the :processors option to has_attached_file: | |
| 114 | - | |
| 115 | - has_attached_file :scan, :styles => { :text => { :quality => :better } }, | |
| 116 | - :processors => [:ocr] | |
| 117 | - | |
| 118 | -This would load the hypothetical class Paperclip::Ocr, which would have the | |
| 119 | -hash "{ :quality => :better }" passed to it along with the uploaded file. For | |
| 120 | -more information about defining processors, see Paperclip::Processor. | |
| 121 | - | |
| 122 | -The default processor is Paperclip::Thumbnail. For backwards compatability | |
| 123 | -reasons, you can pass a single geometry string or an array containing a | |
| 124 | -geometry and a format, which the file will be converted to, like so: | |
| 125 | - | |
| 126 | - has_attached_file :avatar, :styles => { :thumb => ["32x32#", :png] } | |
| 127 | - | |
| 128 | -This will convert the "thumb" style to a 32x32 square in png format, regardless | |
| 129 | -of what was uploaded. If the format is not specified, it is kept the same (i.e. | |
| 130 | -jpgs will remain jpgs). | |
| 131 | - | |
| 132 | -Multiple processors can be specified, and they will be invoked in the order | |
| 133 | -they are defined in the :processors array. Each successive processor will | |
| 134 | -be given the result of the previous processor's execution. All processors will | |
| 135 | -receive the same parameters, which are what you define in the :styles hash. | |
| 136 | -For example, assuming we had this definition: | |
| 137 | - | |
| 138 | - has_attached_file :scan, :styles => { :text => { :quality => :better } }, | |
| 139 | - :processors => [:rotator, :ocr] | |
| 140 | - | |
| 141 | -then both the :rotator processor and the :ocr processor would receive the | |
| 142 | -options "{ :quality => :better }". This parameter may not mean anything to one | |
| 143 | -or more or the processors, and they are expected to ignore it. | |
| 144 | - | |
| 145 | -NOTE: Because processors operate by turning the original attachment into the | |
| 146 | -styles, no processors will be run if there are no styles defined. | |
| 147 | - | |
| 148 | -==Events | |
| 149 | - | |
| 150 | -Before and after the Post Processing step, Paperclip calls back to the model | |
| 151 | -with a few callbacks, allowing the model to change or cancel the processing | |
| 152 | -step. The callbacks are "before_post_process" and "after_post_process" (which | |
| 153 | -are called before and after the processing of each attachment), and the | |
| 154 | -attachment-specific "before_<attachment>_post_process" and | |
| 155 | -"after_<attachment>_post_process". The callbacks are intended to be as close to | |
| 156 | -normal ActiveRecord callbacks as possible, so if you return false (specifically | |
| 157 | -- returning nil is not the same) in a before_ filter, the post processing step | |
| 158 | -will halt. Returning false in an after_ filter will not halt anything, but you | |
| 159 | -can access the model and the attachment if necessary. | |
| 160 | - | |
| 161 | -NOTE: Post processing will not even *start* if the attachment is not valid | |
| 162 | -according to the validations. Your callbacks and processors will *only* be | |
| 163 | -called with valid attachments. | |
| 164 | - | |
| 165 | -==Contributing | |
| 166 | - | |
| 167 | -If you'd like to contribute a feature or bugfix: Thanks! To make sure your | |
| 168 | -fix/feature has a high chance of being included, please read the following | |
| 169 | -guidelines: | |
| 170 | - | |
| 171 | -1. Ask on the mailing list, or post a new GitHub Issue. | |
| 172 | -2. Make sure there are tests! We will not accept any patch that is not tested. | |
| 173 | - It's a rare time when explicit tests aren't needed. If you have questions | |
| 174 | - about writing tests for paperclip, please ask the mailing list. |
vendor/gems/thoughtbot-paperclip-2.2.9.2/Rakefile
| ... | ... | @@ -1,99 +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 | - Dir.glob("paperclip-*.gem").each{|f| FileUtils.rm f } | |
| 46 | -end | |
| 47 | - | |
| 48 | -include_file_globs = ["README*", | |
| 49 | - "LICENSE", | |
| 50 | - "Rakefile", | |
| 51 | - "init.rb", | |
| 52 | - "{generators,lib,tasks,test,shoulda_macros}/**/*"] | |
| 53 | -exclude_file_globs = ["test/s3.yml", | |
| 54 | - "test/debug.log", | |
| 55 | - "test/paperclip.db", | |
| 56 | - "test/doc", | |
| 57 | - "test/doc/*", | |
| 58 | - "test/pkg", | |
| 59 | - "test/pkg/*", | |
| 60 | - "test/tmp", | |
| 61 | - "test/tmp/*"] | |
| 62 | -spec = Gem::Specification.new do |s| | |
| 63 | - s.name = "paperclip" | |
| 64 | - s.version = Paperclip::VERSION | |
| 65 | - s.author = "Jon Yurek" | |
| 66 | - s.email = "jyurek@thoughtbot.com" | |
| 67 | - s.homepage = "http://www.thoughtbot.com/projects/paperclip" | |
| 68 | - s.platform = Gem::Platform::RUBY | |
| 69 | - s.summary = "File attachments as attributes for ActiveRecord" | |
| 70 | - s.files = FileList[include_file_globs].to_a - FileList[exclude_file_globs].to_a | |
| 71 | - s.require_path = "lib" | |
| 72 | - s.test_files = FileList["test/**/test_*.rb"].to_a | |
| 73 | - s.rubyforge_project = "paperclip" | |
| 74 | - s.has_rdoc = true | |
| 75 | - s.extra_rdoc_files = FileList["README*"].to_a | |
| 76 | - s.rdoc_options << '--line-numbers' << '--inline-source' | |
| 77 | - s.requirements << "ImageMagick" | |
| 78 | - s.add_development_dependency 'thoughtbot-shoulda' | |
| 79 | - s.add_development_dependency 'mocha' | |
| 80 | -end | |
| 81 | - | |
| 82 | -desc "Print a list of the files to be put into the gem" | |
| 83 | -task :manifest => :clean do | |
| 84 | - spec.files.each do |file| | |
| 85 | - puts file | |
| 86 | - end | |
| 87 | -end | |
| 88 | - | |
| 89 | -desc "Generate a gemspec file for GitHub" | |
| 90 | -task :gemspec => :clean do | |
| 91 | - File.open("#{spec.name}.gemspec", 'w') do |f| | |
| 92 | - f.write spec.to_ruby | |
| 93 | - end | |
| 94 | -end | |
| 95 | - | |
| 96 | -desc "Build the gem into the current directory" | |
| 97 | -task :gem => :gemspec do | |
| 98 | - `gem build #{spec.name}.gemspec` | |
| 99 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/generators/paperclip/USAGE
vendor/gems/thoughtbot-paperclip-2.2.9.2/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 |
vendor/gems/thoughtbot-paperclip-2.2.9.2/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 |
vendor/gems/thoughtbot-paperclip-2.2.9.2/init.rb
| ... | ... | @@ -1 +0,0 @@ |
| 1 | -require File.join(File.dirname(__FILE__), "lib", "paperclip") |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip.rb
| ... | ... | @@ -1,350 +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-2009 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/interpolations' | |
| 36 | -require 'paperclip/attachment' | |
| 37 | -if defined? RAILS_ROOT | |
| 38 | - Dir.glob(File.join(File.expand_path(RAILS_ROOT), "lib", "paperclip_processors", "*.rb")).each do |processor| | |
| 39 | - require processor | |
| 40 | - end | |
| 41 | -end | |
| 42 | - | |
| 43 | -# The base module that gets included in ActiveRecord::Base. See the | |
| 44 | -# documentation for Paperclip::ClassMethods for more useful information. | |
| 45 | -module Paperclip | |
| 46 | - | |
| 47 | - VERSION = "2.2.9.2" | |
| 48 | - | |
| 49 | - class << self | |
| 50 | - # Provides configurability to Paperclip. There are a number of options available, such as: | |
| 51 | - # * whiny: Will raise an error if Paperclip cannot process thumbnails of | |
| 52 | - # an uploaded image. Defaults to true. | |
| 53 | - # * log: Logs progress to the Rails log. Uses ActiveRecord's logger, so honors | |
| 54 | - # log levels, etc. Defaults to true. | |
| 55 | - # * command_path: Defines the path at which to find the command line | |
| 56 | - # programs if they are not visible to Rails the system's search path. Defaults to | |
| 57 | - # nil, which uses the first executable found in the user's search path. | |
| 58 | - # * image_magick_path: Deprecated alias of command_path. | |
| 59 | - def options | |
| 60 | - @options ||= { | |
| 61 | - :whiny => true, | |
| 62 | - :image_magick_path => nil, | |
| 63 | - :command_path => nil, | |
| 64 | - :log => true, | |
| 65 | - :log_command => false, | |
| 66 | - :swallow_stderr => true | |
| 67 | - } | |
| 68 | - end | |
| 69 | - | |
| 70 | - def path_for_command command #:nodoc: | |
| 71 | - if options[:image_magick_path] | |
| 72 | - warn("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead") | |
| 73 | - end | |
| 74 | - path = [options[:command_path] || options[:image_magick_path], command].compact | |
| 75 | - File.join(*path) | |
| 76 | - end | |
| 77 | - | |
| 78 | - def interpolates key, &block | |
| 79 | - Paperclip::Interpolations[key] = block | |
| 80 | - end | |
| 81 | - | |
| 82 | - # The run method takes a command to execute and a string of parameters | |
| 83 | - # that get passed to it. The command is prefixed with the :command_path | |
| 84 | - # option from Paperclip.options. If you have many commands to run and | |
| 85 | - # they are in different paths, the suggested course of action is to | |
| 86 | - # symlink them so they are all in the same directory. | |
| 87 | - # | |
| 88 | - # If the command returns with a result code that is not one of the | |
| 89 | - # expected_outcodes, a PaperclipCommandLineError will be raised. Generally | |
| 90 | - # a code of 0 is expected, but a list of codes may be passed if necessary. | |
| 91 | - # | |
| 92 | - # This method can log the command being run when | |
| 93 | - # Paperclip.options[:log_command] is set to true (defaults to false). This | |
| 94 | - # will only log if logging in general is set to true as well. | |
| 95 | - def run cmd, params = "", expected_outcodes = 0 | |
| 96 | - command = %Q<#{%Q[#{path_for_command(cmd)} #{params}].gsub(/\s+/, " ")}> | |
| 97 | - command = "#{command} 2>#{bit_bucket}" if Paperclip.options[:swallow_stderr] | |
| 98 | - Paperclip.log(command) if Paperclip.options[:log_command] | |
| 99 | - output = `#{command}` | |
| 100 | - unless [expected_outcodes].flatten.include?($?.exitstatus) | |
| 101 | - raise PaperclipCommandLineError, "Error while running #{cmd}" | |
| 102 | - end | |
| 103 | - output | |
| 104 | - end | |
| 105 | - | |
| 106 | - def bit_bucket #:nodoc: | |
| 107 | - File.exists?("/dev/null") ? "/dev/null" : "NUL" | |
| 108 | - end | |
| 109 | - | |
| 110 | - def included base #:nodoc: | |
| 111 | - base.extend ClassMethods | |
| 112 | - unless base.respond_to?(:define_callbacks) | |
| 113 | - base.send(:include, Paperclip::CallbackCompatability) | |
| 114 | - end | |
| 115 | - end | |
| 116 | - | |
| 117 | - def processor name #:nodoc: | |
| 118 | - name = name.to_s.camelize | |
| 119 | - processor = Paperclip.const_get(name) | |
| 120 | - unless processor.ancestors.include?(Paperclip::Processor) | |
| 121 | - raise PaperclipError.new("Processor #{name} was not found") | |
| 122 | - end | |
| 123 | - processor | |
| 124 | - end | |
| 125 | - | |
| 126 | - # Log a paperclip-specific line. Uses ActiveRecord::Base.logger | |
| 127 | - # by default. Set Paperclip.options[:log] to false to turn off. | |
| 128 | - def log message | |
| 129 | - logger.info("[paperclip] #{message}") if logging? | |
| 130 | - end | |
| 131 | - | |
| 132 | - def logger #:nodoc: | |
| 133 | - ActiveRecord::Base.logger | |
| 134 | - end | |
| 135 | - | |
| 136 | - def logging? #:nodoc: | |
| 137 | - options[:log] | |
| 138 | - end | |
| 139 | - end | |
| 140 | - | |
| 141 | - class PaperclipError < StandardError #:nodoc: | |
| 142 | - end | |
| 143 | - | |
| 144 | - class PaperclipCommandLineError < StandardError #:nodoc: | |
| 145 | - end | |
| 146 | - | |
| 147 | - class NotIdentifiedByImageMagickError < PaperclipError #:nodoc: | |
| 148 | - end | |
| 149 | - | |
| 150 | - class InfiniteInterpolationError < PaperclipError #:nodoc: | |
| 151 | - end | |
| 152 | - | |
| 153 | - module ClassMethods | |
| 154 | - # +has_attached_file+ gives the class it is called on an attribute that maps to a file. This | |
| 155 | - # is typically a file stored somewhere on the filesystem and has been uploaded by a user. | |
| 156 | - # The attribute returns a Paperclip::Attachment object which handles the management of | |
| 157 | - # that file. The intent is to make the attachment as much like a normal attribute. The | |
| 158 | - # thumbnails will be created when the new file is assigned, but they will *not* be saved | |
| 159 | - # until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is | |
| 160 | - # called on it, the attachment will *not* be deleted until +save+ is called. See the | |
| 161 | - # Paperclip::Attachment documentation for more specifics. There are a number of options | |
| 162 | - # you can set to change the behavior of a Paperclip attachment: | |
| 163 | - # * +url+: The full URL of where the attachment is publically accessible. This can just | |
| 164 | - # as easily point to a directory served directly through Apache as it can to an action | |
| 165 | - # that can control permissions. You can specify the full domain and path, but usually | |
| 166 | - # just an absolute path is sufficient. The leading slash *must* be included manually for | |
| 167 | - # absolute paths. The default value is | |
| 168 | - # "/system/:attachment/:id/:style/:filename". See | |
| 169 | - # Paperclip::Attachment#interpolate for more information on variable interpolaton. | |
| 170 | - # :url => "/:class/:attachment/:id/:style_:filename" | |
| 171 | - # :url => "http://some.other.host/stuff/:class/:id_:extension" | |
| 172 | - # * +default_url+: The URL that will be returned if there is no attachment assigned. | |
| 173 | - # This field is interpolated just as the url is. The default value is | |
| 174 | - # "/:attachment/:style/missing.png" | |
| 175 | - # has_attached_file :avatar, :default_url => "/images/default_:style_avatar.png" | |
| 176 | - # User.new.avatar_url(:small) # => "/images/default_small_avatar.png" | |
| 177 | - # * +styles+: A hash of thumbnail styles and their geometries. You can find more about | |
| 178 | - # geometry strings at the ImageMagick website | |
| 179 | - # (http://www.imagemagick.org/script/command-line-options.php#resize). Paperclip | |
| 180 | - # also adds the "#" option (e.g. "50x50#"), which will resize the image to fit maximally | |
| 181 | - # inside the dimensions and then crop the rest off (weighted at the center). The | |
| 182 | - # default value is to generate no thumbnails. | |
| 183 | - # * +default_style+: The thumbnail style that will be used by default URLs. | |
| 184 | - # Defaults to +original+. | |
| 185 | - # has_attached_file :avatar, :styles => { :normal => "100x100#" }, | |
| 186 | - # :default_style => :normal | |
| 187 | - # user.avatar.url # => "/avatars/23/normal_me.png" | |
| 188 | - # * +whiny+: Will raise an error if Paperclip cannot post_process an uploaded file due | |
| 189 | - # to a command line error. This will override the global setting for this attachment. | |
| 190 | - # Defaults to true. This option used to be called :whiny_thumbanils, but this is | |
| 191 | - # deprecated. | |
| 192 | - # * +convert_options+: When creating thumbnails, use this free-form options | |
| 193 | - # field to pass in various convert command options. Typical options are "-strip" to | |
| 194 | - # remove all Exif data from the image (save space for thumbnails and avatars) or | |
| 195 | - # "-depth 8" to specify the bit depth of the resulting conversion. See ImageMagick | |
| 196 | - # convert documentation for more options: (http://www.imagemagick.org/script/convert.php) | |
| 197 | - # Note that this option takes a hash of options, each of which correspond to the style | |
| 198 | - # of thumbnail being generated. You can also specify :all as a key, which will apply | |
| 199 | - # to all of the thumbnails being generated. If you specify options for the :original, | |
| 200 | - # it would be best if you did not specify destructive options, as the intent of keeping | |
| 201 | - # the original around is to regenerate all the thumbnails when requirements change. | |
| 202 | - # has_attached_file :avatar, :styles => { :large => "300x300", :negative => "100x100" } | |
| 203 | - # :convert_options => { | |
| 204 | - # :all => "-strip", | |
| 205 | - # :negative => "-negate" | |
| 206 | - # } | |
| 207 | - # NOTE: While not deprecated yet, it is not recommended to specify options this way. | |
| 208 | - # It is recommended that :convert_options option be included in the hash passed to each | |
| 209 | - # :styles for compatability with future versions. | |
| 210 | - # * +storage+: Chooses the storage backend where the files will be stored. The current | |
| 211 | - # choices are :filesystem and :s3. The default is :filesystem. Make sure you read the | |
| 212 | - # documentation for Paperclip::Storage::Filesystem and Paperclip::Storage::S3 | |
| 213 | - # for backend-specific options. | |
| 214 | - def has_attached_file name, options = {} | |
| 215 | - include InstanceMethods | |
| 216 | - | |
| 217 | - write_inheritable_attribute(:attachment_definitions, {}) if attachment_definitions.nil? | |
| 218 | - attachment_definitions[name] = {:validations => []}.merge(options) | |
| 219 | - | |
| 220 | - after_save :save_attached_files | |
| 221 | - before_destroy :destroy_attached_files | |
| 222 | - | |
| 223 | - define_callbacks :before_post_process, :after_post_process | |
| 224 | - define_callbacks :"before_#{name}_post_process", :"after_#{name}_post_process" | |
| 225 | - | |
| 226 | - define_method name do |*args| | |
| 227 | - a = attachment_for(name) | |
| 228 | - (args.length > 0) ? a.to_s(args.first) : a | |
| 229 | - end | |
| 230 | - | |
| 231 | - define_method "#{name}=" do |file| | |
| 232 | - attachment_for(name).assign(file) | |
| 233 | - end | |
| 234 | - | |
| 235 | - define_method "#{name}?" do | |
| 236 | - attachment_for(name).file? | |
| 237 | - end | |
| 238 | - | |
| 239 | - validates_each(name) do |record, attr, value| | |
| 240 | - attachment = record.attachment_for(name) | |
| 241 | - attachment.send(:flush_errors) unless attachment.valid? | |
| 242 | - end | |
| 243 | - end | |
| 244 | - | |
| 245 | - # Places ActiveRecord-style validations on the size of the file assigned. The | |
| 246 | - # possible options are: | |
| 247 | - # * +in+: a Range of bytes (i.e. +1..1.megabyte+), | |
| 248 | - # * +less_than+: equivalent to :in => 0..options[:less_than] | |
| 249 | - # * +greater_than+: equivalent to :in => options[:greater_than]..Infinity | |
| 250 | - # * +message+: error message to display, use :min and :max as replacements | |
| 251 | - # * +if+: A lambda or name of a method on the instance. Validation will only | |
| 252 | - # be run is this lambda or method returns true. | |
| 253 | - # * +unless+: Same as +if+ but validates if lambda or method returns false. | |
| 254 | - def validates_attachment_size name, options = {} | |
| 255 | - min = options[:greater_than] || (options[:in] && options[:in].first) || 0 | |
| 256 | - max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0) | |
| 257 | - range = (min..max) | |
| 258 | - message = options[:message] || "file size must be between :min and :max bytes." | |
| 259 | - | |
| 260 | - attachment_definitions[name][:validations] << [:size, {:range => range, | |
| 261 | - :message => message, | |
| 262 | - :if => options[:if], | |
| 263 | - :unless => options[:unless]}] | |
| 264 | - end | |
| 265 | - | |
| 266 | - # Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true. | |
| 267 | - def validates_attachment_thumbnails name, options = {} | |
| 268 | - warn('[DEPRECATION] validates_attachment_thumbnail is deprecated. ' + | |
| 269 | - 'This validation is on by default and will be removed from future versions. ' + | |
| 270 | - 'If you wish to turn it off, supply :whiny => false in your definition.') | |
| 271 | - attachment_definitions[name][:whiny_thumbnails] = true | |
| 272 | - end | |
| 273 | - | |
| 274 | - # Places ActiveRecord-style validations on the presence of a file. | |
| 275 | - # Options: | |
| 276 | - # * +if+: A lambda or name of a method on the instance. Validation will only | |
| 277 | - # be run is this lambda or method returns true. | |
| 278 | - # * +unless+: Same as +if+ but validates if lambda or method returns false. | |
| 279 | - def validates_attachment_presence name, options = {} | |
| 280 | - message = options[:message] || "must be set." | |
| 281 | - attachment_definitions[name][:validations] << [:presence, {:message => message, | |
| 282 | - :if => options[:if], | |
| 283 | - :unless => options[:unless]}] | |
| 284 | - end | |
| 285 | - | |
| 286 | - # Places ActiveRecord-style validations on the content type of the file | |
| 287 | - # assigned. The possible options are: | |
| 288 | - # * +content_type+: Allowed content types. Can be a single content type | |
| 289 | - # or an array. Each type can be a String or a Regexp. It should be | |
| 290 | - # noted that Internet Explorer upload files with content_types that you | |
| 291 | - # may not expect. For example, JPEG images are given image/pjpeg and | |
| 292 | - # PNGs are image/x-png, so keep that in mind when determining how you | |
| 293 | - # match. Allows all by default. | |
| 294 | - # * +message+: The message to display when the uploaded file has an invalid | |
| 295 | - # content type. | |
| 296 | - # * +if+: A lambda or name of a method on the instance. Validation will only | |
| 297 | - # be run is this lambda or method returns true. | |
| 298 | - # * +unless+: Same as +if+ but validates if lambda or method returns false. | |
| 299 | - # NOTE: If you do not specify an [attachment]_content_type field on your | |
| 300 | - # model, content_type validation will work _ONLY upon assignment_ and | |
| 301 | - # re-validation after the instance has been reloaded will always succeed. | |
| 302 | - def validates_attachment_content_type name, options = {} | |
| 303 | - attachment_definitions[name][:validations] << [:content_type, {:content_type => options[:content_type], | |
| 304 | - :message => options[:message], | |
| 305 | - :if => options[:if], | |
| 306 | - :unless => options[:unless]}] | |
| 307 | - end | |
| 308 | - | |
| 309 | - # Returns the attachment definitions defined by each call to | |
| 310 | - # has_attached_file. | |
| 311 | - def attachment_definitions | |
| 312 | - read_inheritable_attribute(:attachment_definitions) | |
| 313 | - end | |
| 314 | - end | |
| 315 | - | |
| 316 | - module InstanceMethods #:nodoc: | |
| 317 | - def attachment_for name | |
| 318 | - @_paperclip_attachments ||= {} | |
| 319 | - @_paperclip_attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name]) | |
| 320 | - end | |
| 321 | - | |
| 322 | - def each_attachment | |
| 323 | - self.class.attachment_definitions.each do |name, definition| | |
| 324 | - yield(name, attachment_for(name)) | |
| 325 | - end | |
| 326 | - end | |
| 327 | - | |
| 328 | - def save_attached_files | |
| 329 | - logger.info("[paperclip] Saving attachments.") | |
| 330 | - each_attachment do |name, attachment| | |
| 331 | - attachment.send(:save) | |
| 332 | - end | |
| 333 | - end | |
| 334 | - | |
| 335 | - def destroy_attached_files | |
| 336 | - logger.info("[paperclip] Deleting attachments.") | |
| 337 | - each_attachment do |name, attachment| | |
| 338 | - attachment.send(:queue_existing_for_delete) | |
| 339 | - attachment.send(:flush_deletes) | |
| 340 | - end | |
| 341 | - end | |
| 342 | - end | |
| 343 | - | |
| 344 | -end | |
| 345 | - | |
| 346 | -# Set it all up. | |
| 347 | -if Object.const_defined?("ActiveRecord") | |
| 348 | - ActiveRecord::Base.send(:include, Paperclip) | |
| 349 | - File.send(:include, Paperclip::Upfile) | |
| 350 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/attachment.rb
| ... | ... | @@ -1,413 +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/:filename", | |
| 10 | - :path => ":rails_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 | - ensure_required_accessors! | |
| 65 | - | |
| 66 | - if uploaded_file.is_a?(Paperclip::Attachment) | |
| 67 | - uploaded_file = uploaded_file.to_file(:original) | |
| 68 | - close_uploaded_file = uploaded_file.respond_to?(:close) | |
| 69 | - end | |
| 70 | - | |
| 71 | - return nil unless valid_assignment?(uploaded_file) | |
| 72 | - | |
| 73 | - uploaded_file.binmode if uploaded_file.respond_to? :binmode | |
| 74 | - self.clear | |
| 75 | - | |
| 76 | - return nil if uploaded_file.nil? | |
| 77 | - | |
| 78 | - @queued_for_write[:original] = uploaded_file.to_tempfile | |
| 79 | - instance_write(:file_name, uploaded_file.original_filename.strip.gsub(/[^\w\d\.\-]+/, '_')) | |
| 80 | - instance_write(:content_type, uploaded_file.content_type.to_s.strip) | |
| 81 | - instance_write(:file_size, uploaded_file.size.to_i) | |
| 82 | - instance_write(:updated_at, Time.now) | |
| 83 | - | |
| 84 | - @dirty = true | |
| 85 | - | |
| 86 | - post_process if valid? | |
| 87 | - | |
| 88 | - # Reset the file size if the original file was reprocessed. | |
| 89 | - instance_write(:file_size, @queued_for_write[:original].size.to_i) | |
| 90 | - ensure | |
| 91 | - uploaded_file.close if close_uploaded_file | |
| 92 | - validate | |
| 93 | - end | |
| 94 | - | |
| 95 | - # Returns the public URL of the attachment, with a given style. Note that | |
| 96 | - # this does not necessarily need to point to a file that your web server | |
| 97 | - # can access and can point to an action in your app, if you need fine | |
| 98 | - # grained security. This is not recommended if you don't need the | |
| 99 | - # security, however, for performance reasons. set | |
| 100 | - # include_updated_timestamp to false if you want to stop the attachment | |
| 101 | - # update time appended to the url | |
| 102 | - def url style = default_style, include_updated_timestamp = true | |
| 103 | - url = original_filename.nil? ? interpolate(@default_url, style) : interpolate(@url, style) | |
| 104 | - include_updated_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url | |
| 105 | - end | |
| 106 | - | |
| 107 | - # Returns the path of the attachment as defined by the :path option. If the | |
| 108 | - # file is stored in the filesystem the path refers to the path of the file | |
| 109 | - # on disk. If the file is stored in S3, the path is the "key" part of the | |
| 110 | - # URL, and the :bucket option refers to the S3 bucket. | |
| 111 | - def path style = default_style | |
| 112 | - original_filename.nil? ? nil : interpolate(@path, style) | |
| 113 | - end | |
| 114 | - | |
| 115 | - # Alias to +url+ | |
| 116 | - def to_s style = nil | |
| 117 | - url(style) | |
| 118 | - end | |
| 119 | - | |
| 120 | - # Returns true if there are no errors on this attachment. | |
| 121 | - def valid? | |
| 122 | - validate | |
| 123 | - errors.empty? | |
| 124 | - end | |
| 125 | - | |
| 126 | - # Returns an array containing the errors on this attachment. | |
| 127 | - def errors | |
| 128 | - @errors | |
| 129 | - end | |
| 130 | - | |
| 131 | - # Returns true if there are changes that need to be saved. | |
| 132 | - def dirty? | |
| 133 | - @dirty | |
| 134 | - end | |
| 135 | - | |
| 136 | - # Saves the file, if there are no errors. If there are, it flushes them to | |
| 137 | - # the instance's errors and returns false, cancelling the save. | |
| 138 | - def save | |
| 139 | - if valid? | |
| 140 | - flush_deletes | |
| 141 | - flush_writes | |
| 142 | - @dirty = false | |
| 143 | - true | |
| 144 | - else | |
| 145 | - flush_errors | |
| 146 | - false | |
| 147 | - end | |
| 148 | - end | |
| 149 | - | |
| 150 | - # Clears out the attachment. Has the same effect as previously assigning | |
| 151 | - # nil to the attachment. Does NOT save. If you wish to clear AND save, | |
| 152 | - # use #destroy. | |
| 153 | - def clear | |
| 154 | - queue_existing_for_delete | |
| 155 | - @errors = {} | |
| 156 | - @validation_errors = nil | |
| 157 | - end | |
| 158 | - | |
| 159 | - # Destroys the attachment. Has the same effect as previously assigning | |
| 160 | - # nil to the attachment *and saving*. This is permanent. If you wish to | |
| 161 | - # wipe out the existing attachment but not save, use #clear. | |
| 162 | - def destroy | |
| 163 | - clear | |
| 164 | - save | |
| 165 | - end | |
| 166 | - | |
| 167 | - # Returns the name of the file as originally assigned, and lives in the | |
| 168 | - # <attachment>_file_name attribute of the model. | |
| 169 | - def original_filename | |
| 170 | - instance_read(:file_name) | |
| 171 | - end | |
| 172 | - | |
| 173 | - # Returns the size of the file as originally assigned, and lives in the | |
| 174 | - # <attachment>_file_size attribute of the model. | |
| 175 | - def size | |
| 176 | - instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size) | |
| 177 | - end | |
| 178 | - | |
| 179 | - # Returns the content_type of the file as originally assigned, and lives | |
| 180 | - # in the <attachment>_content_type attribute of the model. | |
| 181 | - def content_type | |
| 182 | - instance_read(:content_type) | |
| 183 | - end | |
| 184 | - | |
| 185 | - # Returns the last modified time of the file as originally assigned, and | |
| 186 | - # lives in the <attachment>_updated_at attribute of the model. | |
| 187 | - def updated_at | |
| 188 | - time = instance_read(:updated_at) | |
| 189 | - time && time.to_i | |
| 190 | - end | |
| 191 | - | |
| 192 | - # Paths and URLs can have a number of variables interpolated into them | |
| 193 | - # to vary the storage location based on name, id, style, class, etc. | |
| 194 | - # This method is a deprecated access into supplying and retrieving these | |
| 195 | - # interpolations. Future access should use either Paperclip.interpolates | |
| 196 | - # or extend the Paperclip::Interpolations module directly. | |
| 197 | - def self.interpolations | |
| 198 | - warn('[DEPRECATION] Paperclip::Attachment.interpolations is deprecated ' + | |
| 199 | - 'and will be removed from future versions. ' + | |
| 200 | - 'Use Paperclip.interpolates instead') | |
| 201 | - Paperclip::Interpolations | |
| 202 | - end | |
| 203 | - | |
| 204 | - # This method really shouldn't be called that often. It's expected use is | |
| 205 | - # in the paperclip:refresh rake task and that's it. It will regenerate all | |
| 206 | - # thumbnails forcefully, by reobtaining the original file and going through | |
| 207 | - # the post-process again. | |
| 208 | - def reprocess! | |
| 209 | - new_original = Tempfile.new("paperclip-reprocess") | |
| 210 | - new_original.binmode | |
| 211 | - if old_original = to_file(:original) | |
| 212 | - new_original.write( old_original.read ) | |
| 213 | - new_original.rewind | |
| 214 | - | |
| 215 | - @queued_for_write = { :original => new_original } | |
| 216 | - post_process | |
| 217 | - | |
| 218 | - old_original.close if old_original.respond_to?(:close) | |
| 219 | - | |
| 220 | - save | |
| 221 | - else | |
| 222 | - true | |
| 223 | - end | |
| 224 | - end | |
| 225 | - | |
| 226 | - # Returns true if a file has been assigned. | |
| 227 | - def file? | |
| 228 | - !original_filename.blank? | |
| 229 | - end | |
| 230 | - | |
| 231 | - # Writes the attachment-specific attribute on the instance. For example, | |
| 232 | - # instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's | |
| 233 | - # "avatar_file_name" field (assuming the attachment is called avatar). | |
| 234 | - def instance_write(attr, value) | |
| 235 | - setter = :"#{name}_#{attr}=" | |
| 236 | - responds = instance.respond_to?(setter) | |
| 237 | - self.instance_variable_set("@_#{setter.to_s.chop}", value) | |
| 238 | - instance.send(setter, value) if responds || attr.to_s == "file_name" | |
| 239 | - end | |
| 240 | - | |
| 241 | - # Reads the attachment-specific attribute on the instance. See instance_write | |
| 242 | - # for more details. | |
| 243 | - def instance_read(attr) | |
| 244 | - getter = :"#{name}_#{attr}" | |
| 245 | - responds = instance.respond_to?(getter) | |
| 246 | - cached = self.instance_variable_get("@_#{getter}") | |
| 247 | - return cached if cached | |
| 248 | - instance.send(getter) if responds || attr.to_s == "file_name" | |
| 249 | - end | |
| 250 | - | |
| 251 | - private | |
| 252 | - | |
| 253 | - def ensure_required_accessors! #:nodoc: | |
| 254 | - %w(file_name).each do |field| | |
| 255 | - unless @instance.respond_to?("#{name}_#{field}") && @instance.respond_to?("#{name}_#{field}=") | |
| 256 | - raise PaperclipError.new("#{@instance.class} model missing required attr_accessor for '#{name}_#{field}'") | |
| 257 | - end | |
| 258 | - end | |
| 259 | - end | |
| 260 | - | |
| 261 | - def log message #:nodoc: | |
| 262 | - Paperclip.log(message) | |
| 263 | - end | |
| 264 | - | |
| 265 | - def valid_assignment? file #:nodoc: | |
| 266 | - file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type)) | |
| 267 | - end | |
| 268 | - | |
| 269 | - def validate #:nodoc: | |
| 270 | - unless @validation_errors | |
| 271 | - @validation_errors = @validations.inject({}) do |errors, validation| | |
| 272 | - name, options = validation | |
| 273 | - errors[name] = send(:"validate_#{name}", options) if allow_validation?(options) | |
| 274 | - errors | |
| 275 | - end | |
| 276 | - @validation_errors.reject!{|k,v| v == nil } | |
| 277 | - @errors.merge!(@validation_errors) | |
| 278 | - end | |
| 279 | - @validation_errors | |
| 280 | - end | |
| 281 | - | |
| 282 | - def allow_validation? options #:nodoc: | |
| 283 | - (options[:if].nil? || check_guard(options[:if])) && (options[:unless].nil? || !check_guard(options[:unless])) | |
| 284 | - end | |
| 285 | - | |
| 286 | - def check_guard guard #:nodoc: | |
| 287 | - if guard.respond_to? :call | |
| 288 | - guard.call(instance) | |
| 289 | - elsif ! guard.blank? | |
| 290 | - instance.send(guard.to_s) | |
| 291 | - end | |
| 292 | - end | |
| 293 | - | |
| 294 | - def validate_size options #:nodoc: | |
| 295 | - if file? && !options[:range].include?(size.to_i) | |
| 296 | - options[:message].gsub(/:min/, options[:min].to_s).gsub(/:max/, options[:max].to_s) | |
| 297 | - end | |
| 298 | - end | |
| 299 | - | |
| 300 | - def validate_presence options #:nodoc: | |
| 301 | - options[:message] unless file? | |
| 302 | - end | |
| 303 | - | |
| 304 | - def validate_content_type options #:nodoc: | |
| 305 | - valid_types = [options[:content_type]].flatten | |
| 306 | - unless original_filename.blank? | |
| 307 | - unless valid_types.blank? | |
| 308 | - content_type = instance_read(:content_type) | |
| 309 | - unless valid_types.any?{|t| content_type.nil? || t === content_type } | |
| 310 | - options[:message] || "is not one of the allowed file types." | |
| 311 | - end | |
| 312 | - end | |
| 313 | - end | |
| 314 | - end | |
| 315 | - | |
| 316 | - def normalize_style_definition #:nodoc: | |
| 317 | - @styles.each do |name, args| | |
| 318 | - unless args.is_a? Hash | |
| 319 | - dimensions, format = [args, nil].flatten[0..1] | |
| 320 | - format = nil if format.blank? | |
| 321 | - @styles[name] = { | |
| 322 | - :processors => @processors, | |
| 323 | - :geometry => dimensions, | |
| 324 | - :format => format, | |
| 325 | - :whiny => @whiny, | |
| 326 | - :convert_options => extra_options_for(name) | |
| 327 | - } | |
| 328 | - else | |
| 329 | - @styles[name] = { | |
| 330 | - :processors => @processors, | |
| 331 | - :whiny => @whiny, | |
| 332 | - :convert_options => extra_options_for(name) | |
| 333 | - }.merge(@styles[name]) | |
| 334 | - end | |
| 335 | - end | |
| 336 | - end | |
| 337 | - | |
| 338 | - def solidify_style_definitions #:nodoc: | |
| 339 | - @styles.each do |name, args| | |
| 340 | - @styles[name][:geometry] = @styles[name][:geometry].call(instance) if @styles[name][:geometry].respond_to?(:call) | |
| 341 | - @styles[name][:processors] = @styles[name][:processors].call(instance) if @styles[name][:processors].respond_to?(:call) | |
| 342 | - end | |
| 343 | - end | |
| 344 | - | |
| 345 | - def initialize_storage #:nodoc: | |
| 346 | - @storage_module = Paperclip::Storage.const_get(@storage.to_s.capitalize) | |
| 347 | - self.extend(@storage_module) | |
| 348 | - end | |
| 349 | - | |
| 350 | - def extra_options_for(style) #:nodoc: | |
| 351 | - all_options = convert_options[:all] | |
| 352 | - all_options = all_options.call(instance) if all_options.respond_to?(:call) | |
| 353 | - style_options = convert_options[style] | |
| 354 | - style_options = style_options.call(instance) if style_options.respond_to?(:call) | |
| 355 | - | |
| 356 | - [ style_options, all_options ].compact.join(" ") | |
| 357 | - end | |
| 358 | - | |
| 359 | - def post_process #:nodoc: | |
| 360 | - return if @queued_for_write[:original].nil? | |
| 361 | - solidify_style_definitions | |
| 362 | - return if fire_events(:before) | |
| 363 | - post_process_styles | |
| 364 | - return if fire_events(:after) | |
| 365 | - end | |
| 366 | - | |
| 367 | - def fire_events(which) #:nodoc: | |
| 368 | - return true if callback(:"#{which}_post_process") == false | |
| 369 | - return true if callback(:"#{which}_#{name}_post_process") == false | |
| 370 | - end | |
| 371 | - | |
| 372 | - def callback which #:nodoc: | |
| 373 | - instance.run_callbacks(which, @queued_for_write){|result, obj| result == false } | |
| 374 | - end | |
| 375 | - | |
| 376 | - def post_process_styles #:nodoc: | |
| 377 | - @styles.each do |name, args| | |
| 378 | - begin | |
| 379 | - raise RuntimeError.new("Style #{name} has no processors defined.") if args[:processors].blank? | |
| 380 | - @queued_for_write[name] = args[:processors].inject(@queued_for_write[:original]) do |file, processor| | |
| 381 | - Paperclip.processor(processor).make(file, args, self) | |
| 382 | - end | |
| 383 | - rescue PaperclipError => e | |
| 384 | - log("An error was received while processing: #{e.inspect}") | |
| 385 | - (@errors[:processing] ||= []) << e.message if @whiny | |
| 386 | - end | |
| 387 | - end | |
| 388 | - end | |
| 389 | - | |
| 390 | - def interpolate pattern, style = default_style #:nodoc: | |
| 391 | - Paperclip::Interpolations.interpolate(pattern, self, style) | |
| 392 | - end | |
| 393 | - | |
| 394 | - def queue_existing_for_delete #:nodoc: | |
| 395 | - return unless file? | |
| 396 | - @queued_for_delete += [:original, *@styles.keys].uniq.map do |style| | |
| 397 | - path(style) if exists?(style) | |
| 398 | - end.compact | |
| 399 | - instance_write(:file_name, nil) | |
| 400 | - instance_write(:content_type, nil) | |
| 401 | - instance_write(:file_size, nil) | |
| 402 | - instance_write(:updated_at, nil) | |
| 403 | - end | |
| 404 | - | |
| 405 | - def flush_errors #:nodoc: | |
| 406 | - @errors.each do |error, message| | |
| 407 | - [message].flatten.each {|m| instance.errors.add(name, m) } | |
| 408 | - end | |
| 409 | - end | |
| 410 | - | |
| 411 | - end | |
| 412 | -end | |
| 413 | - |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/callback_compatability.rb
| ... | ... | @@ -1,33 +0,0 @@ |
| 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 |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/geometry.rb
| ... | ... | @@ -1,115 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - | |
| 3 | - # Defines the geometry of an image. | |
| 4 | - class Geometry | |
| 5 | - attr_accessor :height, :width, :modifier | |
| 6 | - | |
| 7 | - # Gives a Geometry representing the given height and width | |
| 8 | - def initialize width = nil, height = nil, modifier = nil | |
| 9 | - @height = height.to_f | |
| 10 | - @width = width.to_f | |
| 11 | - @modifier = modifier | |
| 12 | - end | |
| 13 | - | |
| 14 | - # Uses ImageMagick to determing the dimensions of a file, passed in as either a | |
| 15 | - # File or path. | |
| 16 | - def self.from_file file | |
| 17 | - file = file.path if file.respond_to? "path" | |
| 18 | - geometry = begin | |
| 19 | - Paperclip.run("identify", %Q[-format "%wx%h" "#{file}"[0]]) | |
| 20 | - rescue PaperclipCommandLineError | |
| 21 | - "" | |
| 22 | - end | |
| 23 | - parse(geometry) || | |
| 24 | - raise(NotIdentifiedByImageMagickError.new("#{file} is not recognized by the 'identify' command.")) | |
| 25 | - end | |
| 26 | - | |
| 27 | - # Parses a "WxH" formatted string, where W is the width and H is the height. | |
| 28 | - def self.parse string | |
| 29 | - if match = (string && string.match(/\b(\d*)x?(\d*)\b([\>\<\#\@\%^!])?/i)) | |
| 30 | - Geometry.new(*match[1,3]) | |
| 31 | - end | |
| 32 | - end | |
| 33 | - | |
| 34 | - # True if the dimensions represent a square | |
| 35 | - def square? | |
| 36 | - height == width | |
| 37 | - end | |
| 38 | - | |
| 39 | - # True if the dimensions represent a horizontal rectangle | |
| 40 | - def horizontal? | |
| 41 | - height < width | |
| 42 | - end | |
| 43 | - | |
| 44 | - # True if the dimensions represent a vertical rectangle | |
| 45 | - def vertical? | |
| 46 | - height > width | |
| 47 | - end | |
| 48 | - | |
| 49 | - # The aspect ratio of the dimensions. | |
| 50 | - def aspect | |
| 51 | - width / height | |
| 52 | - end | |
| 53 | - | |
| 54 | - # Returns the larger of the two dimensions | |
| 55 | - def larger | |
| 56 | - [height, width].max | |
| 57 | - end | |
| 58 | - | |
| 59 | - # Returns the smaller of the two dimensions | |
| 60 | - def smaller | |
| 61 | - [height, width].min | |
| 62 | - end | |
| 63 | - | |
| 64 | - # Returns the width and height in a format suitable to be passed to Geometry.parse | |
| 65 | - def to_s | |
| 66 | - s = "" | |
| 67 | - s << width.to_i.to_s if width > 0 | |
| 68 | - s << "x#{height.to_i}" if height > 0 | |
| 69 | - s << modifier.to_s | |
| 70 | - s | |
| 71 | - end | |
| 72 | - | |
| 73 | - # Same as to_s | |
| 74 | - def inspect | |
| 75 | - to_s | |
| 76 | - end | |
| 77 | - | |
| 78 | - # Returns the scaling and cropping geometries (in string-based ImageMagick format) | |
| 79 | - # neccessary to transform this Geometry into the Geometry given. If crop is true, | |
| 80 | - # then it is assumed the destination Geometry will be the exact final resolution. | |
| 81 | - # In this case, the source Geometry is scaled so that an image containing the | |
| 82 | - # destination Geometry would be completely filled by the source image, and any | |
| 83 | - # overhanging image would be cropped. Useful for square thumbnail images. The cropping | |
| 84 | - # is weighted at the center of the Geometry. | |
| 85 | - def transformation_to dst, crop = false | |
| 86 | - if crop | |
| 87 | - ratio = Geometry.new( dst.width / self.width, dst.height / self.height ) | |
| 88 | - scale_geometry, scale = scaling(dst, ratio) | |
| 89 | - crop_geometry = cropping(dst, ratio, scale) | |
| 90 | - else | |
| 91 | - scale_geometry = dst.to_s | |
| 92 | - end | |
| 93 | - | |
| 94 | - [ scale_geometry, crop_geometry ] | |
| 95 | - end | |
| 96 | - | |
| 97 | - private | |
| 98 | - | |
| 99 | - def scaling dst, ratio | |
| 100 | - if ratio.horizontal? || ratio.square? | |
| 101 | - [ "%dx" % dst.width, ratio.width ] | |
| 102 | - else | |
| 103 | - [ "x%d" % dst.height, ratio.height ] | |
| 104 | - end | |
| 105 | - end | |
| 106 | - | |
| 107 | - def cropping dst, ratio, scale | |
| 108 | - if ratio.horizontal? || ratio.square? | |
| 109 | - "%dx%d+%d+%d" % [ dst.width, dst.height, 0, (self.height * scale - dst.height) / 2 ] | |
| 110 | - else | |
| 111 | - "%dx%d+%d+%d" % [ dst.width, dst.height, (self.width * scale - dst.width) / 2, 0 ] | |
| 112 | - end | |
| 113 | - end | |
| 114 | - end | |
| 115 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/interpolations.rb
| ... | ... | @@ -1,105 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - # This module contains all the methods that are available for interpolation | |
| 3 | - # in paths and urls. To add your own (or override an existing one), you | |
| 4 | - # can either open this module and define it, or call the | |
| 5 | - # Paperclip.interpolates method. | |
| 6 | - module Interpolations | |
| 7 | - extend self | |
| 8 | - | |
| 9 | - # Hash assignment of interpolations. Included only for compatability, | |
| 10 | - # and is not intended for normal use. | |
| 11 | - def self.[]= name, block | |
| 12 | - define_method(name, &block) | |
| 13 | - end | |
| 14 | - | |
| 15 | - # Hash access of interpolations. Included only for compatability, | |
| 16 | - # and is not intended for normal use. | |
| 17 | - def self.[] name | |
| 18 | - method(name) | |
| 19 | - end | |
| 20 | - | |
| 21 | - # Returns a sorted list of all interpolations. | |
| 22 | - def self.all | |
| 23 | - self.instance_methods(false).sort | |
| 24 | - end | |
| 25 | - | |
| 26 | - # Perform the actual interpolation. Takes the pattern to interpolate | |
| 27 | - # and the arguments to pass, which are the attachment and style name. | |
| 28 | - def self.interpolate pattern, *args | |
| 29 | - all.reverse.inject( pattern.dup ) do |result, tag| | |
| 30 | - result.gsub(/:#{tag}/) do |match| | |
| 31 | - send( tag, *args ) | |
| 32 | - end | |
| 33 | - end | |
| 34 | - end | |
| 35 | - | |
| 36 | - # Returns the filename, the same way as ":basename.:extension" would. | |
| 37 | - def filename attachment, style | |
| 38 | - "#{basename(attachment, style)}.#{extension(attachment, style)}" | |
| 39 | - end | |
| 40 | - | |
| 41 | - # Returns the interpolated URL. Will raise an error if the url itself | |
| 42 | - # contains ":url" to prevent infinite recursion. This interpolation | |
| 43 | - # is used in the default :path to ease default specifications. | |
| 44 | - def url attachment, style | |
| 45 | - raise InfiniteInterpolationError if attachment.options[:url].include?(":url") | |
| 46 | - attachment.url(style, false) | |
| 47 | - end | |
| 48 | - | |
| 49 | - # Returns the timestamp as defined by the <attachment>_updated_at field | |
| 50 | - def timestamp attachment, style | |
| 51 | - attachment.instance_read(:updated_at).to_s | |
| 52 | - end | |
| 53 | - | |
| 54 | - # Returns the RAILS_ROOT constant. | |
| 55 | - def rails_root attachment, style | |
| 56 | - RAILS_ROOT | |
| 57 | - end | |
| 58 | - | |
| 59 | - # Returns the RAILS_ENV constant. | |
| 60 | - def rails_env attachment, style | |
| 61 | - RAILS_ENV | |
| 62 | - end | |
| 63 | - | |
| 64 | - # Returns the underscored, pluralized version of the class name. | |
| 65 | - # e.g. "users" for the User class. | |
| 66 | - def class attachment, style | |
| 67 | - attachment.instance.class.to_s.underscore.pluralize | |
| 68 | - end | |
| 69 | - | |
| 70 | - # Returns the basename of the file. e.g. "file" for "file.jpg" | |
| 71 | - def basename attachment, style | |
| 72 | - attachment.original_filename.gsub(/#{File.extname(attachment.original_filename)}$/, "") | |
| 73 | - end | |
| 74 | - | |
| 75 | - # Returns the extension of the file. e.g. "jpg" for "file.jpg" | |
| 76 | - # If the style has a format defined, it will return the format instead | |
| 77 | - # of the actual extension. | |
| 78 | - def extension attachment, style | |
| 79 | - ((style = attachment.styles[style]) && style[:format]) || | |
| 80 | - File.extname(attachment.original_filename).gsub(/^\.+/, "") | |
| 81 | - end | |
| 82 | - | |
| 83 | - # Returns the id of the instance. | |
| 84 | - def id attachment, style | |
| 85 | - attachment.instance.id | |
| 86 | - end | |
| 87 | - | |
| 88 | - # Returns the id of the instance in a split path form. e.g. returns | |
| 89 | - # 000/001/234 for an id of 1234. | |
| 90 | - def id_partition attachment, style | |
| 91 | - ("%09d" % attachment.instance.id).scan(/\d{3}/).join("/") | |
| 92 | - end | |
| 93 | - | |
| 94 | - # Returns the pluralized form of the attachment name. e.g. | |
| 95 | - # "avatars" for an attachment of :avatar | |
| 96 | - def attachment attachment, style | |
| 97 | - attachment.name.to_s.downcase.pluralize | |
| 98 | - end | |
| 99 | - | |
| 100 | - # Returns the style, or the default style if nil is supplied. | |
| 101 | - def style attachment, style | |
| 102 | - style || attachment.default_style | |
| 103 | - end | |
| 104 | - end | |
| 105 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/iostream.rb
| ... | ... | @@ -1,58 +0,0 @@ |
| 1 | -# Provides method that can be included on File-type objects (IO, StringIO, Tempfile, etc) to allow stream copying | |
| 2 | -# and Tempfile conversion. | |
| 3 | -module IOStream | |
| 4 | - | |
| 5 | - # Returns a Tempfile containing the contents of the readable object. | |
| 6 | - def to_tempfile | |
| 7 | - tempfile = Tempfile.new("stream") | |
| 8 | - tempfile.binmode | |
| 9 | - self.stream_to(tempfile) | |
| 10 | - end | |
| 11 | - | |
| 12 | - # Copies one read-able object from one place to another in blocks, obviating the need to load | |
| 13 | - # the whole thing into memory. Defaults to 8k blocks. If this module is included in both | |
| 14 | - # StringIO and Tempfile, then either can have its data copied anywhere else without typing | |
| 15 | - # worries or memory overhead worries. Returns a File if a String is passed in as the destination | |
| 16 | - # and returns the IO or Tempfile as passed in if one is sent as the destination. | |
| 17 | - def stream_to path_or_file, in_blocks_of = 8192 | |
| 18 | - dstio = case path_or_file | |
| 19 | - when String then File.new(path_or_file, "wb+") | |
| 20 | - when IO then path_or_file | |
| 21 | - when Tempfile then path_or_file | |
| 22 | - end | |
| 23 | - buffer = "" | |
| 24 | - self.rewind | |
| 25 | - while self.read(in_blocks_of, buffer) do | |
| 26 | - dstio.write(buffer) | |
| 27 | - end | |
| 28 | - dstio.rewind | |
| 29 | - dstio | |
| 30 | - end | |
| 31 | -end | |
| 32 | - | |
| 33 | -class IO #:nodoc: | |
| 34 | - include IOStream | |
| 35 | -end | |
| 36 | - | |
| 37 | -%w( Tempfile StringIO ).each do |klass| | |
| 38 | - if Object.const_defined? klass | |
| 39 | - Object.const_get(klass).class_eval do | |
| 40 | - include IOStream | |
| 41 | - end | |
| 42 | - end | |
| 43 | -end | |
| 44 | - | |
| 45 | -# Corrects a bug in Windows when asking for Tempfile size. | |
| 46 | -if defined? Tempfile | |
| 47 | - class Tempfile | |
| 48 | - def size | |
| 49 | - if @tmpfile | |
| 50 | - @tmpfile.fsync | |
| 51 | - @tmpfile.flush | |
| 52 | - @tmpfile.stat.size | |
| 53 | - else | |
| 54 | - 0 | |
| 55 | - end | |
| 56 | - end | |
| 57 | - end | |
| 58 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/matchers.rb
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/matchers/have_attached_file_matcher.rb
| ... | ... | @@ -1,49 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - module Shoulda | |
| 3 | - module Matchers | |
| 4 | - def have_attached_file name | |
| 5 | - HaveAttachedFileMatcher.new(name) | |
| 6 | - end | |
| 7 | - | |
| 8 | - class HaveAttachedFileMatcher | |
| 9 | - def initialize attachment_name | |
| 10 | - @attachment_name = attachment_name | |
| 11 | - end | |
| 12 | - | |
| 13 | - def matches? subject | |
| 14 | - @subject = subject | |
| 15 | - responds? && has_column? && included? | |
| 16 | - end | |
| 17 | - | |
| 18 | - def failure_message | |
| 19 | - "Should have an attachment named #{@attachment_name}" | |
| 20 | - end | |
| 21 | - | |
| 22 | - def negative_failure_message | |
| 23 | - "Should not have an attachment named #{@attachment_name}" | |
| 24 | - end | |
| 25 | - | |
| 26 | - def description | |
| 27 | - "have an attachment named #{@attachment_name}" | |
| 28 | - end | |
| 29 | - | |
| 30 | - protected | |
| 31 | - | |
| 32 | - def responds? | |
| 33 | - methods = @subject.instance_methods | |
| 34 | - methods.include?("#{@attachment_name}") && | |
| 35 | - methods.include?("#{@attachment_name}=") && | |
| 36 | - methods.include?("#{@attachment_name}?") | |
| 37 | - end | |
| 38 | - | |
| 39 | - def has_column? | |
| 40 | - @subject.column_names.include?("#{@attachment_name}_file_name") | |
| 41 | - end | |
| 42 | - | |
| 43 | - def included? | |
| 44 | - @subject.ancestors.include?(Paperclip::InstanceMethods) | |
| 45 | - end | |
| 46 | - end | |
| 47 | - end | |
| 48 | - end | |
| 49 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb
| ... | ... | @@ -1,66 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - module Shoulda | |
| 3 | - module Matchers | |
| 4 | - def validate_attachment_content_type name | |
| 5 | - ValidateAttachmentContentTypeMatcher.new(name) | |
| 6 | - end | |
| 7 | - | |
| 8 | - class ValidateAttachmentContentTypeMatcher | |
| 9 | - def initialize attachment_name | |
| 10 | - @attachment_name = attachment_name | |
| 11 | - end | |
| 12 | - | |
| 13 | - def allowing *types | |
| 14 | - @allowed_types = types.flatten | |
| 15 | - self | |
| 16 | - end | |
| 17 | - | |
| 18 | - def rejecting *types | |
| 19 | - @rejected_types = types.flatten | |
| 20 | - self | |
| 21 | - end | |
| 22 | - | |
| 23 | - def matches? subject | |
| 24 | - @subject = subject | |
| 25 | - @allowed_types && @rejected_types && | |
| 26 | - allowed_types_allowed? && rejected_types_rejected? | |
| 27 | - end | |
| 28 | - | |
| 29 | - def failure_message | |
| 30 | - "Content types #{@allowed_types.join(", ")} should be accepted" + | |
| 31 | - " and #{@rejected_types.join(", ")} rejected by #{@attachment_name}" | |
| 32 | - end | |
| 33 | - | |
| 34 | - def negative_failure_message | |
| 35 | - "Content types #{@allowed_types.join(", ")} should be rejected" + | |
| 36 | - " and #{@rejected_types.join(", ")} accepted by #{@attachment_name}" | |
| 37 | - end | |
| 38 | - | |
| 39 | - def description | |
| 40 | - "validate the content types allowed on attachment #{@attachment_name}" | |
| 41 | - end | |
| 42 | - | |
| 43 | - protected | |
| 44 | - | |
| 45 | - def allow_types?(types) | |
| 46 | - types.all? do |type| | |
| 47 | - file = StringIO.new(".") | |
| 48 | - file.content_type = type | |
| 49 | - attachment = @subject.new.attachment_for(@attachment_name) | |
| 50 | - attachment.assign(file) | |
| 51 | - attachment.errors[:content_type].nil? | |
| 52 | - end | |
| 53 | - end | |
| 54 | - | |
| 55 | - def allowed_types_allowed? | |
| 56 | - allow_types?(@allowed_types) | |
| 57 | - end | |
| 58 | - | |
| 59 | - def rejected_types_rejected? | |
| 60 | - not allow_types?(@rejected_types) | |
| 61 | - end | |
| 62 | - end | |
| 63 | - end | |
| 64 | - end | |
| 65 | -end | |
| 66 | - |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/matchers/validate_attachment_presence_matcher.rb
| ... | ... | @@ -1,48 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - module Shoulda | |
| 3 | - module Matchers | |
| 4 | - def validate_attachment_presence name | |
| 5 | - ValidateAttachmentPresenceMatcher.new(name) | |
| 6 | - end | |
| 7 | - | |
| 8 | - class ValidateAttachmentPresenceMatcher | |
| 9 | - def initialize attachment_name | |
| 10 | - @attachment_name = attachment_name | |
| 11 | - end | |
| 12 | - | |
| 13 | - def matches? subject | |
| 14 | - @subject = subject | |
| 15 | - error_when_not_valid? && no_error_when_valid? | |
| 16 | - end | |
| 17 | - | |
| 18 | - def failure_message | |
| 19 | - "Attachment #{@attachment_name} should be required" | |
| 20 | - end | |
| 21 | - | |
| 22 | - def negative_failure_message | |
| 23 | - "Attachment #{@attachment_name} should not be required" | |
| 24 | - end | |
| 25 | - | |
| 26 | - def description | |
| 27 | - "require presence of attachment #{@attachment_name}" | |
| 28 | - end | |
| 29 | - | |
| 30 | - protected | |
| 31 | - | |
| 32 | - def error_when_not_valid? | |
| 33 | - @attachment = @subject.new.send(@attachment_name) | |
| 34 | - @attachment.assign(nil) | |
| 35 | - not @attachment.errors[:presence].nil? | |
| 36 | - end | |
| 37 | - | |
| 38 | - def no_error_when_valid? | |
| 39 | - @file = StringIO.new(".") | |
| 40 | - @attachment = @subject.new.send(@attachment_name) | |
| 41 | - @attachment.assign(@file) | |
| 42 | - @attachment.errors[:presence].nil? | |
| 43 | - end | |
| 44 | - end | |
| 45 | - end | |
| 46 | - end | |
| 47 | -end | |
| 48 | - |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/matchers/validate_attachment_size_matcher.rb
| ... | ... | @@ -1,83 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - module Shoulda | |
| 3 | - module Matchers | |
| 4 | - def validate_attachment_size name | |
| 5 | - ValidateAttachmentSizeMatcher.new(name) | |
| 6 | - end | |
| 7 | - | |
| 8 | - class ValidateAttachmentSizeMatcher | |
| 9 | - def initialize attachment_name | |
| 10 | - @attachment_name = attachment_name | |
| 11 | - @low, @high = 0, (1.0/0) | |
| 12 | - end | |
| 13 | - | |
| 14 | - def less_than size | |
| 15 | - @high = size | |
| 16 | - self | |
| 17 | - end | |
| 18 | - | |
| 19 | - def greater_than size | |
| 20 | - @low = size | |
| 21 | - self | |
| 22 | - end | |
| 23 | - | |
| 24 | - def in range | |
| 25 | - @low, @high = range.first, range.last | |
| 26 | - self | |
| 27 | - end | |
| 28 | - | |
| 29 | - def matches? subject | |
| 30 | - @subject = subject | |
| 31 | - lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high? | |
| 32 | - end | |
| 33 | - | |
| 34 | - def failure_message | |
| 35 | - "Attachment #{@attachment_name} must be between #{@low} and #{@high} bytes" | |
| 36 | - end | |
| 37 | - | |
| 38 | - def negative_failure_message | |
| 39 | - "Attachment #{@attachment_name} cannot be between #{@low} and #{@high} bytes" | |
| 40 | - end | |
| 41 | - | |
| 42 | - def description | |
| 43 | - "validate the size of attachment #{@attachment_name}" | |
| 44 | - end | |
| 45 | - | |
| 46 | - protected | |
| 47 | - | |
| 48 | - def override_method object, method, &replacement | |
| 49 | - (class << object; self; end).class_eval do | |
| 50 | - define_method(method, &replacement) | |
| 51 | - end | |
| 52 | - end | |
| 53 | - | |
| 54 | - def passes_validation_with_size(new_size) | |
| 55 | - file = StringIO.new(".") | |
| 56 | - override_method(file, :size){ new_size } | |
| 57 | - attachment = @subject.new.attachment_for(@attachment_name) | |
| 58 | - attachment.assign(file) | |
| 59 | - attachment.errors[:size].nil? | |
| 60 | - end | |
| 61 | - | |
| 62 | - def lower_than_low? | |
| 63 | - not passes_validation_with_size(@low - 1) | |
| 64 | - end | |
| 65 | - | |
| 66 | - def higher_than_low? | |
| 67 | - passes_validation_with_size(@low + 1) | |
| 68 | - end | |
| 69 | - | |
| 70 | - def lower_than_high? | |
| 71 | - return true if @high == (1.0/0) | |
| 72 | - passes_validation_with_size(@high - 1) | |
| 73 | - end | |
| 74 | - | |
| 75 | - def higher_than_high? | |
| 76 | - return true if @high == (1.0/0) | |
| 77 | - not passes_validation_with_size(@high + 1) | |
| 78 | - end | |
| 79 | - end | |
| 80 | - end | |
| 81 | - end | |
| 82 | -end | |
| 83 | - |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/processor.rb
| ... | ... | @@ -1,49 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - # Paperclip processors allow you to modify attached files when they are | |
| 3 | - # attached in any way you are able. Paperclip itself uses command-line | |
| 4 | - # programs for its included Thumbnail processor, but custom processors | |
| 5 | - # are not required to follow suit. | |
| 6 | - # | |
| 7 | - # Processors are required to be defined inside the Paperclip module and | |
| 8 | - # are also required to be a subclass of Paperclip::Processor. There is | |
| 9 | - # only one method you *must* implement to properly be a subclass: | |
| 10 | - # #make, but #initialize may also be of use. Both methods accept 3 | |
| 11 | - # arguments: the file that will be operated on (which is an instance of | |
| 12 | - # File), a hash of options that were defined in has_attached_file's | |
| 13 | - # style hash, and the Paperclip::Attachment itself. | |
| 14 | - # | |
| 15 | - # All #make needs to return is an instance of File (Tempfile is | |
| 16 | - # acceptable) which contains the results of the processing. | |
| 17 | - # | |
| 18 | - # See Paperclip.run for more information about using command-line | |
| 19 | - # utilities from within Processors. | |
| 20 | - class Processor | |
| 21 | - attr_accessor :file, :options, :attachment | |
| 22 | - | |
| 23 | - def initialize file, options = {}, attachment = nil | |
| 24 | - @file = file | |
| 25 | - @options = options | |
| 26 | - @attachment = attachment | |
| 27 | - end | |
| 28 | - | |
| 29 | - def make | |
| 30 | - end | |
| 31 | - | |
| 32 | - def self.make file, options = {}, attachment = nil | |
| 33 | - new(file, options, attachment).make | |
| 34 | - end | |
| 35 | - end | |
| 36 | - | |
| 37 | - # Due to how ImageMagick handles its image format conversion and how Tempfile | |
| 38 | - # handles its naming scheme, it is necessary to override how Tempfile makes | |
| 39 | - # its names so as to allow for file extensions. Idea taken from the comments | |
| 40 | - # on this blog post: | |
| 41 | - # http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions | |
| 42 | - class Tempfile < ::Tempfile | |
| 43 | - # Replaces Tempfile's +make_tmpname+ with one that honors file extensions. | |
| 44 | - def make_tmpname(basename, n) | |
| 45 | - extension = File.extname(basename) | |
| 46 | - sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension) | |
| 47 | - end | |
| 48 | - end | |
| 49 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/storage.rb
| ... | ... | @@ -1,236 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - module Storage | |
| 3 | - | |
| 4 | - # The default place to store attachments is in the filesystem. Files on the local | |
| 5 | - # filesystem can be very easily served by Apache without requiring a hit to your app. | |
| 6 | - # They also can be processed more easily after they've been saved, as they're just | |
| 7 | - # normal files. There is one Filesystem-specific option for has_attached_file. | |
| 8 | - # * +path+: The location of the repository of attachments on disk. This can (and, in | |
| 9 | - # almost all cases, should) be coordinated with the value of the +url+ option to | |
| 10 | - # allow files to be saved into a place where Apache can serve them without | |
| 11 | - # hitting your app. Defaults to | |
| 12 | - # ":rails_root/public/:attachment/:id/:style/:basename.:extension" | |
| 13 | - # By default this places the files in the app's public directory which can be served | |
| 14 | - # directly. If you are using capistrano for deployment, a good idea would be to | |
| 15 | - # make a symlink to the capistrano-created system directory from inside your app's | |
| 16 | - # public directory. | |
| 17 | - # See Paperclip::Attachment#interpolate for more information on variable interpolaton. | |
| 18 | - # :path => "/var/app/attachments/:class/:id/:style/:basename.:extension" | |
| 19 | - module Filesystem | |
| 20 | - def self.extended base | |
| 21 | - end | |
| 22 | - | |
| 23 | - def exists?(style = default_style) | |
| 24 | - if original_filename | |
| 25 | - File.exist?(path(style)) | |
| 26 | - else | |
| 27 | - false | |
| 28 | - end | |
| 29 | - end | |
| 30 | - | |
| 31 | - # Returns representation of the data of the file assigned to the given | |
| 32 | - # style, in the format most representative of the current storage. | |
| 33 | - def to_file style = default_style | |
| 34 | - @queued_for_write[style] || (File.new(path(style), 'rb') if exists?(style)) | |
| 35 | - end | |
| 36 | - alias_method :to_io, :to_file | |
| 37 | - | |
| 38 | - def flush_writes #:nodoc: | |
| 39 | - @queued_for_write.each do |style, file| | |
| 40 | - file.close | |
| 41 | - FileUtils.mkdir_p(File.dirname(path(style))) | |
| 42 | - log("saving #{path(style)}") | |
| 43 | - FileUtils.mv(file.path, path(style)) | |
| 44 | - FileUtils.chmod(0644, path(style)) | |
| 45 | - end | |
| 46 | - @queued_for_write = {} | |
| 47 | - end | |
| 48 | - | |
| 49 | - def flush_deletes #:nodoc: | |
| 50 | - @queued_for_delete.each do |path| | |
| 51 | - begin | |
| 52 | - log("deleting #{path}") | |
| 53 | - FileUtils.rm(path) if File.exist?(path) | |
| 54 | - rescue Errno::ENOENT => e | |
| 55 | - # ignore file-not-found, let everything else pass | |
| 56 | - end | |
| 57 | - begin | |
| 58 | - while(true) | |
| 59 | - path = File.dirname(path) | |
| 60 | - FileUtils.rmdir(path) | |
| 61 | - end | |
| 62 | - rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR | |
| 63 | - # Stop trying to remove parent directories | |
| 64 | - rescue SystemCallError => e | |
| 65 | - log("There was an unexpected error while deleting directories: #{e.class}") | |
| 66 | - # Ignore it | |
| 67 | - end | |
| 68 | - end | |
| 69 | - @queued_for_delete = [] | |
| 70 | - end | |
| 71 | - end | |
| 72 | - | |
| 73 | - # Amazon's S3 file hosting service is a scalable, easy place to store files for | |
| 74 | - # distribution. You can find out more about it at http://aws.amazon.com/s3 | |
| 75 | - # There are a few S3-specific options for has_attached_file: | |
| 76 | - # * +s3_credentials+: Takes a path, a File, or a Hash. The path (or File) must point | |
| 77 | - # to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon | |
| 78 | - # gives you. You can 'environment-space' this just like you do to your | |
| 79 | - # database.yml file, so different environments can use different accounts: | |
| 80 | - # development: | |
| 81 | - # access_key_id: 123... | |
| 82 | - # secret_access_key: 123... | |
| 83 | - # test: | |
| 84 | - # access_key_id: abc... | |
| 85 | - # secret_access_key: abc... | |
| 86 | - # production: | |
| 87 | - # access_key_id: 456... | |
| 88 | - # secret_access_key: 456... | |
| 89 | - # This is not required, however, and the file may simply look like this: | |
| 90 | - # access_key_id: 456... | |
| 91 | - # secret_access_key: 456... | |
| 92 | - # In which case, those access keys will be used in all environments. You can also | |
| 93 | - # put your bucket name in this file, instead of adding it to the code directly. | |
| 94 | - # This is useful when you want the same account but a different bucket for | |
| 95 | - # development versus production. | |
| 96 | - # * +s3_permissions+: This is a String that should be one of the "canned" access | |
| 97 | - # policies that S3 provides (more information can be found here: | |
| 98 | - # http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html#RESTCannedAccessPolicies) | |
| 99 | - # The default for Paperclip is "public-read". | |
| 100 | - # * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either | |
| 101 | - # 'http' or 'https'. Defaults to 'http' when your :s3_permissions are 'public-read' (the | |
| 102 | - # default), and 'https' when your :s3_permissions are anything else. | |
| 103 | - # * +s3_headers+: A hash of headers such as {'Expires' => 1.year.from_now.httpdate} | |
| 104 | - # * +bucket+: This is the name of the S3 bucket that will store your files. Remember | |
| 105 | - # that the bucket must be unique across all of Amazon S3. If the bucket does not exist | |
| 106 | - # Paperclip will attempt to create it. The bucket name will not be interpolated. | |
| 107 | - # You can define the bucket as a Proc if you want to determine it's name at runtime. | |
| 108 | - # Paperclip will call that Proc with attachment as the only argument. | |
| 109 | - # * +s3_host_alias+: The fully-qualified domain name (FQDN) that is the alias to the | |
| 110 | - # S3 domain of your bucket. Used with the :s3_alias_url url interpolation. See the | |
| 111 | - # link in the +url+ entry for more information about S3 domains and buckets. | |
| 112 | - # * +url+: There are three options for the S3 url. You can choose to have the bucket's name | |
| 113 | - # placed domain-style (bucket.s3.amazonaws.com) or path-style (s3.amazonaws.com/bucket). | |
| 114 | - # Lastly, you can specify a CNAME (which requires the CNAME to be specified as | |
| 115 | - # :s3_alias_url. You can read more about CNAMEs and S3 at | |
| 116 | - # http://docs.amazonwebservices.com/AmazonS3/latest/index.html?VirtualHosting.html | |
| 117 | - # Normally, this won't matter in the slightest and you can leave the default (which is | |
| 118 | - # path-style, or :s3_path_url). But in some cases paths don't work and you need to use | |
| 119 | - # the domain-style (:s3_domain_url). Anything else here will be treated like path-style. | |
| 120 | - # NOTE: If you use a CNAME for use with CloudFront, you can NOT specify https as your | |
| 121 | - # :s3_protocol; This is *not supported* by S3/CloudFront. Finally, when using the host | |
| 122 | - # alias, the :bucket parameter is ignored, as the hostname is used as the bucket name | |
| 123 | - # by S3. | |
| 124 | - # * +path+: This is the key under the bucket in which the file will be stored. The | |
| 125 | - # URL will be constructed from the bucket and the path. This is what you will want | |
| 126 | - # to interpolate. Keys should be unique, like filenames, and despite the fact that | |
| 127 | - # S3 (strictly speaking) does not support directories, you can still use a / to | |
| 128 | - # separate parts of your file name. | |
| 129 | - module S3 | |
| 130 | - def self.extended base | |
| 131 | - require 'right_aws' | |
| 132 | - base.instance_eval do | |
| 133 | - @s3_credentials = parse_credentials(@options[:s3_credentials]) | |
| 134 | - @bucket = @options[:bucket] || @s3_credentials[:bucket] | |
| 135 | - @bucket = @bucket.call(self) if @bucket.is_a?(Proc) | |
| 136 | - @s3_options = @options[:s3_options] || {} | |
| 137 | - @s3_permissions = @options[:s3_permissions] || 'public-read' | |
| 138 | - @s3_protocol = @options[:s3_protocol] || (@s3_permissions == 'public-read' ? 'http' : 'https') | |
| 139 | - @s3_headers = @options[:s3_headers] || {} | |
| 140 | - @s3_host_alias = @options[:s3_host_alias] | |
| 141 | - @url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/) | |
| 142 | - end | |
| 143 | - Paperclip.interpolates(:s3_alias_url) do |attachment, style| | |
| 144 | - "#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}" | |
| 145 | - end | |
| 146 | - Paperclip.interpolates(:s3_path_url) do |attachment, style| | |
| 147 | - "#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}" | |
| 148 | - end | |
| 149 | - Paperclip.interpolates(:s3_domain_url) do |attachment, style| | |
| 150 | - "#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}" | |
| 151 | - end | |
| 152 | - end | |
| 153 | - | |
| 154 | - def s3 | |
| 155 | - @s3 ||= RightAws::S3.new(@s3_credentials[:access_key_id], | |
| 156 | - @s3_credentials[:secret_access_key], | |
| 157 | - @s3_options) | |
| 158 | - end | |
| 159 | - | |
| 160 | - def s3_bucket | |
| 161 | - @s3_bucket ||= s3.bucket(@bucket, true, @s3_permissions) | |
| 162 | - end | |
| 163 | - | |
| 164 | - def bucket_name | |
| 165 | - @bucket | |
| 166 | - end | |
| 167 | - | |
| 168 | - def s3_host_alias | |
| 169 | - @s3_host_alias | |
| 170 | - end | |
| 171 | - | |
| 172 | - def parse_credentials creds | |
| 173 | - creds = find_credentials(creds).stringify_keys | |
| 174 | - (creds[RAILS_ENV] || creds).symbolize_keys | |
| 175 | - end | |
| 176 | - | |
| 177 | - def exists?(style = default_style) | |
| 178 | - s3_bucket.key(path(style)) ? true : false | |
| 179 | - end | |
| 180 | - | |
| 181 | - def s3_protocol | |
| 182 | - @s3_protocol | |
| 183 | - end | |
| 184 | - | |
| 185 | - # Returns representation of the data of the file assigned to the given | |
| 186 | - # style, in the format most representative of the current storage. | |
| 187 | - def to_file style = default_style | |
| 188 | - @queued_for_write[style] || s3_bucket.key(path(style)) | |
| 189 | - end | |
| 190 | - alias_method :to_io, :to_file | |
| 191 | - | |
| 192 | - def flush_writes #:nodoc: | |
| 193 | - @queued_for_write.each do |style, file| | |
| 194 | - begin | |
| 195 | - log("saving #{path(style)}") | |
| 196 | - key = s3_bucket.key(path(style)) | |
| 197 | - key.data = file | |
| 198 | - key.put(nil, @s3_permissions, {'Content-type' => instance_read(:content_type)}.merge(@s3_headers)) | |
| 199 | - rescue RightAws::AwsError => e | |
| 200 | - raise | |
| 201 | - end | |
| 202 | - end | |
| 203 | - @queued_for_write = {} | |
| 204 | - end | |
| 205 | - | |
| 206 | - def flush_deletes #:nodoc: | |
| 207 | - @queued_for_delete.each do |path| | |
| 208 | - begin | |
| 209 | - log("deleting #{path}") | |
| 210 | - if file = s3_bucket.key(path) | |
| 211 | - file.delete | |
| 212 | - end | |
| 213 | - rescue RightAws::AwsError | |
| 214 | - # Ignore this. | |
| 215 | - end | |
| 216 | - end | |
| 217 | - @queued_for_delete = [] | |
| 218 | - end | |
| 219 | - | |
| 220 | - def find_credentials creds | |
| 221 | - case creds | |
| 222 | - when File | |
| 223 | - YAML.load_file(creds.path) | |
| 224 | - when String | |
| 225 | - YAML.load_file(creds) | |
| 226 | - when Hash | |
| 227 | - creds | |
| 228 | - else | |
| 229 | - raise ArgumentError, "Credentials are not a path, file, or hash." | |
| 230 | - end | |
| 231 | - end | |
| 232 | - private :find_credentials | |
| 233 | - | |
| 234 | - end | |
| 235 | - end | |
| 236 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/thumbnail.rb
| ... | ... | @@ -1,70 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - # Handles thumbnailing images that are uploaded. | |
| 3 | - class Thumbnail < Processor | |
| 4 | - | |
| 5 | - attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options | |
| 6 | - | |
| 7 | - # Creates a Thumbnail object set to work on the +file+ given. It | |
| 8 | - # will attempt to transform the image into one defined by +target_geometry+ | |
| 9 | - # which is a "WxH"-style string. +format+ will be inferred from the +file+ | |
| 10 | - # unless specified. Thumbnail creation will raise no errors unless | |
| 11 | - # +whiny+ is true (which it is, by default. If +convert_options+ is | |
| 12 | - # set, the options will be appended to the convert command upon image conversion | |
| 13 | - def initialize file, options = {}, attachment = nil | |
| 14 | - super | |
| 15 | - geometry = options[:geometry] | |
| 16 | - @file = file | |
| 17 | - @crop = geometry[-1,1] == '#' | |
| 18 | - @target_geometry = Geometry.parse geometry | |
| 19 | - @current_geometry = Geometry.from_file @file | |
| 20 | - @convert_options = options[:convert_options] | |
| 21 | - @whiny = options[:whiny].nil? ? true : options[:whiny] | |
| 22 | - @format = options[:format] | |
| 23 | - | |
| 24 | - @current_format = File.extname(@file.path) | |
| 25 | - @basename = File.basename(@file.path, @current_format) | |
| 26 | - end | |
| 27 | - | |
| 28 | - # Returns true if the +target_geometry+ is meant to crop. | |
| 29 | - def crop? | |
| 30 | - @crop | |
| 31 | - end | |
| 32 | - | |
| 33 | - # Returns true if the image is meant to make use of additional convert options. | |
| 34 | - def convert_options? | |
| 35 | - not @convert_options.blank? | |
| 36 | - end | |
| 37 | - | |
| 38 | - # Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile | |
| 39 | - # that contains the new image. | |
| 40 | - def make | |
| 41 | - src = @file | |
| 42 | - dst = Tempfile.new([@basename, @format].compact.join(".")) | |
| 43 | - dst.binmode | |
| 44 | - | |
| 45 | - command = <<-end_command | |
| 46 | - "#{ File.expand_path(src.path) }[0]" | |
| 47 | - #{ transformation_command } | |
| 48 | - "#{ File.expand_path(dst.path) }" | |
| 49 | - end_command | |
| 50 | - | |
| 51 | - begin | |
| 52 | - success = Paperclip.run("convert", command.gsub(/\s+/, " ")) | |
| 53 | - rescue PaperclipCommandLineError | |
| 54 | - raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny | |
| 55 | - end | |
| 56 | - | |
| 57 | - dst | |
| 58 | - end | |
| 59 | - | |
| 60 | - # Returns the command ImageMagick's +convert+ needs to transform the image | |
| 61 | - # into the thumbnail. | |
| 62 | - def transformation_command | |
| 63 | - scale, crop = @current_geometry.transformation_to(@target_geometry, crop?) | |
| 64 | - trans = "-resize \"#{scale}\"" | |
| 65 | - trans << " -crop \"#{crop}\" +repage" if crop | |
| 66 | - trans << " #{convert_options}" if convert_options? | |
| 67 | - trans | |
| 68 | - end | |
| 69 | - end | |
| 70 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/lib/paperclip/upfile.rb
| ... | ... | @@ -1,48 +0,0 @@ |
| 1 | -module Paperclip | |
| 2 | - # The Upfile module is a convenience module for adding uploaded-file-type methods | |
| 3 | - # to the +File+ class. Useful for testing. | |
| 4 | - # user.avatar = File.new("test/test_avatar.jpg") | |
| 5 | - module Upfile | |
| 6 | - | |
| 7 | - # Infer the MIME-type of the file from the extension. | |
| 8 | - def content_type | |
| 9 | - type = (self.path.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase | |
| 10 | - case type | |
| 11 | - when %r"jpe?g" then "image/jpeg" | |
| 12 | - when %r"tiff?" then "image/tiff" | |
| 13 | - when %r"png", "gif", "bmp" then "image/#{type}" | |
| 14 | - when "txt" then "text/plain" | |
| 15 | - when %r"html?" then "text/html" | |
| 16 | - when "csv", "xml", "css", "js" then "text/#{type}" | |
| 17 | - else "application/x-#{type}" | |
| 18 | - end | |
| 19 | - end | |
| 20 | - | |
| 21 | - # Returns the file's normal name. | |
| 22 | - def original_filename | |
| 23 | - File.basename(self.path) | |
| 24 | - end | |
| 25 | - | |
| 26 | - # Returns the size of the file. | |
| 27 | - def size | |
| 28 | - File.size(self) | |
| 29 | - end | |
| 30 | - end | |
| 31 | -end | |
| 32 | - | |
| 33 | -if defined? StringIO | |
| 34 | - class StringIO | |
| 35 | - attr_accessor :original_filename, :content_type | |
| 36 | - def original_filename | |
| 37 | - @original_filename ||= "stringio.txt" | |
| 38 | - end | |
| 39 | - def content_type | |
| 40 | - @content_type ||= "text/plain" | |
| 41 | - end | |
| 42 | - end | |
| 43 | -end | |
| 44 | - | |
| 45 | -class File #:nodoc: | |
| 46 | - include Paperclip::Upfile | |
| 47 | -end | |
| 48 | - |
vendor/gems/thoughtbot-paperclip-2.2.9.2/shoulda_macros/paperclip.rb
| ... | ... | @@ -1,68 +0,0 @@ |
| 1 | -require 'paperclip/matchers' | |
| 2 | - | |
| 3 | -module Paperclip | |
| 4 | - # =Paperclip Shoulda Macros | |
| 5 | - # | |
| 6 | - # These macros are intended for use with shoulda, and will be included into | |
| 7 | - # your tests automatically. All of the macros use the standard shoulda | |
| 8 | - # assumption that the name of the test is based on the name of the model | |
| 9 | - # you're testing (that is, UserTest is the test for the User model), and | |
| 10 | - # will load that class for testing purposes. | |
| 11 | - module Shoulda | |
| 12 | - include Matchers | |
| 13 | - # This will test whether you have defined your attachment correctly by | |
| 14 | - # checking for all the required fields exist after the definition of the | |
| 15 | - # attachment. | |
| 16 | - def should_have_attached_file name | |
| 17 | - klass = self.name.gsub(/Test$/, '').constantize | |
| 18 | - matcher = have_attached_file name | |
| 19 | - should matcher.description do | |
| 20 | - assert_accepts(matcher, klass) | |
| 21 | - end | |
| 22 | - end | |
| 23 | - | |
| 24 | - # Tests for validations on the presence of the attachment. | |
| 25 | - def should_validate_attachment_presence name | |
| 26 | - klass = self.name.gsub(/Test$/, '').constantize | |
| 27 | - matcher = validate_attachment_presence name | |
| 28 | - should matcher.description do | |
| 29 | - assert_accepts(matcher, klass) | |
| 30 | - end | |
| 31 | - end | |
| 32 | - | |
| 33 | - # Tests that you have content_type validations specified. There are two | |
| 34 | - # options, :valid and :invalid. Both accept an array of strings. The | |
| 35 | - # strings should be a list of content types which will pass and fail | |
| 36 | - # validation, respectively. | |
| 37 | - def should_validate_attachment_content_type name, options = {} | |
| 38 | - klass = self.name.gsub(/Test$/, '').constantize | |
| 39 | - valid = [options[:valid]].flatten | |
| 40 | - invalid = [options[:invalid]].flatten | |
| 41 | - matcher = validate_attachment_content_type(name).allowing(valid).rejecting(invalid) | |
| 42 | - should matcher.description do | |
| 43 | - assert_accepts(matcher, klass) | |
| 44 | - end | |
| 45 | - end | |
| 46 | - | |
| 47 | - # Tests to ensure that you have file size validations turned on. You | |
| 48 | - # can pass the same options to this that you can to | |
| 49 | - # validate_attachment_file_size - :less_than, :greater_than, and :in. | |
| 50 | - # :less_than checks that a file is less than a certain size, :greater_than | |
| 51 | - # checks that a file is more than a certain size, and :in takes a Range or | |
| 52 | - # Array which specifies the lower and upper limits of the file size. | |
| 53 | - def should_validate_attachment_size name, options = {} | |
| 54 | - klass = self.name.gsub(/Test$/, '').constantize | |
| 55 | - min = options[:greater_than] || (options[:in] && options[:in].first) || 0 | |
| 56 | - max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0) | |
| 57 | - range = (min..max) | |
| 58 | - matcher = validate_attachment_size(name).in(range) | |
| 59 | - should matcher.description do | |
| 60 | - assert_accepts(matcher, klass) | |
| 61 | - end | |
| 62 | - end | |
| 63 | - end | |
| 64 | -end | |
| 65 | - | |
| 66 | -class Test::Unit::TestCase #:nodoc: | |
| 67 | - extend Paperclip::Shoulda | |
| 68 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/tasks/paperclip_tasks.rake
| ... | ... | @@ -1,79 +0,0 @@ |
| 1 | -def obtain_class | |
| 2 | - class_name = ENV['CLASS'] || ENV['class'] | |
| 3 | - raise "Must specify CLASS" unless class_name | |
| 4 | - @klass = Object.const_get(class_name) | |
| 5 | -end | |
| 6 | - | |
| 7 | -def obtain_attachments | |
| 8 | - name = ENV['ATTACHMENT'] || ENV['attachment'] | |
| 9 | - raise "Class #{@klass.name} has no attachments specified" unless @klass.respond_to?(:attachment_definitions) | |
| 10 | - if !name.blank? && @klass.attachment_definitions.keys.include?(name) | |
| 11 | - [ name ] | |
| 12 | - else | |
| 13 | - @klass.attachment_definitions.keys | |
| 14 | - end | |
| 15 | -end | |
| 16 | - | |
| 17 | -def for_all_attachments | |
| 18 | - klass = obtain_class | |
| 19 | - names = obtain_attachments | |
| 20 | - ids = klass.connection.select_values(klass.send(:construct_finder_sql, :select => 'id')) | |
| 21 | - | |
| 22 | - ids.each do |id| | |
| 23 | - instance = klass.find(id) | |
| 24 | - names.each do |name| | |
| 25 | - result = if instance.send("#{ name }?") | |
| 26 | - yield(instance, name) | |
| 27 | - else | |
| 28 | - true | |
| 29 | - end | |
| 30 | - print result ? "." : "x"; $stdout.flush | |
| 31 | - end | |
| 32 | - end | |
| 33 | - puts " Done." | |
| 34 | -end | |
| 35 | - | |
| 36 | -namespace :paperclip do | |
| 37 | - desc "Refreshes both metadata and thumbnails." | |
| 38 | - task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"] | |
| 39 | - | |
| 40 | - namespace :refresh do | |
| 41 | - desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)." | |
| 42 | - task :thumbnails => :environment do | |
| 43 | - errors = [] | |
| 44 | - for_all_attachments do |instance, name| | |
| 45 | - result = instance.send(name).reprocess! | |
| 46 | - errors << [instance.id, instance.errors] unless instance.errors.blank? | |
| 47 | - result | |
| 48 | - end | |
| 49 | - errors.each{|e| puts "#{e.first}: #{e.last.full_messages.inspect}" } | |
| 50 | - end | |
| 51 | - | |
| 52 | - desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)." | |
| 53 | - task :metadata => :environment do | |
| 54 | - for_all_attachments do |instance, name| | |
| 55 | - if file = instance.send(name).to_file | |
| 56 | - instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip) | |
| 57 | - instance.send("#{name}_content_type=", file.content_type.strip) | |
| 58 | - instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size") | |
| 59 | - instance.save(false) | |
| 60 | - else | |
| 61 | - true | |
| 62 | - end | |
| 63 | - end | |
| 64 | - end | |
| 65 | - end | |
| 66 | - | |
| 67 | - desc "Cleans out invalid attachments. Useful after you've added new validations." | |
| 68 | - task :clean => :environment do | |
| 69 | - for_all_attachments do |instance, name| | |
| 70 | - instance.send(name).send(:validate) | |
| 71 | - if instance.send(name).valid? | |
| 72 | - true | |
| 73 | - else | |
| 74 | - instance.send("#{name}=", nil) | |
| 75 | - instance.save | |
| 76 | - end | |
| 77 | - end | |
| 78 | - end | |
| 79 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/attachment_test.rb
| ... | ... | @@ -1,768 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class Dummy | |
| 4 | - # This is a dummy class | |
| 5 | -end | |
| 6 | - | |
| 7 | -class AttachmentTest < Test::Unit::TestCase | |
| 8 | - should "return the path based on the url by default" do | |
| 9 | - @attachment = attachment :url => "/:class/:id/:basename" | |
| 10 | - @model = @attachment.instance | |
| 11 | - @model.id = 1234 | |
| 12 | - @model.avatar_file_name = "fake.jpg" | |
| 13 | - assert_equal "#{RAILS_ROOT}/public/fake_models/1234/fake", @attachment.path | |
| 14 | - end | |
| 15 | - | |
| 16 | - context "Attachment default_options" do | |
| 17 | - setup do | |
| 18 | - rebuild_model | |
| 19 | - @old_default_options = Paperclip::Attachment.default_options.dup | |
| 20 | - @new_default_options = @old_default_options.merge({ | |
| 21 | - :path => "argle/bargle", | |
| 22 | - :url => "fooferon", | |
| 23 | - :default_url => "not here.png" | |
| 24 | - }) | |
| 25 | - end | |
| 26 | - | |
| 27 | - teardown do | |
| 28 | - Paperclip::Attachment.default_options.merge! @old_default_options | |
| 29 | - end | |
| 30 | - | |
| 31 | - should "be overrideable" do | |
| 32 | - Paperclip::Attachment.default_options.merge!(@new_default_options) | |
| 33 | - @new_default_options.keys.each do |key| | |
| 34 | - assert_equal @new_default_options[key], | |
| 35 | - Paperclip::Attachment.default_options[key] | |
| 36 | - end | |
| 37 | - end | |
| 38 | - | |
| 39 | - context "without an Attachment" do | |
| 40 | - setup do | |
| 41 | - @dummy = Dummy.new | |
| 42 | - end | |
| 43 | - | |
| 44 | - should "return false when asked exists?" do | |
| 45 | - assert !@dummy.avatar.exists? | |
| 46 | - end | |
| 47 | - end | |
| 48 | - | |
| 49 | - context "on an Attachment" do | |
| 50 | - setup do | |
| 51 | - @dummy = Dummy.new | |
| 52 | - @attachment = @dummy.avatar | |
| 53 | - end | |
| 54 | - | |
| 55 | - Paperclip::Attachment.default_options.keys.each do |key| | |
| 56 | - should "be the default_options for #{key}" do | |
| 57 | - assert_equal @old_default_options[key], | |
| 58 | - @attachment.instance_variable_get("@#{key}"), | |
| 59 | - key | |
| 60 | - end | |
| 61 | - end | |
| 62 | - | |
| 63 | - context "when redefined" do | |
| 64 | - setup do | |
| 65 | - Paperclip::Attachment.default_options.merge!(@new_default_options) | |
| 66 | - @dummy = Dummy.new | |
| 67 | - @attachment = @dummy.avatar | |
| 68 | - end | |
| 69 | - | |
| 70 | - Paperclip::Attachment.default_options.keys.each do |key| | |
| 71 | - should "be the new default_options for #{key}" do | |
| 72 | - assert_equal @new_default_options[key], | |
| 73 | - @attachment.instance_variable_get("@#{key}"), | |
| 74 | - key | |
| 75 | - end | |
| 76 | - end | |
| 77 | - end | |
| 78 | - end | |
| 79 | - end | |
| 80 | - | |
| 81 | - context "An attachment with similarly named interpolations" do | |
| 82 | - setup do | |
| 83 | - rebuild_model :path => ":id.omg/:id-bbq/:idwhat/:id_partition.wtf" | |
| 84 | - @dummy = Dummy.new | |
| 85 | - @dummy.stubs(:id).returns(1024) | |
| 86 | - @file = File.new(File.join(File.dirname(__FILE__), | |
| 87 | - "fixtures", | |
| 88 | - "5k.png"), 'rb') | |
| 89 | - @dummy.avatar = @file | |
| 90 | - end | |
| 91 | - | |
| 92 | - teardown { @file.close } | |
| 93 | - | |
| 94 | - should "make sure that they are interpolated correctly" do | |
| 95 | - assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path | |
| 96 | - end | |
| 97 | - end | |
| 98 | - | |
| 99 | - context "An attachment with a :rails_env interpolation" do | |
| 100 | - setup do | |
| 101 | - @rails_env = "blah" | |
| 102 | - @id = 1024 | |
| 103 | - rebuild_model :path => ":rails_env/:id.png" | |
| 104 | - @dummy = Dummy.new | |
| 105 | - @dummy.stubs(:id).returns(@id) | |
| 106 | - @file = StringIO.new(".") | |
| 107 | - @dummy.avatar = @file | |
| 108 | - end | |
| 109 | - | |
| 110 | - should "return the proper path" do | |
| 111 | - temporary_rails_env(@rails_env) { | |
| 112 | - assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path | |
| 113 | - } | |
| 114 | - end | |
| 115 | - end | |
| 116 | - | |
| 117 | - context "An attachment with a default style and an extension interpolation" do | |
| 118 | - setup do | |
| 119 | - @attachment = attachment :path => ":basename.:extension", | |
| 120 | - :styles => { :default => ["100x100", :png] }, | |
| 121 | - :default_style => :default | |
| 122 | - @file = StringIO.new("...") | |
| 123 | - @file.expects(:original_filename).returns("file.jpg") | |
| 124 | - end | |
| 125 | - should "return the right extension for the path" do | |
| 126 | - @attachment.assign(@file) | |
| 127 | - assert_equal "file.png", @attachment.path | |
| 128 | - end | |
| 129 | - end | |
| 130 | - | |
| 131 | - context "An attachment with :convert_options" do | |
| 132 | - setup do | |
| 133 | - rebuild_model :styles => { | |
| 134 | - :thumb => "100x100", | |
| 135 | - :large => "400x400" | |
| 136 | - }, | |
| 137 | - :convert_options => { | |
| 138 | - :all => "-do_stuff", | |
| 139 | - :thumb => "-thumbnailize" | |
| 140 | - } | |
| 141 | - @dummy = Dummy.new | |
| 142 | - @dummy.avatar | |
| 143 | - end | |
| 144 | - | |
| 145 | - should "report the correct options when sent #extra_options_for(:thumb)" do | |
| 146 | - assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect | |
| 147 | - end | |
| 148 | - | |
| 149 | - should "report the correct options when sent #extra_options_for(:large)" do | |
| 150 | - assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large) | |
| 151 | - end | |
| 152 | - | |
| 153 | - before_should "call extra_options_for(:thumb/:large)" do | |
| 154 | - Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb) | |
| 155 | - Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large) | |
| 156 | - end | |
| 157 | - end | |
| 158 | - | |
| 159 | - context "An attachment with :convert_options that is a proc" do | |
| 160 | - setup do | |
| 161 | - rebuild_model :styles => { | |
| 162 | - :thumb => "100x100", | |
| 163 | - :large => "400x400" | |
| 164 | - }, | |
| 165 | - :convert_options => { | |
| 166 | - :all => lambda{|i| i.all }, | |
| 167 | - :thumb => lambda{|i| i.thumb } | |
| 168 | - } | |
| 169 | - Dummy.class_eval do | |
| 170 | - def all; "-all"; end | |
| 171 | - def thumb; "-thumb"; end | |
| 172 | - end | |
| 173 | - @dummy = Dummy.new | |
| 174 | - @dummy.avatar | |
| 175 | - end | |
| 176 | - | |
| 177 | - should "report the correct options when sent #extra_options_for(:thumb)" do | |
| 178 | - assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect | |
| 179 | - end | |
| 180 | - | |
| 181 | - should "report the correct options when sent #extra_options_for(:large)" do | |
| 182 | - assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large) | |
| 183 | - end | |
| 184 | - | |
| 185 | - before_should "call extra_options_for(:thumb/:large)" do | |
| 186 | - Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb) | |
| 187 | - Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large) | |
| 188 | - end | |
| 189 | - end | |
| 190 | - | |
| 191 | - context "An attachment with :path that is a proc" do | |
| 192 | - setup do | |
| 193 | - rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" } | |
| 194 | - | |
| 195 | - @file = File.new(File.join(File.dirname(__FILE__), | |
| 196 | - "fixtures", | |
| 197 | - "5k.png"), 'rb') | |
| 198 | - @dummyA = Dummy.new(:other => 'a') | |
| 199 | - @dummyA.avatar = @file | |
| 200 | - @dummyB = Dummy.new(:other => 'b') | |
| 201 | - @dummyB.avatar = @file | |
| 202 | - end | |
| 203 | - | |
| 204 | - teardown { @file.close } | |
| 205 | - | |
| 206 | - should "return correct path" do | |
| 207 | - assert_equal "path/a.png", @dummyA.avatar.path | |
| 208 | - assert_equal "path/b.png", @dummyB.avatar.path | |
| 209 | - end | |
| 210 | - end | |
| 211 | - | |
| 212 | - context "An attachment with :styles that is a proc" do | |
| 213 | - setup do | |
| 214 | - rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} } | |
| 215 | - | |
| 216 | - @attachment = Dummy.new.avatar | |
| 217 | - end | |
| 218 | - | |
| 219 | - should "have the correct geometry" do | |
| 220 | - assert_equal "50x50#", @attachment.styles[:thumb][:geometry] | |
| 221 | - end | |
| 222 | - end | |
| 223 | - | |
| 224 | - context "An attachment with :url that is a proc" do | |
| 225 | - setup do | |
| 226 | - rebuild_model :url => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" } | |
| 227 | - | |
| 228 | - @file = File.new(File.join(File.dirname(__FILE__), | |
| 229 | - "fixtures", | |
| 230 | - "5k.png"), 'rb') | |
| 231 | - @dummyA = Dummy.new(:other => 'a') | |
| 232 | - @dummyA.avatar = @file | |
| 233 | - @dummyB = Dummy.new(:other => 'b') | |
| 234 | - @dummyB.avatar = @file | |
| 235 | - end | |
| 236 | - | |
| 237 | - teardown { @file.close } | |
| 238 | - | |
| 239 | - should "return correct url" do | |
| 240 | - assert_equal "path/a.png", @dummyA.avatar.url(:original, false) | |
| 241 | - assert_equal "path/b.png", @dummyB.avatar.url(:original, false) | |
| 242 | - end | |
| 243 | - end | |
| 244 | - | |
| 245 | - geometry_specs = [ | |
| 246 | - [ lambda{|z| "50x50#" }, :png ], | |
| 247 | - lambda{|z| "50x50#" }, | |
| 248 | - { :geometry => lambda{|z| "50x50#" } } | |
| 249 | - ] | |
| 250 | - geometry_specs.each do |geometry_spec| | |
| 251 | - context "An attachment geometry like #{geometry_spec}" do | |
| 252 | - setup do | |
| 253 | - rebuild_model :styles => { :normal => geometry_spec } | |
| 254 | - @attachment = Dummy.new.avatar | |
| 255 | - end | |
| 256 | - | |
| 257 | - should "not run the procs immediately" do | |
| 258 | - assert_kind_of Proc, @attachment.styles[:normal][:geometry] | |
| 259 | - end | |
| 260 | - | |
| 261 | - context "when assigned" do | |
| 262 | - setup do | |
| 263 | - @file = StringIO.new(".") | |
| 264 | - @attachment.assign(@file) | |
| 265 | - end | |
| 266 | - | |
| 267 | - should "have the correct geometry" do | |
| 268 | - assert_equal "50x50#", @attachment.styles[:normal][:geometry] | |
| 269 | - end | |
| 270 | - end | |
| 271 | - end | |
| 272 | - end | |
| 273 | - | |
| 274 | - context "An attachment with both 'normal' and hash-style styles" do | |
| 275 | - setup do | |
| 276 | - rebuild_model :styles => { | |
| 277 | - :normal => ["50x50#", :png], | |
| 278 | - :hash => { :geometry => "50x50#", :format => :png } | |
| 279 | - } | |
| 280 | - @dummy = Dummy.new | |
| 281 | - @attachment = @dummy.avatar | |
| 282 | - end | |
| 283 | - | |
| 284 | - [:processors, :whiny, :convert_options, :geometry, :format].each do |field| | |
| 285 | - should "have the same #{field} field" do | |
| 286 | - assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field] | |
| 287 | - end | |
| 288 | - end | |
| 289 | - end | |
| 290 | - | |
| 291 | - context "An attachment with :processors that is a proc" do | |
| 292 | - setup do | |
| 293 | - rebuild_model :styles => { :normal => '' }, :processors => lambda { |a| [ :test ] } | |
| 294 | - @attachment = Dummy.new.avatar | |
| 295 | - end | |
| 296 | - | |
| 297 | - should "not run the proc immediately" do | |
| 298 | - assert_kind_of Proc, @attachment.styles[:normal][:processors] | |
| 299 | - end | |
| 300 | - | |
| 301 | - context "when assigned" do | |
| 302 | - setup do | |
| 303 | - @attachment.assign(StringIO.new(".")) | |
| 304 | - end | |
| 305 | - | |
| 306 | - should "have the correct processors" do | |
| 307 | - assert_equal [ :test ], @attachment.styles[:normal][:processors] | |
| 308 | - end | |
| 309 | - end | |
| 310 | - end | |
| 311 | - | |
| 312 | - context "An attachment with erroring processor" do | |
| 313 | - setup do | |
| 314 | - rebuild_model :processor => [:thumbnail], :styles => { :small => '' }, :whiny_thumbnails => true | |
| 315 | - @dummy = Dummy.new | |
| 316 | - Paperclip::Thumbnail.expects(:make).raises(Paperclip::PaperclipError, "cannot be processed.") | |
| 317 | - @file = StringIO.new("...") | |
| 318 | - @file.stubs(:to_tempfile).returns(@file) | |
| 319 | - @dummy.avatar = @file | |
| 320 | - end | |
| 321 | - | |
| 322 | - should "correctly forward processing error message to the instance" do | |
| 323 | - @dummy.valid? | |
| 324 | - assert_contains @dummy.errors.full_messages, "Avatar cannot be processed." | |
| 325 | - end | |
| 326 | - end | |
| 327 | - | |
| 328 | - context "An attachment with multiple processors" do | |
| 329 | - setup do | |
| 330 | - class Paperclip::Test < Paperclip::Processor; end | |
| 331 | - @style_params = { :once => {:one => 1, :two => 2} } | |
| 332 | - rebuild_model :processors => [:thumbnail, :test], :styles => @style_params | |
| 333 | - @dummy = Dummy.new | |
| 334 | - @file = StringIO.new("...") | |
| 335 | - @file.stubs(:to_tempfile).returns(@file) | |
| 336 | - Paperclip::Test.stubs(:make).returns(@file) | |
| 337 | - Paperclip::Thumbnail.stubs(:make).returns(@file) | |
| 338 | - end | |
| 339 | - | |
| 340 | - context "when assigned" do | |
| 341 | - setup { @dummy.avatar = @file } | |
| 342 | - | |
| 343 | - before_should "call #make on all specified processors" do | |
| 344 | - expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""}) | |
| 345 | - Paperclip::Thumbnail.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file) | |
| 346 | - Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file) | |
| 347 | - end | |
| 348 | - | |
| 349 | - before_should "call #make with attachment passed as third argument" do | |
| 350 | - expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""}) | |
| 351 | - Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file) | |
| 352 | - end | |
| 353 | - end | |
| 354 | - end | |
| 355 | - | |
| 356 | - context "An attachment with no processors defined" do | |
| 357 | - setup do | |
| 358 | - rebuild_model :processors => [], :styles => {:something => 1} | |
| 359 | - @dummy = Dummy.new | |
| 360 | - @file = StringIO.new("...") | |
| 361 | - end | |
| 362 | - should "raise when assigned to" do | |
| 363 | - assert_raises(RuntimeError){ @dummy.avatar = @file } | |
| 364 | - end | |
| 365 | - end | |
| 366 | - | |
| 367 | - context "Assigning an attachment with post_process hooks" do | |
| 368 | - setup do | |
| 369 | - rebuild_model :styles => { :something => "100x100#" } | |
| 370 | - Dummy.class_eval do | |
| 371 | - before_avatar_post_process :do_before_avatar | |
| 372 | - after_avatar_post_process :do_after_avatar | |
| 373 | - before_post_process :do_before_all | |
| 374 | - after_post_process :do_after_all | |
| 375 | - def do_before_avatar; end | |
| 376 | - def do_after_avatar; end | |
| 377 | - def do_before_all; end | |
| 378 | - def do_after_all; end | |
| 379 | - end | |
| 380 | - @file = StringIO.new(".") | |
| 381 | - @file.stubs(:to_tempfile).returns(@file) | |
| 382 | - @dummy = Dummy.new | |
| 383 | - Paperclip::Thumbnail.stubs(:make).returns(@file) | |
| 384 | - @attachment = @dummy.avatar | |
| 385 | - end | |
| 386 | - | |
| 387 | - should "call the defined callbacks when assigned" do | |
| 388 | - @dummy.expects(:do_before_avatar).with() | |
| 389 | - @dummy.expects(:do_after_avatar).with() | |
| 390 | - @dummy.expects(:do_before_all).with() | |
| 391 | - @dummy.expects(:do_after_all).with() | |
| 392 | - Paperclip::Thumbnail.expects(:make).returns(@file) | |
| 393 | - @dummy.avatar = @file | |
| 394 | - end | |
| 395 | - | |
| 396 | - should "not cancel the processing if a before_post_process returns nil" do | |
| 397 | - @dummy.expects(:do_before_avatar).with().returns(nil) | |
| 398 | - @dummy.expects(:do_after_avatar).with() | |
| 399 | - @dummy.expects(:do_before_all).with().returns(nil) | |
| 400 | - @dummy.expects(:do_after_all).with() | |
| 401 | - Paperclip::Thumbnail.expects(:make).returns(@file) | |
| 402 | - @dummy.avatar = @file | |
| 403 | - end | |
| 404 | - | |
| 405 | - should "cancel the processing if a before_post_process returns false" do | |
| 406 | - @dummy.expects(:do_before_avatar).never | |
| 407 | - @dummy.expects(:do_after_avatar).never | |
| 408 | - @dummy.expects(:do_before_all).with().returns(false) | |
| 409 | - @dummy.expects(:do_after_all).never | |
| 410 | - Paperclip::Thumbnail.expects(:make).never | |
| 411 | - @dummy.avatar = @file | |
| 412 | - end | |
| 413 | - | |
| 414 | - should "cancel the processing if a before_avatar_post_process returns false" do | |
| 415 | - @dummy.expects(:do_before_avatar).with().returns(false) | |
| 416 | - @dummy.expects(:do_after_avatar).never | |
| 417 | - @dummy.expects(:do_before_all).with().returns(true) | |
| 418 | - @dummy.expects(:do_after_all).never | |
| 419 | - Paperclip::Thumbnail.expects(:make).never | |
| 420 | - @dummy.avatar = @file | |
| 421 | - end | |
| 422 | - end | |
| 423 | - | |
| 424 | - context "Assigning an attachment" do | |
| 425 | - setup do | |
| 426 | - rebuild_model :styles => { :something => "100x100#" } | |
| 427 | - @file = StringIO.new(".") | |
| 428 | - @file.expects(:original_filename).returns("5k.png\n\n") | |
| 429 | - @file.expects(:content_type).returns("image/png\n\n") | |
| 430 | - @file.stubs(:to_tempfile).returns(@file) | |
| 431 | - @dummy = Dummy.new | |
| 432 | - Paperclip::Thumbnail.expects(:make).returns(@file) | |
| 433 | - @dummy.expects(:run_callbacks).with(:before_avatar_post_process, {:original => @file}) | |
| 434 | - @dummy.expects(:run_callbacks).with(:before_post_process, {:original => @file}) | |
| 435 | - @dummy.expects(:run_callbacks).with(:after_avatar_post_process, {:original => @file, :something => @file}) | |
| 436 | - @dummy.expects(:run_callbacks).with(:after_post_process, {:original => @file, :something => @file}) | |
| 437 | - @attachment = @dummy.avatar | |
| 438 | - @dummy.avatar = @file | |
| 439 | - end | |
| 440 | - | |
| 441 | - should "strip whitespace from original_filename field" do | |
| 442 | - assert_equal "5k.png", @dummy.avatar.original_filename | |
| 443 | - end | |
| 444 | - | |
| 445 | - should "strip whitespace from content_type field" do | |
| 446 | - assert_equal "image/png", @dummy.avatar.instance.avatar_content_type | |
| 447 | - end | |
| 448 | - end | |
| 449 | - | |
| 450 | - context "Attachment with strange letters" do | |
| 451 | - setup do | |
| 452 | - rebuild_model | |
| 453 | - | |
| 454 | - @not_file = mock | |
| 455 | - @tempfile = mock | |
| 456 | - @not_file.stubs(:nil?).returns(false) | |
| 457 | - @not_file.expects(:size).returns(10) | |
| 458 | - @tempfile.expects(:size).returns(10) | |
| 459 | - @not_file.expects(:to_tempfile).returns(@tempfile) | |
| 460 | - @not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n") | |
| 461 | - @not_file.expects(:content_type).returns("image/png\r\n") | |
| 462 | - | |
| 463 | - @dummy = Dummy.new | |
| 464 | - @attachment = @dummy.avatar | |
| 465 | - @attachment.expects(:valid_assignment?).with(@not_file).returns(true) | |
| 466 | - @attachment.expects(:queue_existing_for_delete) | |
| 467 | - @attachment.expects(:post_process) | |
| 468 | - @attachment.expects(:valid?).returns(true) | |
| 469 | - @attachment.expects(:validate) | |
| 470 | - @dummy.avatar = @not_file | |
| 471 | - end | |
| 472 | - | |
| 473 | - should "remove strange letters and replace with underscore (_)" do | |
| 474 | - assert_equal "sheep_say_b_.png", @dummy.avatar.original_filename | |
| 475 | - end | |
| 476 | - | |
| 477 | - end | |
| 478 | - | |
| 479 | - context "An attachment" do | |
| 480 | - setup do | |
| 481 | - @old_defaults = Paperclip::Attachment.default_options.dup | |
| 482 | - Paperclip::Attachment.default_options.merge!({ | |
| 483 | - :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 484 | - }) | |
| 485 | - FileUtils.rm_rf("tmp") | |
| 486 | - rebuild_model | |
| 487 | - @instance = Dummy.new | |
| 488 | - @attachment = Paperclip::Attachment.new(:avatar, @instance) | |
| 489 | - @file = File.new(File.join(File.dirname(__FILE__), | |
| 490 | - "fixtures", | |
| 491 | - "5k.png"), 'rb') | |
| 492 | - end | |
| 493 | - | |
| 494 | - teardown do | |
| 495 | - @file.close | |
| 496 | - Paperclip::Attachment.default_options.merge!(@old_defaults) | |
| 497 | - end | |
| 498 | - | |
| 499 | - should "raise if there are not the correct columns when you try to assign" do | |
| 500 | - @other_attachment = Paperclip::Attachment.new(:not_here, @instance) | |
| 501 | - assert_raises(Paperclip::PaperclipError) do | |
| 502 | - @other_attachment.assign(@file) | |
| 503 | - end | |
| 504 | - end | |
| 505 | - | |
| 506 | - should "return its default_url when no file assigned" do | |
| 507 | - assert @attachment.to_file.nil? | |
| 508 | - assert_equal "/avatars/original/missing.png", @attachment.url | |
| 509 | - assert_equal "/avatars/blah/missing.png", @attachment.url(:blah) | |
| 510 | - end | |
| 511 | - | |
| 512 | - should "return nil as path when no file assigned" do | |
| 513 | - assert @attachment.to_file.nil? | |
| 514 | - assert_equal nil, @attachment.path | |
| 515 | - assert_equal nil, @attachment.path(:blah) | |
| 516 | - end | |
| 517 | - | |
| 518 | - context "with a file assigned in the database" do | |
| 519 | - setup do | |
| 520 | - @attachment.stubs(:instance_read).with(:file_name).returns("5k.png") | |
| 521 | - @attachment.stubs(:instance_read).with(:content_type).returns("image/png") | |
| 522 | - @attachment.stubs(:instance_read).with(:file_size).returns(12345) | |
| 523 | - now = Time.now | |
| 524 | - Time.stubs(:now).returns(now) | |
| 525 | - @attachment.stubs(:instance_read).with(:updated_at).returns(Time.now) | |
| 526 | - end | |
| 527 | - | |
| 528 | - should "return a correct url even if the file does not exist" do | |
| 529 | - assert_nil @attachment.to_file | |
| 530 | - assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah) | |
| 531 | - end | |
| 532 | - | |
| 533 | - should "make sure the updated_at mtime is in the url if it is defined" do | |
| 534 | - assert_match %r{#{Time.now.to_i}$}, @attachment.url(:blah) | |
| 535 | - end | |
| 536 | - | |
| 537 | - should "make sure the updated_at mtime is NOT in the url if false is passed to the url method" do | |
| 538 | - assert_no_match %r{#{Time.now.to_i}$}, @attachment.url(:blah, false) | |
| 539 | - end | |
| 540 | - | |
| 541 | - context "with the updated_at field removed" do | |
| 542 | - setup do | |
| 543 | - @attachment.stubs(:instance_read).with(:updated_at).returns(nil) | |
| 544 | - end | |
| 545 | - | |
| 546 | - should "only return the url without the updated_at when sent #url" do | |
| 547 | - assert_match "/avatars/#{@instance.id}/blah/5k.png", @attachment.url(:blah) | |
| 548 | - end | |
| 549 | - end | |
| 550 | - | |
| 551 | - should "return the proper path when filename has a single .'s" do | |
| 552 | - assert_equal "./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png", @attachment.path | |
| 553 | - end | |
| 554 | - | |
| 555 | - should "return the proper path when filename has multiple .'s" do | |
| 556 | - @attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png") | |
| 557 | - assert_equal "./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png", @attachment.path | |
| 558 | - end | |
| 559 | - | |
| 560 | - context "when expecting three styles" do | |
| 561 | - setup do | |
| 562 | - styles = {:styles => { :large => ["400x400", :png], | |
| 563 | - :medium => ["100x100", :gif], | |
| 564 | - :small => ["32x32#", :jpg]}} | |
| 565 | - @attachment = Paperclip::Attachment.new(:avatar, | |
| 566 | - @instance, | |
| 567 | - styles) | |
| 568 | - end | |
| 569 | - | |
| 570 | - context "and assigned a file" do | |
| 571 | - setup do | |
| 572 | - now = Time.now | |
| 573 | - Time.stubs(:now).returns(now) | |
| 574 | - @attachment.assign(@file) | |
| 575 | - end | |
| 576 | - | |
| 577 | - should "be dirty" do | |
| 578 | - assert @attachment.dirty? | |
| 579 | - end | |
| 580 | - | |
| 581 | - context "and saved" do | |
| 582 | - setup do | |
| 583 | - @attachment.save | |
| 584 | - end | |
| 585 | - | |
| 586 | - should "return the real url" do | |
| 587 | - file = @attachment.to_file | |
| 588 | - assert file | |
| 589 | - assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url | |
| 590 | - assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small) | |
| 591 | - file.close | |
| 592 | - end | |
| 593 | - | |
| 594 | - should "commit the files to disk" do | |
| 595 | - [:large, :medium, :small].each do |style| | |
| 596 | - io = @attachment.to_io(style) | |
| 597 | - assert File.exists?(io) | |
| 598 | - assert ! io.is_a?(::Tempfile) | |
| 599 | - io.close | |
| 600 | - end | |
| 601 | - end | |
| 602 | - | |
| 603 | - should "save the files as the right formats and sizes" do | |
| 604 | - [[:large, 400, 61, "PNG"], | |
| 605 | - [:medium, 100, 15, "GIF"], | |
| 606 | - [:small, 32, 32, "JPEG"]].each do |style| | |
| 607 | - cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"] | |
| 608 | - out = `#{cmd}` | |
| 609 | - width, height, size, format = out.split(" ") | |
| 610 | - assert_equal style[1].to_s, width.to_s | |
| 611 | - assert_equal style[2].to_s, height.to_s | |
| 612 | - assert_equal style[3].to_s, format.to_s | |
| 613 | - end | |
| 614 | - end | |
| 615 | - | |
| 616 | - should "still have its #file attribute not be nil" do | |
| 617 | - assert ! (file = @attachment.to_file).nil? | |
| 618 | - file.close | |
| 619 | - end | |
| 620 | - | |
| 621 | - context "and trying to delete" do | |
| 622 | - setup do | |
| 623 | - @existing_names = @attachment.styles.keys.collect do |style| | |
| 624 | - @attachment.path(style) | |
| 625 | - end | |
| 626 | - end | |
| 627 | - | |
| 628 | - should "delete the files after assigning nil" do | |
| 629 | - @attachment.expects(:instance_write).with(:file_name, nil) | |
| 630 | - @attachment.expects(:instance_write).with(:content_type, nil) | |
| 631 | - @attachment.expects(:instance_write).with(:file_size, nil) | |
| 632 | - @attachment.expects(:instance_write).with(:updated_at, nil) | |
| 633 | - @attachment.assign nil | |
| 634 | - @attachment.save | |
| 635 | - @existing_names.each{|f| assert ! File.exists?(f) } | |
| 636 | - end | |
| 637 | - | |
| 638 | - should "delete the files when you call #clear and #save" do | |
| 639 | - @attachment.expects(:instance_write).with(:file_name, nil) | |
| 640 | - @attachment.expects(:instance_write).with(:content_type, nil) | |
| 641 | - @attachment.expects(:instance_write).with(:file_size, nil) | |
| 642 | - @attachment.expects(:instance_write).with(:updated_at, nil) | |
| 643 | - @attachment.clear | |
| 644 | - @attachment.save | |
| 645 | - @existing_names.each{|f| assert ! File.exists?(f) } | |
| 646 | - end | |
| 647 | - | |
| 648 | - should "delete the files when you call #delete" do | |
| 649 | - @attachment.expects(:instance_write).with(:file_name, nil) | |
| 650 | - @attachment.expects(:instance_write).with(:content_type, nil) | |
| 651 | - @attachment.expects(:instance_write).with(:file_size, nil) | |
| 652 | - @attachment.expects(:instance_write).with(:updated_at, nil) | |
| 653 | - @attachment.destroy | |
| 654 | - @existing_names.each{|f| assert ! File.exists?(f) } | |
| 655 | - end | |
| 656 | - end | |
| 657 | - end | |
| 658 | - end | |
| 659 | - end | |
| 660 | - | |
| 661 | - end | |
| 662 | - | |
| 663 | - context "when trying a nonexistant storage type" do | |
| 664 | - setup do | |
| 665 | - rebuild_model :storage => :not_here | |
| 666 | - end | |
| 667 | - | |
| 668 | - should "not be able to find the module" do | |
| 669 | - assert_raise(NameError){ Dummy.new.avatar } | |
| 670 | - end | |
| 671 | - end | |
| 672 | - end | |
| 673 | - | |
| 674 | - context "An attachment with only a avatar_file_name column" do | |
| 675 | - setup do | |
| 676 | - ActiveRecord::Base.connection.create_table :dummies, :force => true do |table| | |
| 677 | - table.column :avatar_file_name, :string | |
| 678 | - end | |
| 679 | - rebuild_class | |
| 680 | - @dummy = Dummy.new | |
| 681 | - @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | |
| 682 | - end | |
| 683 | - | |
| 684 | - teardown { @file.close } | |
| 685 | - | |
| 686 | - should "not error when assigned an attachment" do | |
| 687 | - assert_nothing_raised { @dummy.avatar = @file } | |
| 688 | - end | |
| 689 | - | |
| 690 | - should "return the time when sent #avatar_updated_at" do | |
| 691 | - now = Time.now | |
| 692 | - Time.stubs(:now).returns(now) | |
| 693 | - @dummy.avatar = @file | |
| 694 | - assert now, @dummy.avatar.updated_at | |
| 695 | - end | |
| 696 | - | |
| 697 | - should "return nil when reloaded and sent #avatar_updated_at" do | |
| 698 | - @dummy.save | |
| 699 | - @dummy.reload | |
| 700 | - assert_nil @dummy.avatar.updated_at | |
| 701 | - end | |
| 702 | - | |
| 703 | - should "return the right value when sent #avatar_file_size" do | |
| 704 | - @dummy.avatar = @file | |
| 705 | - assert_equal @file.size, @dummy.avatar.size | |
| 706 | - end | |
| 707 | - | |
| 708 | - context "and avatar_updated_at column" do | |
| 709 | - setup do | |
| 710 | - ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp | |
| 711 | - rebuild_class | |
| 712 | - @dummy = Dummy.new | |
| 713 | - end | |
| 714 | - | |
| 715 | - should "not error when assigned an attachment" do | |
| 716 | - assert_nothing_raised { @dummy.avatar = @file } | |
| 717 | - end | |
| 718 | - | |
| 719 | - should "return the right value when sent #avatar_updated_at" do | |
| 720 | - now = Time.now | |
| 721 | - Time.stubs(:now).returns(now) | |
| 722 | - @dummy.avatar = @file | |
| 723 | - assert_equal now.to_i, @dummy.avatar.updated_at | |
| 724 | - end | |
| 725 | - end | |
| 726 | - | |
| 727 | - context "and avatar_content_type column" do | |
| 728 | - setup do | |
| 729 | - ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string | |
| 730 | - rebuild_class | |
| 731 | - @dummy = Dummy.new | |
| 732 | - end | |
| 733 | - | |
| 734 | - should "not error when assigned an attachment" do | |
| 735 | - assert_nothing_raised { @dummy.avatar = @file } | |
| 736 | - end | |
| 737 | - | |
| 738 | - should "return the right value when sent #avatar_content_type" do | |
| 739 | - @dummy.avatar = @file | |
| 740 | - assert_equal "image/png", @dummy.avatar.content_type | |
| 741 | - end | |
| 742 | - end | |
| 743 | - | |
| 744 | - context "and avatar_file_size column" do | |
| 745 | - setup do | |
| 746 | - ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer | |
| 747 | - rebuild_class | |
| 748 | - @dummy = Dummy.new | |
| 749 | - end | |
| 750 | - | |
| 751 | - should "not error when assigned an attachment" do | |
| 752 | - assert_nothing_raised { @dummy.avatar = @file } | |
| 753 | - end | |
| 754 | - | |
| 755 | - should "return the right value when sent #avatar_file_size" do | |
| 756 | - @dummy.avatar = @file | |
| 757 | - assert_equal @file.size, @dummy.avatar.size | |
| 758 | - end | |
| 759 | - | |
| 760 | - should "return the right value when saved, reloaded, and sent #avatar_file_size" do | |
| 761 | - @dummy.avatar = @file | |
| 762 | - @dummy.save | |
| 763 | - @dummy = Dummy.find(@dummy.id) | |
| 764 | - assert_equal @file.size, @dummy.avatar.size | |
| 765 | - end | |
| 766 | - end | |
| 767 | - end | |
| 768 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/database.yml
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/fixtures/12k.png
11.8 KB
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/fixtures/50x50.png
1.58 KB
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/fixtures/5k.png
4.35 KB
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/fixtures/bad.png
| ... | ... | @@ -1 +0,0 @@ |
| 1 | -This is not an image. |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/fixtures/s3.yml
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/fixtures/text.txt
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/fixtures/twopage.pdf
No preview for this file type
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/geometry_test.rb
| ... | ... | @@ -1,177 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class GeometryTest < Test::Unit::TestCase | |
| 4 | - context "Paperclip::Geometry" do | |
| 5 | - should "correctly report its given dimensions" do | |
| 6 | - assert @geo = Paperclip::Geometry.new(1024, 768) | |
| 7 | - assert_equal 1024, @geo.width | |
| 8 | - assert_equal 768, @geo.height | |
| 9 | - end | |
| 10 | - | |
| 11 | - should "set height to 0 if height dimension is missing" do | |
| 12 | - assert @geo = Paperclip::Geometry.new(1024) | |
| 13 | - assert_equal 1024, @geo.width | |
| 14 | - assert_equal 0, @geo.height | |
| 15 | - end | |
| 16 | - | |
| 17 | - should "set width to 0 if width dimension is missing" do | |
| 18 | - assert @geo = Paperclip::Geometry.new(nil, 768) | |
| 19 | - assert_equal 0, @geo.width | |
| 20 | - assert_equal 768, @geo.height | |
| 21 | - end | |
| 22 | - | |
| 23 | - should "be generated from a WxH-formatted string" do | |
| 24 | - assert @geo = Paperclip::Geometry.parse("800x600") | |
| 25 | - assert_equal 800, @geo.width | |
| 26 | - assert_equal 600, @geo.height | |
| 27 | - end | |
| 28 | - | |
| 29 | - should "be generated from a xH-formatted string" do | |
| 30 | - assert @geo = Paperclip::Geometry.parse("x600") | |
| 31 | - assert_equal 0, @geo.width | |
| 32 | - assert_equal 600, @geo.height | |
| 33 | - end | |
| 34 | - | |
| 35 | - should "be generated from a Wx-formatted string" do | |
| 36 | - assert @geo = Paperclip::Geometry.parse("800x") | |
| 37 | - assert_equal 800, @geo.width | |
| 38 | - assert_equal 0, @geo.height | |
| 39 | - end | |
| 40 | - | |
| 41 | - should "be generated from a W-formatted string" do | |
| 42 | - assert @geo = Paperclip::Geometry.parse("800") | |
| 43 | - assert_equal 800, @geo.width | |
| 44 | - assert_equal 0, @geo.height | |
| 45 | - end | |
| 46 | - | |
| 47 | - should "ensure the modifier is nil if not present" do | |
| 48 | - assert @geo = Paperclip::Geometry.parse("123x456") | |
| 49 | - assert_nil @geo.modifier | |
| 50 | - end | |
| 51 | - | |
| 52 | - should "treat x and X the same in geometries" do | |
| 53 | - @lower = Paperclip::Geometry.parse("123x456") | |
| 54 | - @upper = Paperclip::Geometry.parse("123X456") | |
| 55 | - assert_equal 123, @lower.width | |
| 56 | - assert_equal 123, @upper.width | |
| 57 | - assert_equal 456, @lower.height | |
| 58 | - assert_equal 456, @upper.height | |
| 59 | - end | |
| 60 | - | |
| 61 | - ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod| | |
| 62 | - should "ensure the modifier #{mod.inspect} is preserved" do | |
| 63 | - assert @geo = Paperclip::Geometry.parse("123x456#{mod}") | |
| 64 | - assert_equal mod, @geo.modifier | |
| 65 | - assert_equal "123x456#{mod}", @geo.to_s | |
| 66 | - end | |
| 67 | - end | |
| 68 | - | |
| 69 | - ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod| | |
| 70 | - should "ensure the modifier #{mod.inspect} is preserved with no height" do | |
| 71 | - assert @geo = Paperclip::Geometry.parse("123x#{mod}") | |
| 72 | - assert_equal mod, @geo.modifier | |
| 73 | - assert_equal "123#{mod}", @geo.to_s | |
| 74 | - end | |
| 75 | - end | |
| 76 | - | |
| 77 | - should "make sure the modifier gets passed during transformation_to" do | |
| 78 | - assert @src = Paperclip::Geometry.parse("123x456") | |
| 79 | - assert @dst = Paperclip::Geometry.parse("123x456>") | |
| 80 | - assert_equal "123x456>", @src.transformation_to(@dst).to_s | |
| 81 | - end | |
| 82 | - | |
| 83 | - should "generate correct ImageMagick formatting string for W-formatted string" do | |
| 84 | - assert @geo = Paperclip::Geometry.parse("800") | |
| 85 | - assert_equal "800", @geo.to_s | |
| 86 | - end | |
| 87 | - | |
| 88 | - should "generate correct ImageMagick formatting string for Wx-formatted string" do | |
| 89 | - assert @geo = Paperclip::Geometry.parse("800x") | |
| 90 | - assert_equal "800", @geo.to_s | |
| 91 | - end | |
| 92 | - | |
| 93 | - should "generate correct ImageMagick formatting string for xH-formatted string" do | |
| 94 | - assert @geo = Paperclip::Geometry.parse("x600") | |
| 95 | - assert_equal "x600", @geo.to_s | |
| 96 | - end | |
| 97 | - | |
| 98 | - should "generate correct ImageMagick formatting string for WxH-formatted string" do | |
| 99 | - assert @geo = Paperclip::Geometry.parse("800x600") | |
| 100 | - assert_equal "800x600", @geo.to_s | |
| 101 | - end | |
| 102 | - | |
| 103 | - should "be generated from a file" do | |
| 104 | - file = File.join(File.dirname(__FILE__), "fixtures", "5k.png") | |
| 105 | - file = File.new(file, 'rb') | |
| 106 | - assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) } | |
| 107 | - assert @geo.height > 0 | |
| 108 | - assert @geo.width > 0 | |
| 109 | - end | |
| 110 | - | |
| 111 | - should "be generated from a file path" do | |
| 112 | - file = File.join(File.dirname(__FILE__), "fixtures", "5k.png") | |
| 113 | - assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) } | |
| 114 | - assert @geo.height > 0 | |
| 115 | - assert @geo.width > 0 | |
| 116 | - end | |
| 117 | - | |
| 118 | - should "not generate from a bad file" do | |
| 119 | - file = "/home/This File Does Not Exist.omg" | |
| 120 | - assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) } | |
| 121 | - end | |
| 122 | - | |
| 123 | - [['vertical', 900, 1440, true, false, false, 1440, 900, 0.625], | |
| 124 | - ['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333], | |
| 125 | - ['square', 100, 100, false, false, true, 100, 100, 1]].each do |args| | |
| 126 | - context "performing calculations on a #{args[0]} viewport" do | |
| 127 | - setup do | |
| 128 | - @geo = Paperclip::Geometry.new(args[1], args[2]) | |
| 129 | - end | |
| 130 | - | |
| 131 | - should "#{args[3] ? "" : "not"} be vertical" do | |
| 132 | - assert_equal args[3], @geo.vertical? | |
| 133 | - end | |
| 134 | - | |
| 135 | - should "#{args[4] ? "" : "not"} be horizontal" do | |
| 136 | - assert_equal args[4], @geo.horizontal? | |
| 137 | - end | |
| 138 | - | |
| 139 | - should "#{args[5] ? "" : "not"} be square" do | |
| 140 | - assert_equal args[5], @geo.square? | |
| 141 | - end | |
| 142 | - | |
| 143 | - should "report that #{args[6]} is the larger dimension" do | |
| 144 | - assert_equal args[6], @geo.larger | |
| 145 | - end | |
| 146 | - | |
| 147 | - should "report that #{args[7]} is the smaller dimension" do | |
| 148 | - assert_equal args[7], @geo.smaller | |
| 149 | - end | |
| 150 | - | |
| 151 | - should "have an aspect ratio of #{args[8]}" do | |
| 152 | - assert_in_delta args[8], @geo.aspect, 0.0001 | |
| 153 | - end | |
| 154 | - end | |
| 155 | - end | |
| 156 | - | |
| 157 | - [[ [1000, 100], [64, 64], "x64", "64x64+288+0" ], | |
| 158 | - [ [100, 1000], [50, 950], "x950", "50x950+22+0" ], | |
| 159 | - [ [100, 1000], [50, 25], "50x", "50x25+0+237" ]]. each do |args| | |
| 160 | - context "of #{args[0].inspect} and given a Geometry #{args[1].inspect} and sent transform_to" do | |
| 161 | - setup do | |
| 162 | - @geo = Paperclip::Geometry.new(*args[0]) | |
| 163 | - @dst = Paperclip::Geometry.new(*args[1]) | |
| 164 | - @scale, @crop = @geo.transformation_to @dst, true | |
| 165 | - end | |
| 166 | - | |
| 167 | - should "be able to return the correct scaling transformation geometry #{args[2]}" do | |
| 168 | - assert_equal args[2], @scale | |
| 169 | - end | |
| 170 | - | |
| 171 | - should "be able to return the correct crop transformation geometry #{args[3]}" do | |
| 172 | - assert_equal args[3], @crop | |
| 173 | - end | |
| 174 | - end | |
| 175 | - end | |
| 176 | - end | |
| 177 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/helper.rb
| ... | ... | @@ -1,100 +0,0 @@ |
| 1 | -require 'rubygems' | |
| 2 | -require 'test/unit' | |
| 3 | -gem 'thoughtbot-shoulda', ">= 2.9.0" | |
| 4 | -require 'shoulda' | |
| 5 | -require 'mocha' | |
| 6 | -require 'tempfile' | |
| 7 | - | |
| 8 | -gem 'sqlite3-ruby' | |
| 9 | - | |
| 10 | -require 'active_record' | |
| 11 | -require 'active_support' | |
| 12 | -begin | |
| 13 | - require 'ruby-debug' | |
| 14 | -rescue LoadError | |
| 15 | - puts "ruby-debug not loaded" | |
| 16 | -end | |
| 17 | - | |
| 18 | -ROOT = File.join(File.dirname(__FILE__), '..') | |
| 19 | -RAILS_ROOT = ROOT | |
| 20 | -RAILS_ENV = "test" | |
| 21 | - | |
| 22 | -$LOAD_PATH << File.join(ROOT, 'lib') | |
| 23 | -$LOAD_PATH << File.join(ROOT, 'lib', 'paperclip') | |
| 24 | - | |
| 25 | -require File.join(ROOT, 'lib', 'paperclip.rb') | |
| 26 | - | |
| 27 | -require 'shoulda_macros/paperclip' | |
| 28 | - | |
| 29 | -FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures") | |
| 30 | -config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) | |
| 31 | -ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log") | |
| 32 | -ActiveRecord::Base.establish_connection(config['test']) | |
| 33 | - | |
| 34 | -def reset_class class_name | |
| 35 | - ActiveRecord::Base.send(:include, Paperclip) | |
| 36 | - Object.send(:remove_const, class_name) rescue nil | |
| 37 | - klass = Object.const_set(class_name, Class.new(ActiveRecord::Base)) | |
| 38 | - klass.class_eval{ include Paperclip } | |
| 39 | - klass | |
| 40 | -end | |
| 41 | - | |
| 42 | -def reset_table table_name, &block | |
| 43 | - block ||= lambda{ true } | |
| 44 | - ActiveRecord::Base.connection.create_table :dummies, {:force => true}, &block | |
| 45 | -end | |
| 46 | - | |
| 47 | -def modify_table table_name, &block | |
| 48 | - ActiveRecord::Base.connection.change_table :dummies, &block | |
| 49 | -end | |
| 50 | - | |
| 51 | -def rebuild_model options = {} | |
| 52 | - ActiveRecord::Base.connection.create_table :dummies, :force => true do |table| | |
| 53 | - table.column :other, :string | |
| 54 | - table.column :avatar_file_name, :string | |
| 55 | - table.column :avatar_content_type, :string | |
| 56 | - table.column :avatar_file_size, :integer | |
| 57 | - table.column :avatar_updated_at, :datetime | |
| 58 | - end | |
| 59 | - rebuild_class options | |
| 60 | -end | |
| 61 | - | |
| 62 | -def rebuild_class options = {} | |
| 63 | - ActiveRecord::Base.send(:include, Paperclip) | |
| 64 | - Object.send(:remove_const, "Dummy") rescue nil | |
| 65 | - Object.const_set("Dummy", Class.new(ActiveRecord::Base)) | |
| 66 | - Dummy.class_eval do | |
| 67 | - include Paperclip | |
| 68 | - has_attached_file :avatar, options | |
| 69 | - end | |
| 70 | -end | |
| 71 | - | |
| 72 | -def temporary_rails_env(new_env) | |
| 73 | - old_env = Object.const_defined?("RAILS_ENV") ? RAILS_ENV : nil | |
| 74 | - silence_warnings do | |
| 75 | - Object.const_set("RAILS_ENV", new_env) | |
| 76 | - end | |
| 77 | - yield | |
| 78 | - silence_warnings do | |
| 79 | - Object.const_set("RAILS_ENV", old_env) | |
| 80 | - end | |
| 81 | -end | |
| 82 | - | |
| 83 | -class FakeModel | |
| 84 | - attr_accessor :avatar_file_name, | |
| 85 | - :avatar_file_size, | |
| 86 | - :avatar_last_updated, | |
| 87 | - :avatar_content_type, | |
| 88 | - :id | |
| 89 | - | |
| 90 | - def errors | |
| 91 | - @errors ||= [] | |
| 92 | - end | |
| 93 | - | |
| 94 | - def run_callbacks name, *args | |
| 95 | - end | |
| 96 | -end | |
| 97 | - | |
| 98 | -def attachment options | |
| 99 | - Paperclip::Attachment.new(:avatar, FakeModel.new, options) | |
| 100 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/integration_test.rb
| ... | ... | @@ -1,481 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class IntegrationTest < Test::Unit::TestCase | |
| 4 | - context "Many models at once" do | |
| 5 | - setup do | |
| 6 | - rebuild_model | |
| 7 | - @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | |
| 8 | - 300.times do |i| | |
| 9 | - Dummy.create! :avatar => @file | |
| 10 | - end | |
| 11 | - end | |
| 12 | - | |
| 13 | - should "not exceed the open file limit" do | |
| 14 | - assert_nothing_raised do | |
| 15 | - dummies = Dummy.find(:all) | |
| 16 | - dummies.each { |dummy| dummy.avatar } | |
| 17 | - end | |
| 18 | - end | |
| 19 | - end | |
| 20 | - | |
| 21 | - context "An attachment" do | |
| 22 | - setup do | |
| 23 | - rebuild_model :styles => { :thumb => "50x50#" } | |
| 24 | - @dummy = Dummy.new | |
| 25 | - @file = File.new(File.join(File.dirname(__FILE__), | |
| 26 | - "fixtures", | |
| 27 | - "5k.png"), 'rb') | |
| 28 | - @dummy.avatar = @file | |
| 29 | - assert @dummy.save | |
| 30 | - end | |
| 31 | - | |
| 32 | - teardown { @file.close } | |
| 33 | - | |
| 34 | - should "create its thumbnails properly" do | |
| 35 | - assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"` | |
| 36 | - end | |
| 37 | - | |
| 38 | - context "redefining its attachment styles" do | |
| 39 | - setup do | |
| 40 | - Dummy.class_eval do | |
| 41 | - has_attached_file :avatar, :styles => { :thumb => "150x25#" } | |
| 42 | - has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } } | |
| 43 | - end | |
| 44 | - @d2 = Dummy.find(@dummy.id) | |
| 45 | - @d2.avatar.reprocess! | |
| 46 | - @d2.save | |
| 47 | - end | |
| 48 | - | |
| 49 | - should "create its thumbnails properly" do | |
| 50 | - assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"` | |
| 51 | - assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"` | |
| 52 | - end | |
| 53 | - end | |
| 54 | - end | |
| 55 | - | |
| 56 | - context "A model that modifies its original" do | |
| 57 | - setup do | |
| 58 | - rebuild_model :styles => { :original => "2x2#" } | |
| 59 | - @dummy = Dummy.new | |
| 60 | - @file = File.new(File.join(File.dirname(__FILE__), | |
| 61 | - "fixtures", | |
| 62 | - "5k.png"), 'rb') | |
| 63 | - @dummy.avatar = @file | |
| 64 | - end | |
| 65 | - | |
| 66 | - should "report the file size of the processed file and not the original" do | |
| 67 | - assert_not_equal @file.size, @dummy.avatar.size | |
| 68 | - end | |
| 69 | - | |
| 70 | - teardown { @file.close } | |
| 71 | - end | |
| 72 | - | |
| 73 | - context "A model with attachments scoped under an id" do | |
| 74 | - setup do | |
| 75 | - rebuild_model :styles => { :large => "100x100", | |
| 76 | - :medium => "50x50" }, | |
| 77 | - :path => ":rails_root/tmp/:id/:attachments/:style.:extension" | |
| 78 | - @dummy = Dummy.new | |
| 79 | - @file = File.new(File.join(File.dirname(__FILE__), | |
| 80 | - "fixtures", | |
| 81 | - "5k.png"), 'rb') | |
| 82 | - @dummy.avatar = @file | |
| 83 | - end | |
| 84 | - | |
| 85 | - teardown { @file.close } | |
| 86 | - | |
| 87 | - context "when saved" do | |
| 88 | - setup do | |
| 89 | - @dummy.save | |
| 90 | - @saved_path = @dummy.avatar.path(:large) | |
| 91 | - end | |
| 92 | - | |
| 93 | - should "have a large file in the right place" do | |
| 94 | - assert File.exists?(@dummy.avatar.path(:large)) | |
| 95 | - end | |
| 96 | - | |
| 97 | - context "and deleted" do | |
| 98 | - setup do | |
| 99 | - @dummy.avatar.clear | |
| 100 | - @dummy.save | |
| 101 | - end | |
| 102 | - | |
| 103 | - should "not have a large file in the right place anymore" do | |
| 104 | - assert ! File.exists?(@saved_path) | |
| 105 | - end | |
| 106 | - | |
| 107 | - should "not have its next two parent directories" do | |
| 108 | - assert ! File.exists?(File.dirname(@saved_path)) | |
| 109 | - assert ! File.exists?(File.dirname(File.dirname(@saved_path))) | |
| 110 | - end | |
| 111 | - | |
| 112 | - before_should "not die if an unexpected SystemCallError happens" do | |
| 113 | - FileUtils.stubs(:rmdir).raises(Errno::EPIPE) | |
| 114 | - end | |
| 115 | - end | |
| 116 | - end | |
| 117 | - end | |
| 118 | - | |
| 119 | - context "A model with no attachment validation" do | |
| 120 | - setup do | |
| 121 | - rebuild_model :styles => { :large => "300x300>", | |
| 122 | - :medium => "100x100", | |
| 123 | - :thumb => ["32x32#", :gif] }, | |
| 124 | - :default_style => :medium, | |
| 125 | - :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 126 | - :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 127 | - @dummy = Dummy.new | |
| 128 | - end | |
| 129 | - | |
| 130 | - should "have its definition return false when asked about whiny_thumbnails" do | |
| 131 | - assert ! Dummy.attachment_definitions[:avatar][:whiny_thumbnails] | |
| 132 | - end | |
| 133 | - | |
| 134 | - context "when validates_attachment_thumbnails is called" do | |
| 135 | - setup do | |
| 136 | - Dummy.validates_attachment_thumbnails :avatar | |
| 137 | - end | |
| 138 | - | |
| 139 | - should "have its definition return true when asked about whiny_thumbnails" do | |
| 140 | - assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails] | |
| 141 | - end | |
| 142 | - end | |
| 143 | - | |
| 144 | - context "redefined to have attachment validations" do | |
| 145 | - setup do | |
| 146 | - rebuild_model :styles => { :large => "300x300>", | |
| 147 | - :medium => "100x100", | |
| 148 | - :thumb => ["32x32#", :gif] }, | |
| 149 | - :whiny_thumbnails => true, | |
| 150 | - :default_style => :medium, | |
| 151 | - :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 152 | - :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 153 | - end | |
| 154 | - | |
| 155 | - should "have its definition return true when asked about whiny_thumbnails" do | |
| 156 | - assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails] | |
| 157 | - end | |
| 158 | - end | |
| 159 | - end | |
| 160 | - | |
| 161 | - context "A model with no convert_options setting" do | |
| 162 | - setup do | |
| 163 | - rebuild_model :styles => { :large => "300x300>", | |
| 164 | - :medium => "100x100", | |
| 165 | - :thumb => ["32x32#", :gif] }, | |
| 166 | - :default_style => :medium, | |
| 167 | - :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 168 | - :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 169 | - @dummy = Dummy.new | |
| 170 | - end | |
| 171 | - | |
| 172 | - should "have its definition return nil when asked about convert_options" do | |
| 173 | - assert ! Dummy.attachment_definitions[:avatar][:convert_options] | |
| 174 | - end | |
| 175 | - | |
| 176 | - context "redefined to have convert_options setting" do | |
| 177 | - setup do | |
| 178 | - rebuild_model :styles => { :large => "300x300>", | |
| 179 | - :medium => "100x100", | |
| 180 | - :thumb => ["32x32#", :gif] }, | |
| 181 | - :convert_options => "-strip -depth 8", | |
| 182 | - :default_style => :medium, | |
| 183 | - :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 184 | - :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 185 | - end | |
| 186 | - | |
| 187 | - should "have its definition return convert_options value when asked about convert_options" do | |
| 188 | - assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options] | |
| 189 | - end | |
| 190 | - end | |
| 191 | - end | |
| 192 | - | |
| 193 | - context "A model with a filesystem attachment" do | |
| 194 | - setup do | |
| 195 | - rebuild_model :styles => { :large => "300x300>", | |
| 196 | - :medium => "100x100", | |
| 197 | - :thumb => ["32x32#", :gif] }, | |
| 198 | - :whiny_thumbnails => true, | |
| 199 | - :default_style => :medium, | |
| 200 | - :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 201 | - :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 202 | - @dummy = Dummy.new | |
| 203 | - @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | |
| 204 | - @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb') | |
| 205 | - | |
| 206 | - assert @dummy.avatar = @file | |
| 207 | - assert @dummy.valid? | |
| 208 | - assert @dummy.save | |
| 209 | - end | |
| 210 | - | |
| 211 | - should "write and delete its files" do | |
| 212 | - [["434x66", :original], | |
| 213 | - ["300x46", :large], | |
| 214 | - ["100x15", :medium], | |
| 215 | - ["32x32", :thumb]].each do |geo, style| | |
| 216 | - cmd = %Q[identify -format "%wx%h" "#{@dummy.avatar.path(style)}"] | |
| 217 | - assert_equal geo, `#{cmd}`.chomp, cmd | |
| 218 | - end | |
| 219 | - | |
| 220 | - saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) } | |
| 221 | - | |
| 222 | - @d2 = Dummy.find(@dummy.id) | |
| 223 | - assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path}"`.chomp | |
| 224 | - assert_equal "434x66", `identify -format "%wx%h" "#{@d2.avatar.path(:original)}"`.chomp | |
| 225 | - assert_equal "300x46", `identify -format "%wx%h" "#{@d2.avatar.path(:large)}"`.chomp | |
| 226 | - assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp | |
| 227 | - assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp | |
| 228 | - | |
| 229 | - @dummy.avatar = "not a valid file but not nil" | |
| 230 | - assert_equal File.basename(@file.path), @dummy.avatar_file_name | |
| 231 | - assert @dummy.valid? | |
| 232 | - assert @dummy.save | |
| 233 | - | |
| 234 | - saved_paths.each do |p| | |
| 235 | - assert File.exists?(p) | |
| 236 | - end | |
| 237 | - | |
| 238 | - @dummy.avatar.clear | |
| 239 | - assert_nil @dummy.avatar_file_name | |
| 240 | - assert @dummy.valid? | |
| 241 | - assert @dummy.save | |
| 242 | - | |
| 243 | - saved_paths.each do |p| | |
| 244 | - assert ! File.exists?(p) | |
| 245 | - end | |
| 246 | - | |
| 247 | - @d2 = Dummy.find(@dummy.id) | |
| 248 | - assert_nil @d2.avatar_file_name | |
| 249 | - end | |
| 250 | - | |
| 251 | - should "work exactly the same when new as when reloaded" do | |
| 252 | - @d2 = Dummy.find(@dummy.id) | |
| 253 | - | |
| 254 | - assert_equal @dummy.avatar_file_name, @d2.avatar_file_name | |
| 255 | - [:thumb, :medium, :large, :original].each do |style| | |
| 256 | - assert_equal @dummy.avatar.path(style), @d2.avatar.path(style) | |
| 257 | - end | |
| 258 | - | |
| 259 | - saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) } | |
| 260 | - | |
| 261 | - @d2.avatar.clear | |
| 262 | - assert @d2.save | |
| 263 | - | |
| 264 | - saved_paths.each do |p| | |
| 265 | - assert ! File.exists?(p) | |
| 266 | - end | |
| 267 | - end | |
| 268 | - | |
| 269 | - should "know the difference between good files, bad files, and not files" do | |
| 270 | - expected = @dummy.avatar.to_file | |
| 271 | - @dummy.avatar = "not a file" | |
| 272 | - assert @dummy.valid? | |
| 273 | - assert_equal expected.path, @dummy.avatar.path | |
| 274 | - expected.close | |
| 275 | - | |
| 276 | - @dummy.avatar = @bad_file | |
| 277 | - assert ! @dummy.valid? | |
| 278 | - end | |
| 279 | - | |
| 280 | - should "know the difference between good files, bad files, and not files when validating" do | |
| 281 | - Dummy.validates_attachment_presence :avatar | |
| 282 | - @d2 = Dummy.find(@dummy.id) | |
| 283 | - @d2.avatar = @file | |
| 284 | - assert @d2.valid?, @d2.errors.full_messages.inspect | |
| 285 | - @d2.avatar = @bad_file | |
| 286 | - assert ! @d2.valid? | |
| 287 | - end | |
| 288 | - | |
| 289 | - should "be able to reload without saving and not have the file disappear" do | |
| 290 | - @dummy.avatar = @file | |
| 291 | - assert @dummy.save | |
| 292 | - @dummy.avatar.clear | |
| 293 | - assert_nil @dummy.avatar_file_name | |
| 294 | - @dummy.reload | |
| 295 | - assert_equal "5k.png", @dummy.avatar_file_name | |
| 296 | - end | |
| 297 | - | |
| 298 | - context "that is assigned its file from another Paperclip attachment" do | |
| 299 | - setup do | |
| 300 | - @dummy2 = Dummy.new | |
| 301 | - @file2 = File.new(File.join(FIXTURES_DIR, "12k.png"), 'rb') | |
| 302 | - assert @dummy2.avatar = @file2 | |
| 303 | - @dummy2.save | |
| 304 | - end | |
| 305 | - | |
| 306 | - should "work when assigned a file" do | |
| 307 | - assert_not_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`, | |
| 308 | - `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"` | |
| 309 | - | |
| 310 | - assert @dummy.avatar = @dummy2.avatar | |
| 311 | - @dummy.save | |
| 312 | - assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`, | |
| 313 | - `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"` | |
| 314 | - end | |
| 315 | - end | |
| 316 | - | |
| 317 | - end | |
| 318 | - | |
| 319 | - context "A model with an attachments association and a Paperclip attachment" do | |
| 320 | - setup do | |
| 321 | - Dummy.class_eval do | |
| 322 | - has_many :attachments, :class_name => 'Dummy' | |
| 323 | - end | |
| 324 | - | |
| 325 | - @dummy = Dummy.new | |
| 326 | - @dummy.avatar = File.new(File.join(File.dirname(__FILE__), | |
| 327 | - "fixtures", | |
| 328 | - "5k.png"), 'rb') | |
| 329 | - end | |
| 330 | - | |
| 331 | - should "should not error when saving" do | |
| 332 | - assert_nothing_raised do | |
| 333 | - @dummy.save! | |
| 334 | - end | |
| 335 | - end | |
| 336 | - end | |
| 337 | - | |
| 338 | - if ENV['S3_TEST_BUCKET'] | |
| 339 | - def s3_files_for attachment | |
| 340 | - [:thumb, :medium, :large, :original].inject({}) do |files, style| | |
| 341 | - data = `curl "#{attachment.url(style)}" 2>/dev/null`.chomp | |
| 342 | - t = Tempfile.new("paperclip-test") | |
| 343 | - t.binmode | |
| 344 | - t.write(data) | |
| 345 | - t.rewind | |
| 346 | - files[style] = t | |
| 347 | - files | |
| 348 | - end | |
| 349 | - end | |
| 350 | - | |
| 351 | - def s3_headers_for attachment, style | |
| 352 | - `curl --head "#{attachment.url(style)}" 2>/dev/null`.split("\n").inject({}) do |h,head| | |
| 353 | - split_head = head.chomp.split(/\s*:\s*/, 2) | |
| 354 | - h[split_head.first.downcase] = split_head.last unless split_head.empty? | |
| 355 | - h | |
| 356 | - end | |
| 357 | - end | |
| 358 | - | |
| 359 | - context "A model with an S3 attachment" do | |
| 360 | - setup do | |
| 361 | - rebuild_model :styles => { :large => "300x300>", | |
| 362 | - :medium => "100x100", | |
| 363 | - :thumb => ["32x32#", :gif] }, | |
| 364 | - :storage => :s3, | |
| 365 | - :whiny_thumbnails => true, | |
| 366 | - # :s3_options => {:logger => Logger.new(StringIO.new)}, | |
| 367 | - :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")), | |
| 368 | - :default_style => :medium, | |
| 369 | - :bucket => ENV['S3_TEST_BUCKET'], | |
| 370 | - :path => ":class/:attachment/:id/:style/:basename.:extension" | |
| 371 | - @dummy = Dummy.new | |
| 372 | - @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | |
| 373 | - @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb') | |
| 374 | - | |
| 375 | - assert @dummy.avatar = @file | |
| 376 | - assert @dummy.valid? | |
| 377 | - assert @dummy.save | |
| 378 | - | |
| 379 | - @files_on_s3 = s3_files_for @dummy.avatar | |
| 380 | - end | |
| 381 | - | |
| 382 | - should "write and delete its files" do | |
| 383 | - [["434x66", :original], | |
| 384 | - ["300x46", :large], | |
| 385 | - ["100x15", :medium], | |
| 386 | - ["32x32", :thumb]].each do |geo, style| | |
| 387 | - cmd = %Q[identify -format "%wx%h" "#{@files_on_s3[style].path}"] | |
| 388 | - assert_equal geo, `#{cmd}`.chomp, cmd | |
| 389 | - end | |
| 390 | - | |
| 391 | - @d2 = Dummy.find(@dummy.id) | |
| 392 | - @d2_files = s3_files_for @d2.avatar | |
| 393 | - [["434x66", :original], | |
| 394 | - ["300x46", :large], | |
| 395 | - ["100x15", :medium], | |
| 396 | - ["32x32", :thumb]].each do |geo, style| | |
| 397 | - cmd = %Q[identify -format "%wx%h" "#{@d2_files[style].path}"] | |
| 398 | - assert_equal geo, `#{cmd}`.chomp, cmd | |
| 399 | - end | |
| 400 | - | |
| 401 | - @dummy.avatar = "not a valid file but not nil" | |
| 402 | - assert_equal File.basename(@file.path), @dummy.avatar_file_name | |
| 403 | - assert @dummy.valid? | |
| 404 | - assert @dummy.save | |
| 405 | - | |
| 406 | - saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) } | |
| 407 | - | |
| 408 | - saved_keys.each do |key| | |
| 409 | - assert key.exists? | |
| 410 | - end | |
| 411 | - | |
| 412 | - @dummy.avatar.clear | |
| 413 | - assert_nil @dummy.avatar_file_name | |
| 414 | - assert @dummy.valid? | |
| 415 | - assert @dummy.save | |
| 416 | - | |
| 417 | - saved_keys.each do |key| | |
| 418 | - assert ! key.exists? | |
| 419 | - end | |
| 420 | - | |
| 421 | - @d2 = Dummy.find(@dummy.id) | |
| 422 | - assert_nil @d2.avatar_file_name | |
| 423 | - end | |
| 424 | - | |
| 425 | - should "work exactly the same when new as when reloaded" do | |
| 426 | - @d2 = Dummy.find(@dummy.id) | |
| 427 | - | |
| 428 | - assert_equal @dummy.avatar_file_name, @d2.avatar_file_name | |
| 429 | - [:thumb, :medium, :large, :original].each do |style| | |
| 430 | - assert_equal @dummy.avatar.to_file(style).to_s, @d2.avatar.to_file(style).to_s | |
| 431 | - end | |
| 432 | - | |
| 433 | - saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) } | |
| 434 | - | |
| 435 | - @d2.avatar.clear | |
| 436 | - assert @d2.save | |
| 437 | - | |
| 438 | - saved_keys.each do |key| | |
| 439 | - assert ! key.exists? | |
| 440 | - end | |
| 441 | - end | |
| 442 | - | |
| 443 | - should "know the difference between good files, bad files, not files, and nil" do | |
| 444 | - expected = @dummy.avatar.to_file | |
| 445 | - @dummy.avatar = "not a file" | |
| 446 | - assert @dummy.valid? | |
| 447 | - assert_equal expected.full_name, @dummy.avatar.to_file.full_name | |
| 448 | - | |
| 449 | - @dummy.avatar = @bad_file | |
| 450 | - assert ! @dummy.valid? | |
| 451 | - @dummy.avatar = nil | |
| 452 | - assert @dummy.valid? | |
| 453 | - | |
| 454 | - Dummy.validates_attachment_presence :avatar | |
| 455 | - @d2 = Dummy.find(@dummy.id) | |
| 456 | - @d2.avatar = @file | |
| 457 | - assert @d2.valid? | |
| 458 | - @d2.avatar = @bad_file | |
| 459 | - assert ! @d2.valid? | |
| 460 | - @d2.avatar = nil | |
| 461 | - assert ! @d2.valid? | |
| 462 | - end | |
| 463 | - | |
| 464 | - should "be able to reload without saving and not have the file disappear" do | |
| 465 | - @dummy.avatar = @file | |
| 466 | - assert @dummy.save | |
| 467 | - @dummy.avatar = nil | |
| 468 | - assert_nil @dummy.avatar_file_name | |
| 469 | - @dummy.reload | |
| 470 | - assert_equal "5k.png", @dummy.avatar_file_name | |
| 471 | - end | |
| 472 | - | |
| 473 | - should "have the right content type" do | |
| 474 | - headers = s3_headers_for(@dummy.avatar, :original) | |
| 475 | - p headers | |
| 476 | - assert_equal 'image/png', headers['content-type'] | |
| 477 | - end | |
| 478 | - end | |
| 479 | - end | |
| 480 | -end | |
| 481 | - |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/interpolations_test.rb
| ... | ... | @@ -1,120 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class InterpolationsTest < Test::Unit::TestCase | |
| 4 | - should "return all methods but the infrastructure when sent #all" do | |
| 5 | - methods = Paperclip::Interpolations.all | |
| 6 | - assert ! methods.include?(:[]) | |
| 7 | - assert ! methods.include?(:[]=) | |
| 8 | - assert ! methods.include?(:all) | |
| 9 | - methods.each do |m| | |
| 10 | - assert Paperclip::Interpolations.respond_to? m | |
| 11 | - end | |
| 12 | - end | |
| 13 | - | |
| 14 | - should "return the RAILS_ROOT" do | |
| 15 | - assert_equal RAILS_ROOT, Paperclip::Interpolations.rails_root(:attachment, :style) | |
| 16 | - end | |
| 17 | - | |
| 18 | - should "return the RAILS_ENV" do | |
| 19 | - assert_equal RAILS_ENV, Paperclip::Interpolations.rails_env(:attachment, :style) | |
| 20 | - end | |
| 21 | - | |
| 22 | - should "return the class of the instance" do | |
| 23 | - attachment = mock | |
| 24 | - attachment.expects(:instance).returns(attachment) | |
| 25 | - attachment.expects(:class).returns("Thing") | |
| 26 | - assert_equal "things", Paperclip::Interpolations.class(attachment, :style) | |
| 27 | - end | |
| 28 | - | |
| 29 | - should "return the basename of the file" do | |
| 30 | - attachment = mock | |
| 31 | - attachment.expects(:original_filename).returns("one.jpg").times(2) | |
| 32 | - assert_equal "one", Paperclip::Interpolations.basename(attachment, :style) | |
| 33 | - end | |
| 34 | - | |
| 35 | - should "return the extension of the file" do | |
| 36 | - attachment = mock | |
| 37 | - attachment.expects(:original_filename).returns("one.jpg") | |
| 38 | - attachment.expects(:styles).returns({}) | |
| 39 | - assert_equal "jpg", Paperclip::Interpolations.extension(attachment, :style) | |
| 40 | - end | |
| 41 | - | |
| 42 | - should "return the extension of the file as the format if defined in the style" do | |
| 43 | - attachment = mock | |
| 44 | - attachment.expects(:original_filename).never | |
| 45 | - attachment.expects(:styles).returns({:style => {:format => "png"}}) | |
| 46 | - assert_equal "png", Paperclip::Interpolations.extension(attachment, :style) | |
| 47 | - end | |
| 48 | - | |
| 49 | - should "return the id of the attachment" do | |
| 50 | - attachment = mock | |
| 51 | - attachment.expects(:id).returns(23) | |
| 52 | - attachment.expects(:instance).returns(attachment) | |
| 53 | - assert_equal 23, Paperclip::Interpolations.id(attachment, :style) | |
| 54 | - end | |
| 55 | - | |
| 56 | - should "return the partitioned id of the attachment" do | |
| 57 | - attachment = mock | |
| 58 | - attachment.expects(:id).returns(23) | |
| 59 | - attachment.expects(:instance).returns(attachment) | |
| 60 | - assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style) | |
| 61 | - end | |
| 62 | - | |
| 63 | - should "return the name of the attachment" do | |
| 64 | - attachment = mock | |
| 65 | - attachment.expects(:name).returns("file") | |
| 66 | - assert_equal "files", Paperclip::Interpolations.attachment(attachment, :style) | |
| 67 | - end | |
| 68 | - | |
| 69 | - should "return the style" do | |
| 70 | - assert_equal :style, Paperclip::Interpolations.style(:attachment, :style) | |
| 71 | - end | |
| 72 | - | |
| 73 | - should "return the default style" do | |
| 74 | - attachment = mock | |
| 75 | - attachment.expects(:default_style).returns(:default_style) | |
| 76 | - assert_equal :default_style, Paperclip::Interpolations.style(attachment, nil) | |
| 77 | - end | |
| 78 | - | |
| 79 | - should "reinterpolate :url" do | |
| 80 | - attachment = mock | |
| 81 | - attachment.expects(:options).returns({:url => ":id"}) | |
| 82 | - attachment.expects(:url).with(:style, false).returns("1234") | |
| 83 | - assert_equal "1234", Paperclip::Interpolations.url(attachment, :style) | |
| 84 | - end | |
| 85 | - | |
| 86 | - should "raise if infinite loop detcted reinterpolating :url" do | |
| 87 | - attachment = mock | |
| 88 | - attachment.expects(:options).returns({:url => ":url"}) | |
| 89 | - assert_raises(Paperclip::InfiniteInterpolationError){ Paperclip::Interpolations.url(attachment, :style) } | |
| 90 | - end | |
| 91 | - | |
| 92 | - should "return the filename as basename.extension" do | |
| 93 | - attachment = mock | |
| 94 | - attachment.expects(:styles).returns({}) | |
| 95 | - attachment.expects(:original_filename).returns("one.jpg").times(3) | |
| 96 | - assert_equal "one.jpg", Paperclip::Interpolations.filename(attachment, :style) | |
| 97 | - end | |
| 98 | - | |
| 99 | - should "return the filename as basename.extension when format supplied" do | |
| 100 | - attachment = mock | |
| 101 | - attachment.expects(:styles).returns({:style => {:format => :png}}) | |
| 102 | - attachment.expects(:original_filename).returns("one.jpg").times(2) | |
| 103 | - assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style) | |
| 104 | - end | |
| 105 | - | |
| 106 | - should "return the timestamp" do | |
| 107 | - now = Time.now | |
| 108 | - attachment = mock | |
| 109 | - attachment.expects(:instance_read).with(:updated_at).returns(now) | |
| 110 | - assert_equal now.to_s, Paperclip::Interpolations.timestamp(attachment, :style) | |
| 111 | - end | |
| 112 | - | |
| 113 | - should "call all expected interpolations with the given arguments" do | |
| 114 | - Paperclip::Interpolations.expects(:id).with(:attachment, :style).returns(1234) | |
| 115 | - Paperclip::Interpolations.expects(:attachment).with(:attachment, :style).returns("attachments") | |
| 116 | - Paperclip::Interpolations.expects(:notreal).never | |
| 117 | - value = Paperclip::Interpolations.interpolate(":notreal/:id/:attachment", :attachment, :style) | |
| 118 | - assert_equal ":notreal/1234/attachments", value | |
| 119 | - end | |
| 120 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/iostream_test.rb
| ... | ... | @@ -1,71 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class IOStreamTest < Test::Unit::TestCase | |
| 4 | - context "IOStream" do | |
| 5 | - should "be included in IO, File, Tempfile, and StringIO" do | |
| 6 | - [IO, File, Tempfile, StringIO].each do |klass| | |
| 7 | - assert klass.included_modules.include?(IOStream), "Not in #{klass}" | |
| 8 | - end | |
| 9 | - end | |
| 10 | - end | |
| 11 | - | |
| 12 | - context "A file" do | |
| 13 | - setup do | |
| 14 | - @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | |
| 15 | - end | |
| 16 | - | |
| 17 | - teardown { @file.close } | |
| 18 | - | |
| 19 | - context "that is sent #stream_to" do | |
| 20 | - | |
| 21 | - context "and given a String" do | |
| 22 | - setup do | |
| 23 | - FileUtils.mkdir_p(File.join(ROOT, 'tmp')) | |
| 24 | - assert @result = @file.stream_to(File.join(ROOT, 'tmp', 'iostream.string.test')) | |
| 25 | - end | |
| 26 | - | |
| 27 | - should "return a File" do | |
| 28 | - assert @result.is_a?(File) | |
| 29 | - end | |
| 30 | - | |
| 31 | - should "contain the same data as the original file" do | |
| 32 | - @file.rewind; @result.rewind | |
| 33 | - assert_equal @file.read, @result.read | |
| 34 | - end | |
| 35 | - end | |
| 36 | - | |
| 37 | - context "and given a Tempfile" do | |
| 38 | - setup do | |
| 39 | - tempfile = Tempfile.new('iostream.test') | |
| 40 | - tempfile.binmode | |
| 41 | - assert @result = @file.stream_to(tempfile) | |
| 42 | - end | |
| 43 | - | |
| 44 | - should "return a Tempfile" do | |
| 45 | - assert @result.is_a?(Tempfile) | |
| 46 | - end | |
| 47 | - | |
| 48 | - should "contain the same data as the original file" do | |
| 49 | - @file.rewind; @result.rewind | |
| 50 | - assert_equal @file.read, @result.read | |
| 51 | - end | |
| 52 | - end | |
| 53 | - | |
| 54 | - end | |
| 55 | - | |
| 56 | - context "that is sent #to_tempfile" do | |
| 57 | - setup do | |
| 58 | - assert @tempfile = @file.to_tempfile | |
| 59 | - end | |
| 60 | - | |
| 61 | - should "convert it to a Tempfile" do | |
| 62 | - assert @tempfile.is_a?(Tempfile) | |
| 63 | - end | |
| 64 | - | |
| 65 | - should "have the Tempfile contain the same data as the file" do | |
| 66 | - @file.rewind; @tempfile.rewind | |
| 67 | - assert_equal @file.read, @tempfile.read | |
| 68 | - end | |
| 69 | - end | |
| 70 | - end | |
| 71 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/matchers/have_attached_file_matcher_test.rb
| ... | ... | @@ -1,21 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class HaveAttachedFileMatcherTest < Test::Unit::TestCase | |
| 4 | - context "have_attached_file" do | |
| 5 | - setup do | |
| 6 | - @dummy_class = reset_class "Dummy" | |
| 7 | - reset_table "dummies" | |
| 8 | - @matcher = self.class.have_attached_file(:avatar) | |
| 9 | - end | |
| 10 | - | |
| 11 | - should "reject a class with no attachment" do | |
| 12 | - assert_rejects @matcher, @dummy_class | |
| 13 | - end | |
| 14 | - | |
| 15 | - should "accept a class with an attachment" do | |
| 16 | - modify_table("dummies"){|d| d.string :avatar_file_name } | |
| 17 | - @dummy_class.has_attached_file :avatar | |
| 18 | - assert_accepts @matcher, @dummy_class | |
| 19 | - end | |
| 20 | - end | |
| 21 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/matchers/validate_attachment_content_type_matcher_test.rb
| ... | ... | @@ -1,30 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase | |
| 4 | - context "validate_attachment_content_type" do | |
| 5 | - setup do | |
| 6 | - reset_table("dummies") do |d| | |
| 7 | - d.string :avatar_file_name | |
| 8 | - end | |
| 9 | - @dummy_class = reset_class "Dummy" | |
| 10 | - @dummy_class.has_attached_file :avatar | |
| 11 | - @matcher = self.class.validate_attachment_content_type(:avatar). | |
| 12 | - allowing(%w(image/png image/jpeg)). | |
| 13 | - rejecting(%w(audio/mp3 application/octet-stream)) | |
| 14 | - end | |
| 15 | - | |
| 16 | - should "reject a class with no validation" do | |
| 17 | - assert_rejects @matcher, @dummy_class | |
| 18 | - end | |
| 19 | - | |
| 20 | - should "reject a class with a validation that doesn't match" do | |
| 21 | - @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*} | |
| 22 | - assert_rejects @matcher, @dummy_class | |
| 23 | - end | |
| 24 | - | |
| 25 | - should "accept a class with a validation" do | |
| 26 | - @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*} | |
| 27 | - assert_accepts @matcher, @dummy_class | |
| 28 | - end | |
| 29 | - end | |
| 30 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/matchers/validate_attachment_presence_matcher_test.rb
| ... | ... | @@ -1,21 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase | |
| 4 | - context "validate_attachment_presence" do | |
| 5 | - setup do | |
| 6 | - reset_table("dummies"){|d| d.string :avatar_file_name } | |
| 7 | - @dummy_class = reset_class "Dummy" | |
| 8 | - @dummy_class.has_attached_file :avatar | |
| 9 | - @matcher = self.class.validate_attachment_presence(:avatar) | |
| 10 | - end | |
| 11 | - | |
| 12 | - should "reject a class with no validation" do | |
| 13 | - assert_rejects @matcher, @dummy_class | |
| 14 | - end | |
| 15 | - | |
| 16 | - should "accept a class with a validation" do | |
| 17 | - @dummy_class.validates_attachment_presence :avatar | |
| 18 | - assert_accepts @matcher, @dummy_class | |
| 19 | - end | |
| 20 | - end | |
| 21 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/matchers/validate_attachment_size_matcher_test.rb
| ... | ... | @@ -1,50 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase | |
| 4 | - context "validate_attachment_size" do | |
| 5 | - setup do | |
| 6 | - reset_table("dummies") do |d| | |
| 7 | - d.string :avatar_file_name | |
| 8 | - end | |
| 9 | - @dummy_class = reset_class "Dummy" | |
| 10 | - @dummy_class.has_attached_file :avatar | |
| 11 | - end | |
| 12 | - | |
| 13 | - context "of limited size" do | |
| 14 | - setup{ @matcher = self.class.validate_attachment_size(:avatar).in(256..1024) } | |
| 15 | - | |
| 16 | - should "reject a class with no validation" do | |
| 17 | - assert_rejects @matcher, @dummy_class | |
| 18 | - end | |
| 19 | - | |
| 20 | - should "reject a class with a validation that's too high" do | |
| 21 | - @dummy_class.validates_attachment_size :avatar, :in => 256..2048 | |
| 22 | - assert_rejects @matcher, @dummy_class | |
| 23 | - end | |
| 24 | - | |
| 25 | - should "reject a class with a validation that's too low" do | |
| 26 | - @dummy_class.validates_attachment_size :avatar, :in => 0..1024 | |
| 27 | - assert_rejects @matcher, @dummy_class | |
| 28 | - end | |
| 29 | - | |
| 30 | - should "accept a class with a validation that matches" do | |
| 31 | - @dummy_class.validates_attachment_size :avatar, :in => 256..1024 | |
| 32 | - assert_accepts @matcher, @dummy_class | |
| 33 | - end | |
| 34 | - end | |
| 35 | - | |
| 36 | - context "validates_attachment_size with infinite range" do | |
| 37 | - setup{ @matcher = self.class.validate_attachment_size(:avatar) } | |
| 38 | - | |
| 39 | - should "accept a class with an upper limit" do | |
| 40 | - @dummy_class.validates_attachment_size :avatar, :less_than => 1 | |
| 41 | - assert_accepts @matcher, @dummy_class | |
| 42 | - end | |
| 43 | - | |
| 44 | - should "accept a class with no upper limit" do | |
| 45 | - @dummy_class.validates_attachment_size :avatar, :greater_than => 1 | |
| 46 | - assert_accepts @matcher, @dummy_class | |
| 47 | - end | |
| 48 | - end | |
| 49 | - end | |
| 50 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/paperclip_test.rb
| ... | ... | @@ -1,291 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class PaperclipTest < Test::Unit::TestCase | |
| 4 | - [:image_magick_path, :convert_path].each do |path| | |
| 5 | - context "Calling Paperclip.run with an #{path} specified" do | |
| 6 | - setup do | |
| 7 | - Paperclip.options[:image_magick_path] = nil | |
| 8 | - Paperclip.options[:convert_path] = nil | |
| 9 | - Paperclip.options[path] = "/usr/bin" | |
| 10 | - end | |
| 11 | - | |
| 12 | - should "execute the right command" do | |
| 13 | - Paperclip.expects(:path_for_command).with("convert").returns("/usr/bin/convert") | |
| 14 | - Paperclip.expects(:bit_bucket).returns("/dev/null") | |
| 15 | - Paperclip.expects(:"`").with("/usr/bin/convert one.jpg two.jpg 2>/dev/null") | |
| 16 | - Paperclip.run("convert", "one.jpg two.jpg") | |
| 17 | - end | |
| 18 | - end | |
| 19 | - end | |
| 20 | - | |
| 21 | - context "Calling Paperclip.run with no path specified" do | |
| 22 | - setup do | |
| 23 | - Paperclip.options[:image_magick_path] = nil | |
| 24 | - Paperclip.options[:convert_path] = nil | |
| 25 | - end | |
| 26 | - | |
| 27 | - should "execute the right command" do | |
| 28 | - Paperclip.expects(:path_for_command).with("convert").returns("convert") | |
| 29 | - Paperclip.expects(:bit_bucket).returns("/dev/null") | |
| 30 | - Paperclip.expects(:"`").with("convert one.jpg two.jpg 2>/dev/null") | |
| 31 | - Paperclip.run("convert", "one.jpg two.jpg") | |
| 32 | - end | |
| 33 | - | |
| 34 | - should "log the command when :log_command is set" do | |
| 35 | - Paperclip.options[:log_command] = true | |
| 36 | - Paperclip.expects(:bit_bucket).returns("/dev/null") | |
| 37 | - Paperclip.expects(:log).with("this is the command 2>/dev/null") | |
| 38 | - Paperclip.expects(:"`").with("this is the command 2>/dev/null") | |
| 39 | - Paperclip.run("this","is the command") | |
| 40 | - end | |
| 41 | - end | |
| 42 | - | |
| 43 | - should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do | |
| 44 | - assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) } | |
| 45 | - end | |
| 46 | - | |
| 47 | - should "raise when sent #processor and the name of a class that doesn't exist" do | |
| 48 | - assert_raises(NameError){ Paperclip.processor(:boogey_man) } | |
| 49 | - end | |
| 50 | - | |
| 51 | - should "return a class when sent #processor and the name of a class under Paperclip" do | |
| 52 | - assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail) | |
| 53 | - end | |
| 54 | - | |
| 55 | - should "call a proc sent to check_guard" do | |
| 56 | - @dummy = Dummy.new | |
| 57 | - @dummy.expects(:one).returns(:one) | |
| 58 | - assert_equal :one, @dummy.avatar.send(:check_guard, lambda{|x| x.one }) | |
| 59 | - end | |
| 60 | - | |
| 61 | - should "call a method name sent to check_guard" do | |
| 62 | - @dummy = Dummy.new | |
| 63 | - @dummy.expects(:one).returns(:one) | |
| 64 | - assert_equal :one, @dummy.avatar.send(:check_guard, :one) | |
| 65 | - end | |
| 66 | - | |
| 67 | - context "Paperclip.bit_bucket" do | |
| 68 | - context "on systems without /dev/null" do | |
| 69 | - setup do | |
| 70 | - File.expects(:exists?).with("/dev/null").returns(false) | |
| 71 | - end | |
| 72 | - | |
| 73 | - should "return 'NUL'" do | |
| 74 | - assert_equal "NUL", Paperclip.bit_bucket | |
| 75 | - end | |
| 76 | - end | |
| 77 | - | |
| 78 | - context "on systems with /dev/null" do | |
| 79 | - setup do | |
| 80 | - File.expects(:exists?).with("/dev/null").returns(true) | |
| 81 | - end | |
| 82 | - | |
| 83 | - should "return '/dev/null'" do | |
| 84 | - assert_equal "/dev/null", Paperclip.bit_bucket | |
| 85 | - end | |
| 86 | - end | |
| 87 | - end | |
| 88 | - | |
| 89 | - context "An ActiveRecord model with an 'avatar' attachment" do | |
| 90 | - setup do | |
| 91 | - rebuild_model :path => "tmp/:class/omg/:style.:extension" | |
| 92 | - @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | |
| 93 | - end | |
| 94 | - | |
| 95 | - teardown { @file.close } | |
| 96 | - | |
| 97 | - should "not error when trying to also create a 'blah' attachment" do | |
| 98 | - assert_nothing_raised do | |
| 99 | - Dummy.class_eval do | |
| 100 | - has_attached_file :blah | |
| 101 | - end | |
| 102 | - end | |
| 103 | - end | |
| 104 | - | |
| 105 | - context "that is attr_protected" do | |
| 106 | - setup do | |
| 107 | - Dummy.class_eval do | |
| 108 | - attr_protected :avatar | |
| 109 | - end | |
| 110 | - @dummy = Dummy.new | |
| 111 | - end | |
| 112 | - | |
| 113 | - should "not assign the avatar on mass-set" do | |
| 114 | - @dummy.attributes = { :other => "I'm set!", | |
| 115 | - :avatar => @file } | |
| 116 | - | |
| 117 | - assert_equal "I'm set!", @dummy.other | |
| 118 | - assert ! @dummy.avatar? | |
| 119 | - end | |
| 120 | - | |
| 121 | - should "still allow assigment on normal set" do | |
| 122 | - @dummy.other = "I'm set!" | |
| 123 | - @dummy.avatar = @file | |
| 124 | - | |
| 125 | - assert_equal "I'm set!", @dummy.other | |
| 126 | - assert @dummy.avatar? | |
| 127 | - end | |
| 128 | - end | |
| 129 | - | |
| 130 | - context "with a subclass" do | |
| 131 | - setup do | |
| 132 | - class ::SubDummy < Dummy; end | |
| 133 | - end | |
| 134 | - | |
| 135 | - should "be able to use the attachment from the subclass" do | |
| 136 | - assert_nothing_raised do | |
| 137 | - @subdummy = SubDummy.create(:avatar => @file) | |
| 138 | - end | |
| 139 | - end | |
| 140 | - | |
| 141 | - should "be able to see the attachment definition from the subclass's class" do | |
| 142 | - assert_equal "tmp/:class/omg/:style.:extension", SubDummy.attachment_definitions[:avatar][:path] | |
| 143 | - end | |
| 144 | - | |
| 145 | - teardown do | |
| 146 | - Object.send(:remove_const, "SubDummy") rescue nil | |
| 147 | - end | |
| 148 | - end | |
| 149 | - | |
| 150 | - should "have an #avatar method" do | |
| 151 | - assert Dummy.new.respond_to?(:avatar) | |
| 152 | - end | |
| 153 | - | |
| 154 | - should "have an #avatar= method" do | |
| 155 | - assert Dummy.new.respond_to?(:avatar=) | |
| 156 | - end | |
| 157 | - | |
| 158 | - context "that is valid" do | |
| 159 | - setup do | |
| 160 | - @dummy = Dummy.new | |
| 161 | - @dummy.avatar = @file | |
| 162 | - end | |
| 163 | - | |
| 164 | - should "be valid" do | |
| 165 | - assert @dummy.valid? | |
| 166 | - end | |
| 167 | - | |
| 168 | - context "then has a validation added that makes it invalid" do | |
| 169 | - setup do | |
| 170 | - assert @dummy.save | |
| 171 | - Dummy.class_eval do | |
| 172 | - validates_attachment_content_type :avatar, :content_type => ["text/plain"] | |
| 173 | - end | |
| 174 | - @dummy2 = Dummy.find(@dummy.id) | |
| 175 | - end | |
| 176 | - | |
| 177 | - should "be invalid when reloaded" do | |
| 178 | - assert ! @dummy2.valid?, @dummy2.errors.inspect | |
| 179 | - end | |
| 180 | - | |
| 181 | - should "be able to call #valid? twice without having duplicate errors" do | |
| 182 | - @dummy2.avatar.valid? | |
| 183 | - first_errors = @dummy2.avatar.errors | |
| 184 | - @dummy2.avatar.valid? | |
| 185 | - assert_equal first_errors, @dummy2.avatar.errors | |
| 186 | - end | |
| 187 | - end | |
| 188 | - end | |
| 189 | - | |
| 190 | - context "a validation with an if guard clause" do | |
| 191 | - setup do | |
| 192 | - Dummy.send(:"validates_attachment_presence", :avatar, :if => lambda{|i| i.foo }) | |
| 193 | - @dummy = Dummy.new | |
| 194 | - end | |
| 195 | - | |
| 196 | - should "attempt validation if the guard returns true" do | |
| 197 | - @dummy.expects(:foo).returns(true) | |
| 198 | - @dummy.avatar.expects(:validate_presence).returns(nil) | |
| 199 | - @dummy.valid? | |
| 200 | - end | |
| 201 | - | |
| 202 | - should "not attempt validation if the guard returns false" do | |
| 203 | - @dummy.expects(:foo).returns(false) | |
| 204 | - @dummy.avatar.expects(:validate_presence).never | |
| 205 | - @dummy.valid? | |
| 206 | - end | |
| 207 | - end | |
| 208 | - | |
| 209 | - context "a validation with an unless guard clause" do | |
| 210 | - setup do | |
| 211 | - Dummy.send(:"validates_attachment_presence", :avatar, :unless => lambda{|i| i.foo }) | |
| 212 | - @dummy = Dummy.new | |
| 213 | - end | |
| 214 | - | |
| 215 | - should "attempt validation if the guard returns true" do | |
| 216 | - @dummy.expects(:foo).returns(false) | |
| 217 | - @dummy.avatar.expects(:validate_presence).returns(nil) | |
| 218 | - @dummy.valid? | |
| 219 | - end | |
| 220 | - | |
| 221 | - should "not attempt validation if the guard returns false" do | |
| 222 | - @dummy.expects(:foo).returns(true) | |
| 223 | - @dummy.avatar.expects(:validate_presence).never | |
| 224 | - @dummy.valid? | |
| 225 | - end | |
| 226 | - end | |
| 227 | - | |
| 228 | - def self.should_validate validation, options, valid_file, invalid_file | |
| 229 | - context "with #{validation} validation and #{options.inspect} options" do | |
| 230 | - setup do | |
| 231 | - Dummy.send(:"validates_attachment_#{validation}", :avatar, options) | |
| 232 | - @dummy = Dummy.new | |
| 233 | - end | |
| 234 | - context "and assigning nil" do | |
| 235 | - setup do | |
| 236 | - @dummy.avatar = nil | |
| 237 | - @dummy.valid? | |
| 238 | - end | |
| 239 | - if validation == :presence | |
| 240 | - should "have an error on the attachment" do | |
| 241 | - assert @dummy.errors.on(:avatar) | |
| 242 | - end | |
| 243 | - else | |
| 244 | - should "not have an error on the attachment" do | |
| 245 | - assert_nil @dummy.errors.on(:avatar) | |
| 246 | - end | |
| 247 | - end | |
| 248 | - end | |
| 249 | - context "and assigned a valid file" do | |
| 250 | - setup do | |
| 251 | - @dummy.avatar = valid_file | |
| 252 | - @dummy.valid? | |
| 253 | - end | |
| 254 | - should "not have an error when assigned a valid file" do | |
| 255 | - assert ! @dummy.avatar.errors.key?(validation) | |
| 256 | - end | |
| 257 | - should "not have an error on the attachment" do | |
| 258 | - assert_nil @dummy.errors.on(:avatar) | |
| 259 | - end | |
| 260 | - end | |
| 261 | - context "and assigned an invalid file" do | |
| 262 | - setup do | |
| 263 | - @dummy.avatar = invalid_file | |
| 264 | - @dummy.valid? | |
| 265 | - end | |
| 266 | - should "have an error when assigned a valid file" do | |
| 267 | - assert_not_nil @dummy.avatar.errors[validation] | |
| 268 | - end | |
| 269 | - should "have an error on the attachment" do | |
| 270 | - assert @dummy.errors.on(:avatar) | |
| 271 | - end | |
| 272 | - end | |
| 273 | - end | |
| 274 | - end | |
| 275 | - | |
| 276 | - [[:presence, {}, "5k.png", nil], | |
| 277 | - [:size, {:in => 1..10240}, nil, "12k.png"], | |
| 278 | - [:size, {:less_than => 10240}, "5k.png", "12k.png"], | |
| 279 | - [:size, {:greater_than => 8096}, "12k.png", "5k.png"], | |
| 280 | - [:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"], | |
| 281 | - [:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"], | |
| 282 | - [:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args| | |
| 283 | - validation, options, valid_file, invalid_file = args | |
| 284 | - valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb") | |
| 285 | - invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb") | |
| 286 | - | |
| 287 | - should_validate validation, options, valid_file, invalid_file | |
| 288 | - end | |
| 289 | - | |
| 290 | - end | |
| 291 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/processor_test.rb
| ... | ... | @@ -1,10 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class ProcessorTest < Test::Unit::TestCase | |
| 4 | - should "instantiate and call #make when sent #make to the class" do | |
| 5 | - processor = mock | |
| 6 | - processor.expects(:make).with() | |
| 7 | - Paperclip::Processor.expects(:new).with(:one, :two, :three).returns(processor) | |
| 8 | - Paperclip::Processor.make(:one, :two, :three) | |
| 9 | - end | |
| 10 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/storage_test.rb
| ... | ... | @@ -1,282 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class StorageTest < Test::Unit::TestCase | |
| 4 | - context "Parsing S3 credentials" do | |
| 5 | - setup do | |
| 6 | - rebuild_model :storage => :s3, | |
| 7 | - :bucket => "testing", | |
| 8 | - :s3_credentials => {:not => :important} | |
| 9 | - | |
| 10 | - @dummy = Dummy.new | |
| 11 | - @avatar = @dummy.avatar | |
| 12 | - | |
| 13 | - @current_env = RAILS_ENV | |
| 14 | - end | |
| 15 | - | |
| 16 | - teardown do | |
| 17 | - Object.const_set("RAILS_ENV", @current_env) | |
| 18 | - end | |
| 19 | - | |
| 20 | - should "get the correct credentials when RAILS_ENV is production" do | |
| 21 | - Object.const_set('RAILS_ENV', "production") | |
| 22 | - assert_equal({:key => "12345"}, | |
| 23 | - @avatar.parse_credentials('production' => {:key => '12345'}, | |
| 24 | - :development => {:key => "54321"})) | |
| 25 | - end | |
| 26 | - | |
| 27 | - should "get the correct credentials when RAILS_ENV is development" do | |
| 28 | - Object.const_set('RAILS_ENV', "development") | |
| 29 | - assert_equal({:key => "54321"}, | |
| 30 | - @avatar.parse_credentials('production' => {:key => '12345'}, | |
| 31 | - :development => {:key => "54321"})) | |
| 32 | - end | |
| 33 | - | |
| 34 | - should "return the argument if the key does not exist" do | |
| 35 | - Object.const_set('RAILS_ENV', "not really an env") | |
| 36 | - assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345")) | |
| 37 | - end | |
| 38 | - end | |
| 39 | - | |
| 40 | - context "" do | |
| 41 | - setup do | |
| 42 | - rebuild_model :storage => :s3, | |
| 43 | - :s3_credentials => {}, | |
| 44 | - :bucket => "bucket", | |
| 45 | - :path => ":attachment/:basename.:extension", | |
| 46 | - :url => ":s3_path_url" | |
| 47 | - @dummy = Dummy.new | |
| 48 | - @dummy.avatar = StringIO.new(".") | |
| 49 | - end | |
| 50 | - | |
| 51 | - should "return a url based on an S3 path" do | |
| 52 | - assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url | |
| 53 | - end | |
| 54 | - end | |
| 55 | - context "" do | |
| 56 | - setup do | |
| 57 | - rebuild_model :storage => :s3, | |
| 58 | - :s3_credentials => {}, | |
| 59 | - :bucket => "bucket", | |
| 60 | - :path => ":attachment/:basename.:extension", | |
| 61 | - :url => ":s3_domain_url" | |
| 62 | - @dummy = Dummy.new | |
| 63 | - @dummy.avatar = StringIO.new(".") | |
| 64 | - end | |
| 65 | - | |
| 66 | - should "return a url based on an S3 subdomain" do | |
| 67 | - assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url | |
| 68 | - end | |
| 69 | - end | |
| 70 | - context "" do | |
| 71 | - setup do | |
| 72 | - rebuild_model :storage => :s3, | |
| 73 | - :s3_credentials => { | |
| 74 | - :production => { :bucket => "prod_bucket" }, | |
| 75 | - :development => { :bucket => "dev_bucket" } | |
| 76 | - }, | |
| 77 | - :s3_host_alias => "something.something.com", | |
| 78 | - :path => ":attachment/:basename.:extension", | |
| 79 | - :url => ":s3_alias_url" | |
| 80 | - @dummy = Dummy.new | |
| 81 | - @dummy.avatar = StringIO.new(".") | |
| 82 | - end | |
| 83 | - | |
| 84 | - should "return a url based on the host_alias" do | |
| 85 | - assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url | |
| 86 | - end | |
| 87 | - end | |
| 88 | - | |
| 89 | - context "Parsing S3 credentials with a bucket in them" do | |
| 90 | - setup do | |
| 91 | - rebuild_model :storage => :s3, | |
| 92 | - :s3_credentials => { | |
| 93 | - :production => { :bucket => "prod_bucket" }, | |
| 94 | - :development => { :bucket => "dev_bucket" } | |
| 95 | - } | |
| 96 | - @dummy = Dummy.new | |
| 97 | - @old_env = RAILS_ENV | |
| 98 | - end | |
| 99 | - | |
| 100 | - teardown{ Object.const_set("RAILS_ENV", @old_env) } | |
| 101 | - | |
| 102 | - should "get the right bucket in production" do | |
| 103 | - Object.const_set("RAILS_ENV", "production") | |
| 104 | - assert_equal "prod_bucket", @dummy.avatar.bucket_name | |
| 105 | - end | |
| 106 | - | |
| 107 | - should "get the right bucket in development" do | |
| 108 | - Object.const_set("RAILS_ENV", "development") | |
| 109 | - assert_equal "dev_bucket", @dummy.avatar.bucket_name | |
| 110 | - end | |
| 111 | - end | |
| 112 | - | |
| 113 | - context "An attachment with S3 storage" do | |
| 114 | - setup do | |
| 115 | - rebuild_model :storage => :s3, | |
| 116 | - :bucket => "testing", | |
| 117 | - :path => ":attachment/:style/:basename.:extension", | |
| 118 | - :s3_credentials => { | |
| 119 | - 'access_key_id' => "12345", | |
| 120 | - 'secret_access_key' => "54321" | |
| 121 | - } | |
| 122 | - end | |
| 123 | - | |
| 124 | - should "be extended by the S3 module" do | |
| 125 | - assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3) | |
| 126 | - end | |
| 127 | - | |
| 128 | - should "not be extended by the Filesystem module" do | |
| 129 | - assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem) | |
| 130 | - end | |
| 131 | - | |
| 132 | - context "when assigned" do | |
| 133 | - setup do | |
| 134 | - @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb') | |
| 135 | - @dummy = Dummy.new | |
| 136 | - @dummy.avatar = @file | |
| 137 | - end | |
| 138 | - | |
| 139 | - teardown { @file.close } | |
| 140 | - | |
| 141 | - should "not get a bucket to get a URL" do | |
| 142 | - @dummy.avatar.expects(:s3).never | |
| 143 | - @dummy.avatar.expects(:s3_bucket).never | |
| 144 | - assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url | |
| 145 | - end | |
| 146 | - | |
| 147 | - context "and saved" do | |
| 148 | - setup do | |
| 149 | - @s3_mock = stub | |
| 150 | - @bucket_mock = stub | |
| 151 | - RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock) | |
| 152 | - @s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock) | |
| 153 | - @key_mock = stub | |
| 154 | - @bucket_mock.expects(:key).returns(@key_mock) | |
| 155 | - @key_mock.expects(:data=) | |
| 156 | - @key_mock.expects(:put).with(nil, 'public-read', 'Content-type' => 'image/png') | |
| 157 | - @dummy.save | |
| 158 | - end | |
| 159 | - | |
| 160 | - should "succeed" do | |
| 161 | - assert true | |
| 162 | - end | |
| 163 | - end | |
| 164 | - | |
| 165 | - context "and remove" do | |
| 166 | - setup do | |
| 167 | - @s3_mock = stub | |
| 168 | - @bucket_mock = stub | |
| 169 | - RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock) | |
| 170 | - @s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock) | |
| 171 | - @key_mock = stub | |
| 172 | - @bucket_mock.expects(:key).at_least(2).returns(@key_mock) | |
| 173 | - @key_mock.expects(:delete) | |
| 174 | - @dummy.destroy_attached_files | |
| 175 | - end | |
| 176 | - | |
| 177 | - should "succeed" do | |
| 178 | - assert true | |
| 179 | - end | |
| 180 | - end | |
| 181 | - end | |
| 182 | - end | |
| 183 | - | |
| 184 | - context "An attachment with S3 storage and bucket defined as a Proc" do | |
| 185 | - setup do | |
| 186 | - rebuild_model :storage => :s3, | |
| 187 | - :bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" }, | |
| 188 | - :s3_credentials => {:not => :important} | |
| 189 | - end | |
| 190 | - | |
| 191 | - should "get the right bucket name" do | |
| 192 | - assert "bucket_a", Dummy.new(:other => 'a').avatar.bucket_name | |
| 193 | - assert "bucket_b", Dummy.new(:other => 'b').avatar.bucket_name | |
| 194 | - end | |
| 195 | - end | |
| 196 | - | |
| 197 | - context "An attachment with S3 storage and specific s3 headers set" do | |
| 198 | - setup do | |
| 199 | - rebuild_model :storage => :s3, | |
| 200 | - :bucket => "testing", | |
| 201 | - :path => ":attachment/:style/:basename.:extension", | |
| 202 | - :s3_credentials => { | |
| 203 | - 'access_key_id' => "12345", | |
| 204 | - 'secret_access_key' => "54321" | |
| 205 | - }, | |
| 206 | - :s3_headers => {'Cache-Control' => 'max-age=31557600'} | |
| 207 | - end | |
| 208 | - | |
| 209 | - context "when assigned" do | |
| 210 | - setup do | |
| 211 | - @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb') | |
| 212 | - @dummy = Dummy.new | |
| 213 | - @dummy.avatar = @file | |
| 214 | - end | |
| 215 | - | |
| 216 | - teardown { @file.close } | |
| 217 | - | |
| 218 | - context "and saved" do | |
| 219 | - setup do | |
| 220 | - @s3_mock = stub | |
| 221 | - @bucket_mock = stub | |
| 222 | - RightAws::S3.expects(:new).with("12345", "54321", {}).returns(@s3_mock) | |
| 223 | - @s3_mock.expects(:bucket).with("testing", true, "public-read").returns(@bucket_mock) | |
| 224 | - @key_mock = stub | |
| 225 | - @bucket_mock.expects(:key).returns(@key_mock) | |
| 226 | - @key_mock.expects(:data=) | |
| 227 | - @key_mock.expects(:put).with(nil, | |
| 228 | - 'public-read', | |
| 229 | - 'Content-type' => 'image/png', | |
| 230 | - 'Cache-Control' => 'max-age=31557600') | |
| 231 | - @dummy.save | |
| 232 | - end | |
| 233 | - | |
| 234 | - should "succeed" do | |
| 235 | - assert true | |
| 236 | - end | |
| 237 | - end | |
| 238 | - end | |
| 239 | - end | |
| 240 | - | |
| 241 | - unless ENV["S3_TEST_BUCKET"].blank? | |
| 242 | - context "Using S3 for real, an attachment with S3 storage" do | |
| 243 | - setup do | |
| 244 | - rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" }, | |
| 245 | - :storage => :s3, | |
| 246 | - :bucket => ENV["S3_TEST_BUCKET"], | |
| 247 | - :path => ":class/:attachment/:id/:style.:extension", | |
| 248 | - :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")) | |
| 249 | - | |
| 250 | - Dummy.delete_all | |
| 251 | - @dummy = Dummy.new | |
| 252 | - end | |
| 253 | - | |
| 254 | - should "be extended by the S3 module" do | |
| 255 | - assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3) | |
| 256 | - end | |
| 257 | - | |
| 258 | - context "when assigned" do | |
| 259 | - setup do | |
| 260 | - @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb') | |
| 261 | - @dummy.avatar = @file | |
| 262 | - end | |
| 263 | - | |
| 264 | - teardown { @file.close } | |
| 265 | - | |
| 266 | - should "still return a Tempfile when sent #to_io" do | |
| 267 | - assert_equal Tempfile, @dummy.avatar.to_io.class | |
| 268 | - end | |
| 269 | - | |
| 270 | - context "and saved" do | |
| 271 | - setup do | |
| 272 | - @dummy.save | |
| 273 | - end | |
| 274 | - | |
| 275 | - should "be on S3" do | |
| 276 | - assert true | |
| 277 | - end | |
| 278 | - end | |
| 279 | - end | |
| 280 | - end | |
| 281 | - end | |
| 282 | -end |
vendor/gems/thoughtbot-paperclip-2.2.9.2/test/thumbnail_test.rb
| ... | ... | @@ -1,177 +0,0 @@ |
| 1 | -require 'test/helper' | |
| 2 | - | |
| 3 | -class ThumbnailTest < Test::Unit::TestCase | |
| 4 | - | |
| 5 | - context "A Paperclip Tempfile" do | |
| 6 | - setup do | |
| 7 | - @tempfile = Paperclip::Tempfile.new("file.jpg") | |
| 8 | - end | |
| 9 | - | |
| 10 | - should "have its path contain a real extension" do | |
| 11 | - assert_equal ".jpg", File.extname(@tempfile.path) | |
| 12 | - end | |
| 13 | - | |
| 14 | - should "be a real Tempfile" do | |
| 15 | - assert @tempfile.is_a?(::Tempfile) | |
| 16 | - end | |
| 17 | - end | |
| 18 | - | |
| 19 | - context "Another Paperclip Tempfile" do | |
| 20 | - setup do | |
| 21 | - @tempfile = Paperclip::Tempfile.new("file") | |
| 22 | - end | |
| 23 | - | |
| 24 | - should "not have an extension if not given one" do | |
| 25 | - assert_equal "", File.extname(@tempfile.path) | |
| 26 | - end | |
| 27 | - | |
| 28 | - should "still be a real Tempfile" do | |
| 29 | - assert @tempfile.is_a?(::Tempfile) | |
| 30 | - end | |
| 31 | - end | |
| 32 | - | |
| 33 | - context "An image" do | |
| 34 | - setup do | |
| 35 | - @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | |
| 36 | - end | |
| 37 | - | |
| 38 | - teardown { @file.close } | |
| 39 | - | |
| 40 | - [["600x600>", "434x66"], | |
| 41 | - ["400x400>", "400x61"], | |
| 42 | - ["32x32<", "434x66"] | |
| 43 | - ].each do |args| | |
| 44 | - context "being thumbnailed with a geometry of #{args[0]}" do | |
| 45 | - setup do | |
| 46 | - @thumb = Paperclip::Thumbnail.new(@file, :geometry => args[0]) | |
| 47 | - end | |
| 48 | - | |
| 49 | - should "start with dimensions of 434x66" do | |
| 50 | - cmd = %Q[identify -format "%wx%h" "#{@file.path}"] | |
| 51 | - assert_equal "434x66", `#{cmd}`.chomp | |
| 52 | - end | |
| 53 | - | |
| 54 | - should "report the correct target geometry" do | |
| 55 | - assert_equal args[0], @thumb.target_geometry.to_s | |
| 56 | - end | |
| 57 | - | |
| 58 | - context "when made" do | |
| 59 | - setup do | |
| 60 | - @thumb_result = @thumb.make | |
| 61 | - end | |
| 62 | - | |
| 63 | - should "be the size we expect it to be" do | |
| 64 | - cmd = %Q[identify -format "%wx%h" "#{@thumb_result.path}"] | |
| 65 | - assert_equal args[1], `#{cmd}`.chomp | |
| 66 | - end | |
| 67 | - end | |
| 68 | - end | |
| 69 | - end | |
| 70 | - | |
| 71 | - context "being thumbnailed at 100x50 with cropping" do | |
| 72 | - setup do | |
| 73 | - @thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x50#") | |
| 74 | - end | |
| 75 | - | |
| 76 | - should "report its correct current and target geometries" do | |
| 77 | - assert_equal "100x50#", @thumb.target_geometry.to_s | |
| 78 | - assert_equal "434x66", @thumb.current_geometry.to_s | |
| 79 | - end | |
| 80 | - | |
| 81 | - should "report its correct format" do | |
| 82 | - assert_nil @thumb.format | |
| 83 | - end | |
| 84 | - | |
| 85 | - should "have whiny turned on by default" do | |
| 86 | - assert @thumb.whiny | |
| 87 | - end | |
| 88 | - | |
| 89 | - should "have convert_options set to nil by default" do | |
| 90 | - assert_equal nil, @thumb.convert_options | |
| 91 | - end | |
| 92 | - | |
| 93 | - should "send the right command to convert when sent #make" do | |
| 94 | - Paperclip.expects(:"`").with do |arg| | |
| 95 | - arg.match %r{convert\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+\"x50\"\s+-crop\s+\"100x50\+114\+0\"\s+\+repage\s+".*?"} | |
| 96 | - end | |
| 97 | - @thumb.make | |
| 98 | - end | |
| 99 | - | |
| 100 | - should "create the thumbnail when sent #make" do | |
| 101 | - dst = @thumb.make | |
| 102 | - assert_match /100x50/, `identify "#{dst.path}"` | |
| 103 | - end | |
| 104 | - end | |
| 105 | - | |
| 106 | - context "being thumbnailed with convert options set" do | |
| 107 | - setup do | |
| 108 | - @thumb = Paperclip::Thumbnail.new(@file, | |
| 109 | - :geometry => "100x50#", | |
| 110 | - :convert_options => "-strip -depth 8") | |
| 111 | - end | |
| 112 | - | |
| 113 | - should "have convert_options value set" do | |
| 114 | - assert_equal "-strip -depth 8", @thumb.convert_options | |
| 115 | - end | |
| 116 | - | |
| 117 | - should "send the right command to convert when sent #make" do | |
| 118 | - Paperclip.expects(:"`").with do |arg| | |
| 119 | - arg.match %r{convert\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+"x50"\s+-crop\s+"100x50\+114\+0"\s+\+repage\s+-strip\s+-depth\s+8\s+".*?"} | |
| 120 | - end | |
| 121 | - @thumb.make | |
| 122 | - end | |
| 123 | - | |
| 124 | - should "create the thumbnail when sent #make" do | |
| 125 | - dst = @thumb.make | |
| 126 | - assert_match /100x50/, `identify "#{dst.path}"` | |
| 127 | - end | |
| 128 | - | |
| 129 | - context "redefined to have bad convert_options setting" do | |
| 130 | - setup do | |
| 131 | - @thumb = Paperclip::Thumbnail.new(@file, | |
| 132 | - :geometry => "100x50#", | |
| 133 | - :convert_options => "-this-aint-no-option") | |
| 134 | - end | |
| 135 | - | |
| 136 | - should "error when trying to create the thumbnail" do | |
| 137 | - assert_raises(Paperclip::PaperclipError) do | |
| 138 | - @thumb.make | |
| 139 | - end | |
| 140 | - end | |
| 141 | - end | |
| 142 | - end | |
| 143 | - end | |
| 144 | - | |
| 145 | - context "A multipage PDF" do | |
| 146 | - setup do | |
| 147 | - @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "twopage.pdf"), 'rb') | |
| 148 | - end | |
| 149 | - | |
| 150 | - teardown { @file.close } | |
| 151 | - | |
| 152 | - should "start with two pages with dimensions 612x792" do | |
| 153 | - cmd = %Q[identify -format "%wx%h" "#{@file.path}"] | |
| 154 | - assert_equal "612x792"*2, `#{cmd}`.chomp | |
| 155 | - end | |
| 156 | - | |
| 157 | - context "being thumbnailed at 100x100 with cropping" do | |
| 158 | - setup do | |
| 159 | - @thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x100#", :format => :png) | |
| 160 | - end | |
| 161 | - | |
| 162 | - should "report its correct current and target geometries" do | |
| 163 | - assert_equal "100x100#", @thumb.target_geometry.to_s | |
| 164 | - assert_equal "612x792", @thumb.current_geometry.to_s | |
| 165 | - end | |
| 166 | - | |
| 167 | - should "report its correct format" do | |
| 168 | - assert_equal :png, @thumb.format | |
| 169 | - end | |
| 170 | - | |
| 171 | - should "create the thumbnail when sent #make" do | |
| 172 | - dst = @thumb.make | |
| 173 | - assert_match /100x100/, `identify "#{dst.path}"` | |
| 174 | - end | |
| 175 | - end | |
| 176 | - end | |
| 177 | -end |
| ... | ... | @@ -0,0 +1,126 @@ |
| 1 | +--- !ruby/object:Gem::Specification | |
| 2 | +name: tristandunn-paperclip | |
| 3 | +version: !ruby/object:Gem::Version | |
| 4 | + version: 2.3.1 | |
| 5 | +platform: ruby | |
| 6 | +authors: | |
| 7 | +- Jon Yurek | |
| 8 | +autorequire: | |
| 9 | +bindir: bin | |
| 10 | +cert_chain: [] | |
| 11 | + | |
| 12 | +date: 2009-08-06 00:00:00 -04:00 | |
| 13 | +default_executable: | |
| 14 | +dependencies: | |
| 15 | +- !ruby/object:Gem::Dependency | |
| 16 | + name: thoughtbot-shoulda | |
| 17 | + type: :development | |
| 18 | + version_requirement: | |
| 19 | + version_requirements: !ruby/object:Gem::Requirement | |
| 20 | + requirements: | |
| 21 | + - - ">=" | |
| 22 | + - !ruby/object:Gem::Version | |
| 23 | + version: "0" | |
| 24 | + version: | |
| 25 | +- !ruby/object:Gem::Dependency | |
| 26 | + name: mocha | |
| 27 | + type: :development | |
| 28 | + version_requirement: | |
| 29 | + version_requirements: !ruby/object:Gem::Requirement | |
| 30 | + requirements: | |
| 31 | + - - ">=" | |
| 32 | + - !ruby/object:Gem::Version | |
| 33 | + version: "0" | |
| 34 | + version: | |
| 35 | +description: | |
| 36 | +email: jyurek@thoughtbot.com | |
| 37 | +executables: [] | |
| 38 | + | |
| 39 | +extensions: [] | |
| 40 | + | |
| 41 | +extra_rdoc_files: | |
| 42 | +- README.rdoc | |
| 43 | +files: | |
| 44 | +- README.rdoc | |
| 45 | +- LICENSE | |
| 46 | +- Rakefile | |
| 47 | +- init.rb | |
| 48 | +- generators/paperclip | |
| 49 | +- generators/paperclip/paperclip_generator.rb | |
| 50 | +- generators/paperclip/templates | |
| 51 | +- generators/paperclip/templates/paperclip_migration.rb.erb | |
| 52 | +- generators/paperclip/USAGE | |
| 53 | +- lib/paperclip | |
| 54 | +- lib/paperclip/attachment.rb | |
| 55 | +- lib/paperclip/callback_compatability.rb | |
| 56 | +- lib/paperclip/geometry.rb | |
| 57 | +- lib/paperclip/interpolations.rb | |
| 58 | +- lib/paperclip/iostream.rb | |
| 59 | +- lib/paperclip/matchers | |
| 60 | +- lib/paperclip/matchers/have_attached_file_matcher.rb | |
| 61 | +- lib/paperclip/matchers/validate_attachment_content_type_matcher.rb | |
| 62 | +- lib/paperclip/matchers/validate_attachment_presence_matcher.rb | |
| 63 | +- lib/paperclip/matchers/validate_attachment_size_matcher.rb | |
| 64 | +- lib/paperclip/matchers.rb | |
| 65 | +- lib/paperclip/processor.rb | |
| 66 | +- lib/paperclip/storage.rb | |
| 67 | +- lib/paperclip/thumbnail.rb | |
| 68 | +- lib/paperclip/upfile.rb | |
| 69 | +- lib/paperclip.rb | |
| 70 | +- tasks/paperclip_tasks.rake | |
| 71 | +- test/attachment_test.rb | |
| 72 | +- test/database.yml | |
| 73 | +- test/fixtures | |
| 74 | +- test/fixtures/12k.png | |
| 75 | +- test/fixtures/50x50.png | |
| 76 | +- test/fixtures/5k.png | |
| 77 | +- test/fixtures/bad.png | |
| 78 | +- test/fixtures/s3.yml | |
| 79 | +- test/fixtures/text.txt | |
| 80 | +- test/fixtures/twopage.pdf | |
| 81 | +- test/geometry_test.rb | |
| 82 | +- test/helper.rb | |
| 83 | +- test/integration_test.rb | |
| 84 | +- test/interpolations_test.rb | |
| 85 | +- test/iostream_test.rb | |
| 86 | +- test/matchers | |
| 87 | +- test/matchers/have_attached_file_matcher_test.rb | |
| 88 | +- test/matchers/validate_attachment_content_type_matcher_test.rb | |
| 89 | +- test/matchers/validate_attachment_presence_matcher_test.rb | |
| 90 | +- test/matchers/validate_attachment_size_matcher_test.rb | |
| 91 | +- test/paperclip_test.rb | |
| 92 | +- test/processor_test.rb | |
| 93 | +- test/storage_test.rb | |
| 94 | +- test/thumbnail_test.rb | |
| 95 | +- shoulda_macros/paperclip.rb | |
| 96 | +has_rdoc: true | |
| 97 | +homepage: http://www.thoughtbot.com/projects/paperclip | |
| 98 | +licenses: [] | |
| 99 | + | |
| 100 | +post_install_message: | |
| 101 | +rdoc_options: | |
| 102 | +- --line-numbers | |
| 103 | +- --inline-source | |
| 104 | +require_paths: | |
| 105 | +- lib | |
| 106 | +required_ruby_version: !ruby/object:Gem::Requirement | |
| 107 | + requirements: | |
| 108 | + - - ">=" | |
| 109 | + - !ruby/object:Gem::Version | |
| 110 | + version: "0" | |
| 111 | + version: | |
| 112 | +required_rubygems_version: !ruby/object:Gem::Requirement | |
| 113 | + requirements: | |
| 114 | + - - ">=" | |
| 115 | + - !ruby/object:Gem::Version | |
| 116 | + version: "0" | |
| 117 | + version: | |
| 118 | +requirements: | |
| 119 | +- ImageMagick | |
| 120 | +rubyforge_project: paperclip | |
| 121 | +rubygems_version: 1.3.4 | |
| 122 | +signing_key: | |
| 123 | +specification_version: 3 | |
| 124 | +summary: File attachments as attributes for ActiveRecord | |
| 125 | +test_files: [] | |
| 126 | + | ... | ... |
| ... | ... | @@ -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 | + | ... | ... |
| ... | ... | @@ -0,0 +1,174 @@ |
| 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 ":rails_root/public/system/:attachment/:id/:style/:filename". This | |
| 83 | +location was chosen because on standard Capistrano deployments, the | |
| 84 | +public/system directory is symlinked to the app's shared directory, meaning it | |
| 85 | +will survive between deployments. For example, using that :path, you may have a | |
| 86 | +file at | |
| 87 | + | |
| 88 | + /data/myapp/releases/20081229172410/public/system/avatars/13/small/my_pic.png | |
| 89 | + | |
| 90 | +NOTE: This is a change from previous versions of Paperclip, but is overall a | |
| 91 | +safer choice for the default file store. | |
| 92 | + | |
| 93 | +You may also choose to store your files using Amazon's S3 service. You can find | |
| 94 | +more information about S3 storage at the description for | |
| 95 | +Paperclip::Storage::S3. | |
| 96 | + | |
| 97 | +Files on the local filesystem (and in the Rails app's public directory) will be | |
| 98 | +available to the internet at large. If you require access control, it's | |
| 99 | +possible to place your files in a different location. You will need to change | |
| 100 | +both the :path and :url options in order to make sure the files are unavailable | |
| 101 | +to the public. Both :path and :url allow the same set of interpolated | |
| 102 | +variables. | |
| 103 | + | |
| 104 | +==Post Processing | |
| 105 | + | |
| 106 | +Paperclip supports an extensible selection of post-processors. When you define | |
| 107 | +a set of styles for an attachment, by default it is expected that those | |
| 108 | +"styles" are actually "thumbnails". However, you can do much more than just | |
| 109 | +thumbnail images. By defining a subclass of Paperclip::Processor, you can | |
| 110 | +perform any processing you want on the files that are attached. Any file in | |
| 111 | +your Rails app's lib/paperclip_processors directory is automatically loaded by | |
| 112 | +paperclip, allowing you to easily define custom processors. You can specify a | |
| 113 | +processor with the :processors option to has_attached_file: | |
| 114 | + | |
| 115 | + has_attached_file :scan, :styles => { :text => { :quality => :better } }, | |
| 116 | + :processors => [:ocr] | |
| 117 | + | |
| 118 | +This would load the hypothetical class Paperclip::Ocr, which would have the | |
| 119 | +hash "{ :quality => :better }" passed to it along with the uploaded file. For | |
| 120 | +more information about defining processors, see Paperclip::Processor. | |
| 121 | + | |
| 122 | +The default processor is Paperclip::Thumbnail. For backwards compatability | |
| 123 | +reasons, you can pass a single geometry string or an array containing a | |
| 124 | +geometry and a format, which the file will be converted to, like so: | |
| 125 | + | |
| 126 | + has_attached_file :avatar, :styles => { :thumb => ["32x32#", :png] } | |
| 127 | + | |
| 128 | +This will convert the "thumb" style to a 32x32 square in png format, regardless | |
| 129 | +of what was uploaded. If the format is not specified, it is kept the same (i.e. | |
| 130 | +jpgs will remain jpgs). | |
| 131 | + | |
| 132 | +Multiple processors can be specified, and they will be invoked in the order | |
| 133 | +they are defined in the :processors array. Each successive processor will | |
| 134 | +be given the result of the previous processor's execution. All processors will | |
| 135 | +receive the same parameters, which are what you define in the :styles hash. | |
| 136 | +For example, assuming we had this definition: | |
| 137 | + | |
| 138 | + has_attached_file :scan, :styles => { :text => { :quality => :better } }, | |
| 139 | + :processors => [:rotator, :ocr] | |
| 140 | + | |
| 141 | +then both the :rotator processor and the :ocr processor would receive the | |
| 142 | +options "{ :quality => :better }". This parameter may not mean anything to one | |
| 143 | +or more or the processors, and they are expected to ignore it. | |
| 144 | + | |
| 145 | +NOTE: Because processors operate by turning the original attachment into the | |
| 146 | +styles, no processors will be run if there are no styles defined. | |
| 147 | + | |
| 148 | +==Events | |
| 149 | + | |
| 150 | +Before and after the Post Processing step, Paperclip calls back to the model | |
| 151 | +with a few callbacks, allowing the model to change or cancel the processing | |
| 152 | +step. The callbacks are "before_post_process" and "after_post_process" (which | |
| 153 | +are called before and after the processing of each attachment), and the | |
| 154 | +attachment-specific "before_<attachment>_post_process" and | |
| 155 | +"after_<attachment>_post_process". The callbacks are intended to be as close to | |
| 156 | +normal ActiveRecord callbacks as possible, so if you return false (specifically | |
| 157 | +- returning nil is not the same) in a before_ filter, the post processing step | |
| 158 | +will halt. Returning false in an after_ filter will not halt anything, but you | |
| 159 | +can access the model and the attachment if necessary. | |
| 160 | + | |
| 161 | +NOTE: Post processing will not even *start* if the attachment is not valid | |
| 162 | +according to the validations. Your callbacks and processors will *only* be | |
| 163 | +called with valid attachments. | |
| 164 | + | |
| 165 | +==Contributing | |
| 166 | + | |
| 167 | +If you'd like to contribute a feature or bugfix: Thanks! To make sure your | |
| 168 | +fix/feature has a high chance of being included, please read the following | |
| 169 | +guidelines: | |
| 170 | + | |
| 171 | +1. Ask on the mailing list, or post a new GitHub Issue. | |
| 172 | +2. Make sure there are tests! We will not accept any patch that is not tested. | |
| 173 | + It's a rare time when explicit tests aren't needed. If you have questions | |
| 174 | + about writing tests for paperclip, please ask the mailing list. | ... | ... |
| ... | ... | @@ -0,0 +1,99 @@ |
| 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 | + Dir.glob("paperclip-*.gem").each{|f| FileUtils.rm f } | |
| 46 | +end | |
| 47 | + | |
| 48 | +include_file_globs = ["README*", | |
| 49 | + "LICENSE", | |
| 50 | + "Rakefile", | |
| 51 | + "init.rb", | |
| 52 | + "{generators,lib,tasks,test,shoulda_macros}/**/*"] | |
| 53 | +exclude_file_globs = ["test/s3.yml", | |
| 54 | + "test/debug.log", | |
| 55 | + "test/paperclip.db", | |
| 56 | + "test/doc", | |
| 57 | + "test/doc/*", | |
| 58 | + "test/pkg", | |
| 59 | + "test/pkg/*", | |
| 60 | + "test/tmp", | |
| 61 | + "test/tmp/*"] | |
| 62 | +spec = Gem::Specification.new do |s| | |
| 63 | + s.name = "paperclip" | |
| 64 | + s.version = Paperclip::VERSION | |
| 65 | + s.author = "Jon Yurek" | |
| 66 | + s.email = "jyurek@thoughtbot.com" | |
| 67 | + s.homepage = "http://www.thoughtbot.com/projects/paperclip" | |
| 68 | + s.platform = Gem::Platform::RUBY | |
| 69 | + s.summary = "File attachments as attributes for ActiveRecord" | |
| 70 | + s.files = FileList[include_file_globs].to_a - FileList[exclude_file_globs].to_a | |
| 71 | + s.require_path = "lib" | |
| 72 | + s.test_files = FileList["test/**/test_*.rb"].to_a | |
| 73 | + s.rubyforge_project = "paperclip" | |
| 74 | + s.has_rdoc = true | |
| 75 | + s.extra_rdoc_files = FileList["README*"].to_a | |
| 76 | + s.rdoc_options << '--line-numbers' << '--inline-source' | |
| 77 | + s.requirements << "ImageMagick" | |
| 78 | + s.add_development_dependency 'thoughtbot-shoulda' | |
| 79 | + s.add_development_dependency 'mocha' | |
| 80 | +end | |
| 81 | + | |
| 82 | +desc "Print a list of the files to be put into the gem" | |
| 83 | +task :manifest => :clean do | |
| 84 | + spec.files.each do |file| | |
| 85 | + puts file | |
| 86 | + end | |
| 87 | +end | |
| 88 | + | |
| 89 | +desc "Generate a gemspec file for GitHub" | |
| 90 | +task :gemspec => :clean do | |
| 91 | + File.open("#{spec.name}.gemspec", 'w') do |f| | |
| 92 | + f.write spec.to_ruby | |
| 93 | + end | |
| 94 | +end | |
| 95 | + | |
| 96 | +desc "Build the gem into the current directory" | |
| 97 | +task :gem => :gemspec do | |
| 98 | + `gem build #{spec.name}.gemspec` | |
| 99 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/generators/paperclip/USAGE
0 → 100644
vendor/gems/tristandunn-paperclip-2.3.1/generators/paperclip/paperclip_generator.rb
0 → 100644
| ... | ... | @@ -0,0 +1,27 @@ |
| 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 | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/generators/paperclip/templates/paperclip_migration.rb.erb
0 → 100644
| ... | ... | @@ -0,0 +1,19 @@ |
| 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 | ... | ... |
| ... | ... | @@ -0,0 +1 @@ |
| 1 | +require File.join(File.dirname(__FILE__), "lib", "paperclip") | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip.rb
0 → 100644
| ... | ... | @@ -0,0 +1,350 @@ |
| 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-2009 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/interpolations' | |
| 36 | +require 'paperclip/attachment' | |
| 37 | +if defined? RAILS_ROOT | |
| 38 | + Dir.glob(File.join(File.expand_path(RAILS_ROOT), "lib", "paperclip_processors", "*.rb")).each do |processor| | |
| 39 | + require processor | |
| 40 | + end | |
| 41 | +end | |
| 42 | + | |
| 43 | +# The base module that gets included in ActiveRecord::Base. See the | |
| 44 | +# documentation for Paperclip::ClassMethods for more useful information. | |
| 45 | +module Paperclip | |
| 46 | + | |
| 47 | + VERSION = "2.3.1" | |
| 48 | + | |
| 49 | + class << self | |
| 50 | + # Provides configurability to Paperclip. There are a number of options available, such as: | |
| 51 | + # * whiny: Will raise an error if Paperclip cannot process thumbnails of | |
| 52 | + # an uploaded image. Defaults to true. | |
| 53 | + # * log: Logs progress to the Rails log. Uses ActiveRecord's logger, so honors | |
| 54 | + # log levels, etc. Defaults to true. | |
| 55 | + # * command_path: Defines the path at which to find the command line | |
| 56 | + # programs if they are not visible to Rails the system's search path. Defaults to | |
| 57 | + # nil, which uses the first executable found in the user's search path. | |
| 58 | + # * image_magick_path: Deprecated alias of command_path. | |
| 59 | + def options | |
| 60 | + @options ||= { | |
| 61 | + :whiny => true, | |
| 62 | + :image_magick_path => nil, | |
| 63 | + :command_path => nil, | |
| 64 | + :log => true, | |
| 65 | + :log_command => false, | |
| 66 | + :swallow_stderr => true | |
| 67 | + } | |
| 68 | + end | |
| 69 | + | |
| 70 | + def path_for_command command #:nodoc: | |
| 71 | + if options[:image_magick_path] | |
| 72 | + warn("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead") | |
| 73 | + end | |
| 74 | + path = [options[:command_path] || options[:image_magick_path], command].compact | |
| 75 | + File.join(*path) | |
| 76 | + end | |
| 77 | + | |
| 78 | + def interpolates key, &block | |
| 79 | + Paperclip::Interpolations[key] = block | |
| 80 | + end | |
| 81 | + | |
| 82 | + # The run method takes a command to execute and a string of parameters | |
| 83 | + # that get passed to it. The command is prefixed with the :command_path | |
| 84 | + # option from Paperclip.options. If you have many commands to run and | |
| 85 | + # they are in different paths, the suggested course of action is to | |
| 86 | + # symlink them so they are all in the same directory. | |
| 87 | + # | |
| 88 | + # If the command returns with a result code that is not one of the | |
| 89 | + # expected_outcodes, a PaperclipCommandLineError will be raised. Generally | |
| 90 | + # a code of 0 is expected, but a list of codes may be passed if necessary. | |
| 91 | + # | |
| 92 | + # This method can log the command being run when | |
| 93 | + # Paperclip.options[:log_command] is set to true (defaults to false). This | |
| 94 | + # will only log if logging in general is set to true as well. | |
| 95 | + def run cmd, params = "", expected_outcodes = 0 | |
| 96 | + command = %Q[#{path_for_command(cmd)} #{params}].gsub(/\s+/, " ") | |
| 97 | + command = "#{command} 2>#{bit_bucket}" if Paperclip.options[:swallow_stderr] | |
| 98 | + Paperclip.log(command) if Paperclip.options[:log_command] | |
| 99 | + output = `#{command}` | |
| 100 | + unless [expected_outcodes].flatten.include?($?.exitstatus) | |
| 101 | + raise PaperclipCommandLineError, "Error while running #{cmd}" | |
| 102 | + end | |
| 103 | + output | |
| 104 | + end | |
| 105 | + | |
| 106 | + def bit_bucket #:nodoc: | |
| 107 | + File.exists?("/dev/null") ? "/dev/null" : "NUL" | |
| 108 | + end | |
| 109 | + | |
| 110 | + def included base #:nodoc: | |
| 111 | + base.extend ClassMethods | |
| 112 | + unless base.respond_to?(:define_callbacks) | |
| 113 | + base.send(:include, Paperclip::CallbackCompatability) | |
| 114 | + end | |
| 115 | + end | |
| 116 | + | |
| 117 | + def processor name #:nodoc: | |
| 118 | + name = name.to_s.camelize | |
| 119 | + processor = Paperclip.const_get(name) | |
| 120 | + unless processor.ancestors.include?(Paperclip::Processor) | |
| 121 | + raise PaperclipError.new("Processor #{name} was not found") | |
| 122 | + end | |
| 123 | + processor | |
| 124 | + end | |
| 125 | + | |
| 126 | + # Log a paperclip-specific line. Uses ActiveRecord::Base.logger | |
| 127 | + # by default. Set Paperclip.options[:log] to false to turn off. | |
| 128 | + def log message | |
| 129 | + logger.info("[paperclip] #{message}") if logging? | |
| 130 | + end | |
| 131 | + | |
| 132 | + def logger #:nodoc: | |
| 133 | + ActiveRecord::Base.logger | |
| 134 | + end | |
| 135 | + | |
| 136 | + def logging? #:nodoc: | |
| 137 | + options[:log] | |
| 138 | + end | |
| 139 | + end | |
| 140 | + | |
| 141 | + class PaperclipError < StandardError #:nodoc: | |
| 142 | + end | |
| 143 | + | |
| 144 | + class PaperclipCommandLineError < StandardError #:nodoc: | |
| 145 | + end | |
| 146 | + | |
| 147 | + class NotIdentifiedByImageMagickError < PaperclipError #:nodoc: | |
| 148 | + end | |
| 149 | + | |
| 150 | + class InfiniteInterpolationError < PaperclipError #:nodoc: | |
| 151 | + end | |
| 152 | + | |
| 153 | + module ClassMethods | |
| 154 | + # +has_attached_file+ gives the class it is called on an attribute that maps to a file. This | |
| 155 | + # is typically a file stored somewhere on the filesystem and has been uploaded by a user. | |
| 156 | + # The attribute returns a Paperclip::Attachment object which handles the management of | |
| 157 | + # that file. The intent is to make the attachment as much like a normal attribute. The | |
| 158 | + # thumbnails will be created when the new file is assigned, but they will *not* be saved | |
| 159 | + # until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is | |
| 160 | + # called on it, the attachment will *not* be deleted until +save+ is called. See the | |
| 161 | + # Paperclip::Attachment documentation for more specifics. There are a number of options | |
| 162 | + # you can set to change the behavior of a Paperclip attachment: | |
| 163 | + # * +url+: The full URL of where the attachment is publically accessible. This can just | |
| 164 | + # as easily point to a directory served directly through Apache as it can to an action | |
| 165 | + # that can control permissions. You can specify the full domain and path, but usually | |
| 166 | + # just an absolute path is sufficient. The leading slash *must* be included manually for | |
| 167 | + # absolute paths. The default value is | |
| 168 | + # "/system/:attachment/:id/:style/:filename". See | |
| 169 | + # Paperclip::Attachment#interpolate for more information on variable interpolaton. | |
| 170 | + # :url => "/:class/:attachment/:id/:style_:filename" | |
| 171 | + # :url => "http://some.other.host/stuff/:class/:id_:extension" | |
| 172 | + # * +default_url+: The URL that will be returned if there is no attachment assigned. | |
| 173 | + # This field is interpolated just as the url is. The default value is | |
| 174 | + # "/:attachment/:style/missing.png" | |
| 175 | + # has_attached_file :avatar, :default_url => "/images/default_:style_avatar.png" | |
| 176 | + # User.new.avatar_url(:small) # => "/images/default_small_avatar.png" | |
| 177 | + # * +styles+: A hash of thumbnail styles and their geometries. You can find more about | |
| 178 | + # geometry strings at the ImageMagick website | |
| 179 | + # (http://www.imagemagick.org/script/command-line-options.php#resize). Paperclip | |
| 180 | + # also adds the "#" option (e.g. "50x50#"), which will resize the image to fit maximally | |
| 181 | + # inside the dimensions and then crop the rest off (weighted at the center). The | |
| 182 | + # default value is to generate no thumbnails. | |
| 183 | + # * +default_style+: The thumbnail style that will be used by default URLs. | |
| 184 | + # Defaults to +original+. | |
| 185 | + # has_attached_file :avatar, :styles => { :normal => "100x100#" }, | |
| 186 | + # :default_style => :normal | |
| 187 | + # user.avatar.url # => "/avatars/23/normal_me.png" | |
| 188 | + # * +whiny+: Will raise an error if Paperclip cannot post_process an uploaded file due | |
| 189 | + # to a command line error. This will override the global setting for this attachment. | |
| 190 | + # Defaults to true. This option used to be called :whiny_thumbanils, but this is | |
| 191 | + # deprecated. | |
| 192 | + # * +convert_options+: When creating thumbnails, use this free-form options | |
| 193 | + # field to pass in various convert command options. Typical options are "-strip" to | |
| 194 | + # remove all Exif data from the image (save space for thumbnails and avatars) or | |
| 195 | + # "-depth 8" to specify the bit depth of the resulting conversion. See ImageMagick | |
| 196 | + # convert documentation for more options: (http://www.imagemagick.org/script/convert.php) | |
| 197 | + # Note that this option takes a hash of options, each of which correspond to the style | |
| 198 | + # of thumbnail being generated. You can also specify :all as a key, which will apply | |
| 199 | + # to all of the thumbnails being generated. If you specify options for the :original, | |
| 200 | + # it would be best if you did not specify destructive options, as the intent of keeping | |
| 201 | + # the original around is to regenerate all the thumbnails when requirements change. | |
| 202 | + # has_attached_file :avatar, :styles => { :large => "300x300", :negative => "100x100" } | |
| 203 | + # :convert_options => { | |
| 204 | + # :all => "-strip", | |
| 205 | + # :negative => "-negate" | |
| 206 | + # } | |
| 207 | + # NOTE: While not deprecated yet, it is not recommended to specify options this way. | |
| 208 | + # It is recommended that :convert_options option be included in the hash passed to each | |
| 209 | + # :styles for compatability with future versions. | |
| 210 | + # * +storage+: Chooses the storage backend where the files will be stored. The current | |
| 211 | + # choices are :filesystem and :s3. The default is :filesystem. Make sure you read the | |
| 212 | + # documentation for Paperclip::Storage::Filesystem and Paperclip::Storage::S3 | |
| 213 | + # for backend-specific options. | |
| 214 | + def has_attached_file name, options = {} | |
| 215 | + include InstanceMethods | |
| 216 | + | |
| 217 | + write_inheritable_attribute(:attachment_definitions, {}) if attachment_definitions.nil? | |
| 218 | + attachment_definitions[name] = {:validations => []}.merge(options) | |
| 219 | + | |
| 220 | + after_save :save_attached_files | |
| 221 | + before_destroy :destroy_attached_files | |
| 222 | + | |
| 223 | + define_callbacks :before_post_process, :after_post_process | |
| 224 | + define_callbacks :"before_#{name}_post_process", :"after_#{name}_post_process" | |
| 225 | + | |
| 226 | + define_method name do |*args| | |
| 227 | + a = attachment_for(name) | |
| 228 | + (args.length > 0) ? a.to_s(args.first) : a | |
| 229 | + end | |
| 230 | + | |
| 231 | + define_method "#{name}=" do |file| | |
| 232 | + attachment_for(name).assign(file) | |
| 233 | + end | |
| 234 | + | |
| 235 | + define_method "#{name}?" do | |
| 236 | + attachment_for(name).file? | |
| 237 | + end | |
| 238 | + | |
| 239 | + validates_each(name) do |record, attr, value| | |
| 240 | + attachment = record.attachment_for(name) | |
| 241 | + attachment.send(:flush_errors) unless attachment.valid? | |
| 242 | + end | |
| 243 | + end | |
| 244 | + | |
| 245 | + # Places ActiveRecord-style validations on the size of the file assigned. The | |
| 246 | + # possible options are: | |
| 247 | + # * +in+: a Range of bytes (i.e. +1..1.megabyte+), | |
| 248 | + # * +less_than+: equivalent to :in => 0..options[:less_than] | |
| 249 | + # * +greater_than+: equivalent to :in => options[:greater_than]..Infinity | |
| 250 | + # * +message+: error message to display, use :min and :max as replacements | |
| 251 | + # * +if+: A lambda or name of a method on the instance. Validation will only | |
| 252 | + # be run is this lambda or method returns true. | |
| 253 | + # * +unless+: Same as +if+ but validates if lambda or method returns false. | |
| 254 | + def validates_attachment_size name, options = {} | |
| 255 | + min = options[:greater_than] || (options[:in] && options[:in].first) || 0 | |
| 256 | + max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0) | |
| 257 | + range = (min..max) | |
| 258 | + message = options[:message] || "file size must be between :min and :max bytes." | |
| 259 | + | |
| 260 | + attachment_definitions[name][:validations] << [:size, {:range => range, | |
| 261 | + :message => message, | |
| 262 | + :if => options[:if], | |
| 263 | + :unless => options[:unless]}] | |
| 264 | + end | |
| 265 | + | |
| 266 | + # Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true. | |
| 267 | + def validates_attachment_thumbnails name, options = {} | |
| 268 | + warn('[DEPRECATION] validates_attachment_thumbnail is deprecated. ' + | |
| 269 | + 'This validation is on by default and will be removed from future versions. ' + | |
| 270 | + 'If you wish to turn it off, supply :whiny => false in your definition.') | |
| 271 | + attachment_definitions[name][:whiny_thumbnails] = true | |
| 272 | + end | |
| 273 | + | |
| 274 | + # Places ActiveRecord-style validations on the presence of a file. | |
| 275 | + # Options: | |
| 276 | + # * +if+: A lambda or name of a method on the instance. Validation will only | |
| 277 | + # be run is this lambda or method returns true. | |
| 278 | + # * +unless+: Same as +if+ but validates if lambda or method returns false. | |
| 279 | + def validates_attachment_presence name, options = {} | |
| 280 | + message = options[:message] || "must be set." | |
| 281 | + attachment_definitions[name][:validations] << [:presence, {:message => message, | |
| 282 | + :if => options[:if], | |
| 283 | + :unless => options[:unless]}] | |
| 284 | + end | |
| 285 | + | |
| 286 | + # Places ActiveRecord-style validations on the content type of the file | |
| 287 | + # assigned. The possible options are: | |
| 288 | + # * +content_type+: Allowed content types. Can be a single content type | |
| 289 | + # or an array. Each type can be a String or a Regexp. It should be | |
| 290 | + # noted that Internet Explorer upload files with content_types that you | |
| 291 | + # may not expect. For example, JPEG images are given image/pjpeg and | |
| 292 | + # PNGs are image/x-png, so keep that in mind when determining how you | |
| 293 | + # match. Allows all by default. | |
| 294 | + # * +message+: The message to display when the uploaded file has an invalid | |
| 295 | + # content type. | |
| 296 | + # * +if+: A lambda or name of a method on the instance. Validation will only | |
| 297 | + # be run is this lambda or method returns true. | |
| 298 | + # * +unless+: Same as +if+ but validates if lambda or method returns false. | |
| 299 | + # NOTE: If you do not specify an [attachment]_content_type field on your | |
| 300 | + # model, content_type validation will work _ONLY upon assignment_ and | |
| 301 | + # re-validation after the instance has been reloaded will always succeed. | |
| 302 | + def validates_attachment_content_type name, options = {} | |
| 303 | + attachment_definitions[name][:validations] << [:content_type, {:content_type => options[:content_type], | |
| 304 | + :message => options[:message], | |
| 305 | + :if => options[:if], | |
| 306 | + :unless => options[:unless]}] | |
| 307 | + end | |
| 308 | + | |
| 309 | + # Returns the attachment definitions defined by each call to | |
| 310 | + # has_attached_file. | |
| 311 | + def attachment_definitions | |
| 312 | + read_inheritable_attribute(:attachment_definitions) | |
| 313 | + end | |
| 314 | + end | |
| 315 | + | |
| 316 | + module InstanceMethods #:nodoc: | |
| 317 | + def attachment_for name | |
| 318 | + @_paperclip_attachments ||= {} | |
| 319 | + @_paperclip_attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name]) | |
| 320 | + end | |
| 321 | + | |
| 322 | + def each_attachment | |
| 323 | + self.class.attachment_definitions.each do |name, definition| | |
| 324 | + yield(name, attachment_for(name)) | |
| 325 | + end | |
| 326 | + end | |
| 327 | + | |
| 328 | + def save_attached_files | |
| 329 | + logger.info("[paperclip] Saving attachments.") | |
| 330 | + each_attachment do |name, attachment| | |
| 331 | + attachment.send(:save) | |
| 332 | + end | |
| 333 | + end | |
| 334 | + | |
| 335 | + def destroy_attached_files | |
| 336 | + logger.info("[paperclip] Deleting attachments.") | |
| 337 | + each_attachment do |name, attachment| | |
| 338 | + attachment.send(:queue_existing_for_delete) | |
| 339 | + attachment.send(:flush_deletes) | |
| 340 | + end | |
| 341 | + end | |
| 342 | + end | |
| 343 | + | |
| 344 | +end | |
| 345 | + | |
| 346 | +# Set it all up. | |
| 347 | +if Object.const_defined?("ActiveRecord") | |
| 348 | + ActiveRecord::Base.send(:include, Paperclip) | |
| 349 | + File.send(:include, Paperclip::Upfile) | |
| 350 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/attachment.rb
0 → 100644
| ... | ... | @@ -0,0 +1,414 @@ |
| 1 | +# encoding: utf-8 | |
| 2 | +module Paperclip | |
| 3 | + # The Attachment class manages the files for a given attachment. It saves | |
| 4 | + # when the model saves, deletes when the model is destroyed, and processes | |
| 5 | + # the file upon assignment. | |
| 6 | + class Attachment | |
| 7 | + | |
| 8 | + def self.default_options | |
| 9 | + @default_options ||= { | |
| 10 | + :url => "/system/:attachment/:id/:style/:filename", | |
| 11 | + :path => ":rails_root/public:url", | |
| 12 | + :styles => {}, | |
| 13 | + :default_url => "/:attachment/:style/missing.png", | |
| 14 | + :default_style => :original, | |
| 15 | + :validations => [], | |
| 16 | + :storage => :filesystem, | |
| 17 | + :whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails] | |
| 18 | + } | |
| 19 | + end | |
| 20 | + | |
| 21 | + attr_reader :name, :instance, :styles, :default_style, :convert_options, :queued_for_write, :options | |
| 22 | + | |
| 23 | + # Creates an Attachment object. +name+ is the name of the attachment, | |
| 24 | + # +instance+ is the ActiveRecord object instance it's attached to, and | |
| 25 | + # +options+ is the same as the hash passed to +has_attached_file+. | |
| 26 | + def initialize name, instance, options = {} | |
| 27 | + @name = name | |
| 28 | + @instance = instance | |
| 29 | + | |
| 30 | + options = self.class.default_options.merge(options) | |
| 31 | + | |
| 32 | + @url = options[:url] | |
| 33 | + @url = @url.call(self) if @url.is_a?(Proc) | |
| 34 | + @path = options[:path] | |
| 35 | + @path = @path.call(self) if @path.is_a?(Proc) | |
| 36 | + @styles = options[:styles] | |
| 37 | + @styles = @styles.call(self) if @styles.is_a?(Proc) | |
| 38 | + @default_url = options[:default_url] | |
| 39 | + @validations = options[:validations] | |
| 40 | + @default_style = options[:default_style] | |
| 41 | + @storage = options[:storage] | |
| 42 | + @whiny = options[:whiny_thumbnails] || options[:whiny] | |
| 43 | + @convert_options = options[:convert_options] || {} | |
| 44 | + @processors = options[:processors] || [:thumbnail] | |
| 45 | + @options = options | |
| 46 | + @queued_for_delete = [] | |
| 47 | + @queued_for_write = {} | |
| 48 | + @errors = {} | |
| 49 | + @validation_errors = nil | |
| 50 | + @dirty = false | |
| 51 | + | |
| 52 | + normalize_style_definition | |
| 53 | + initialize_storage | |
| 54 | + end | |
| 55 | + | |
| 56 | + # What gets called when you call instance.attachment = File. It clears | |
| 57 | + # errors, assigns attributes, processes the file, and runs validations. It | |
| 58 | + # also queues up the previous file for deletion, to be flushed away on | |
| 59 | + # #save of its host. In addition to form uploads, you can also assign | |
| 60 | + # another Paperclip attachment: | |
| 61 | + # new_user.avatar = old_user.avatar | |
| 62 | + # If the file that is assigned is not valid, the processing (i.e. | |
| 63 | + # thumbnailing, etc) will NOT be run. | |
| 64 | + def assign uploaded_file | |
| 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 | + @queued_for_write[:original] = uploaded_file.to_tempfile | |
| 80 | + instance_write(:file_name, uploaded_file.original_filename.strip.gsub(/[^A-Za-z\d\.\-_]+/, '_')) | |
| 81 | + instance_write(:content_type, uploaded_file.content_type.to_s.strip) | |
| 82 | + instance_write(:file_size, uploaded_file.size.to_i) | |
| 83 | + instance_write(:updated_at, Time.now) | |
| 84 | + | |
| 85 | + @dirty = true | |
| 86 | + | |
| 87 | + post_process if valid? | |
| 88 | + | |
| 89 | + # Reset the file size if the original file was reprocessed. | |
| 90 | + instance_write(:file_size, @queued_for_write[:original].size.to_i) | |
| 91 | + ensure | |
| 92 | + uploaded_file.close if close_uploaded_file | |
| 93 | + validate | |
| 94 | + end | |
| 95 | + | |
| 96 | + # Returns the public URL of the attachment, with a given style. Note that | |
| 97 | + # this does not necessarily need to point to a file that your web server | |
| 98 | + # can access and can point to an action in your app, if you need fine | |
| 99 | + # grained security. This is not recommended if you don't need the | |
| 100 | + # security, however, for performance reasons. set | |
| 101 | + # include_updated_timestamp to false if you want to stop the attachment | |
| 102 | + # update time appended to the url | |
| 103 | + def url style = default_style, include_updated_timestamp = true | |
| 104 | + url = original_filename.nil? ? interpolate(@default_url, style) : interpolate(@url, style) | |
| 105 | + include_updated_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url | |
| 106 | + end | |
| 107 | + | |
| 108 | + # Returns the path of the attachment as defined by the :path option. If the | |
| 109 | + # file is stored in the filesystem the path refers to the path of the file | |
| 110 | + # on disk. If the file is stored in S3, the path is the "key" part of the | |
| 111 | + # URL, and the :bucket option refers to the S3 bucket. | |
| 112 | + def path style = default_style | |
| 113 | + original_filename.nil? ? nil : interpolate(@path, style) | |
| 114 | + end | |
| 115 | + | |
| 116 | + # Alias to +url+ | |
| 117 | + def to_s style = nil | |
| 118 | + url(style) | |
| 119 | + end | |
| 120 | + | |
| 121 | + # Returns true if there are no errors on this attachment. | |
| 122 | + def valid? | |
| 123 | + validate | |
| 124 | + errors.empty? | |
| 125 | + end | |
| 126 | + | |
| 127 | + # Returns an array containing the errors on this attachment. | |
| 128 | + def errors | |
| 129 | + @errors | |
| 130 | + end | |
| 131 | + | |
| 132 | + # Returns true if there are changes that need to be saved. | |
| 133 | + def dirty? | |
| 134 | + @dirty | |
| 135 | + end | |
| 136 | + | |
| 137 | + # Saves the file, if there are no errors. If there are, it flushes them to | |
| 138 | + # the instance's errors and returns false, cancelling the save. | |
| 139 | + def save | |
| 140 | + if valid? | |
| 141 | + flush_deletes | |
| 142 | + flush_writes | |
| 143 | + @dirty = false | |
| 144 | + true | |
| 145 | + else | |
| 146 | + flush_errors | |
| 147 | + false | |
| 148 | + end | |
| 149 | + end | |
| 150 | + | |
| 151 | + # Clears out the attachment. Has the same effect as previously assigning | |
| 152 | + # nil to the attachment. Does NOT save. If you wish to clear AND save, | |
| 153 | + # use #destroy. | |
| 154 | + def clear | |
| 155 | + queue_existing_for_delete | |
| 156 | + @errors = {} | |
| 157 | + @validation_errors = nil | |
| 158 | + end | |
| 159 | + | |
| 160 | + # Destroys the attachment. Has the same effect as previously assigning | |
| 161 | + # nil to the attachment *and saving*. This is permanent. If you wish to | |
| 162 | + # wipe out the existing attachment but not save, use #clear. | |
| 163 | + def destroy | |
| 164 | + clear | |
| 165 | + save | |
| 166 | + end | |
| 167 | + | |
| 168 | + # Returns the name of the file as originally assigned, and lives in the | |
| 169 | + # <attachment>_file_name attribute of the model. | |
| 170 | + def original_filename | |
| 171 | + instance_read(:file_name) | |
| 172 | + end | |
| 173 | + | |
| 174 | + # Returns the size of the file as originally assigned, and lives in the | |
| 175 | + # <attachment>_file_size attribute of the model. | |
| 176 | + def size | |
| 177 | + instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size) | |
| 178 | + end | |
| 179 | + | |
| 180 | + # Returns the content_type of the file as originally assigned, and lives | |
| 181 | + # in the <attachment>_content_type attribute of the model. | |
| 182 | + def content_type | |
| 183 | + instance_read(:content_type) | |
| 184 | + end | |
| 185 | + | |
| 186 | + # Returns the last modified time of the file as originally assigned, and | |
| 187 | + # lives in the <attachment>_updated_at attribute of the model. | |
| 188 | + def updated_at | |
| 189 | + time = instance_read(:updated_at) | |
| 190 | + time && time.to_i | |
| 191 | + end | |
| 192 | + | |
| 193 | + # Paths and URLs can have a number of variables interpolated into them | |
| 194 | + # to vary the storage location based on name, id, style, class, etc. | |
| 195 | + # This method is a deprecated access into supplying and retrieving these | |
| 196 | + # interpolations. Future access should use either Paperclip.interpolates | |
| 197 | + # or extend the Paperclip::Interpolations module directly. | |
| 198 | + def self.interpolations | |
| 199 | + warn('[DEPRECATION] Paperclip::Attachment.interpolations is deprecated ' + | |
| 200 | + 'and will be removed from future versions. ' + | |
| 201 | + 'Use Paperclip.interpolates instead') | |
| 202 | + Paperclip::Interpolations | |
| 203 | + end | |
| 204 | + | |
| 205 | + # This method really shouldn't be called that often. It's expected use is | |
| 206 | + # in the paperclip:refresh rake task and that's it. It will regenerate all | |
| 207 | + # thumbnails forcefully, by reobtaining the original file and going through | |
| 208 | + # the post-process again. | |
| 209 | + def reprocess! | |
| 210 | + new_original = Tempfile.new("paperclip-reprocess") | |
| 211 | + new_original.binmode | |
| 212 | + if old_original = to_file(:original) | |
| 213 | + new_original.write( old_original.read ) | |
| 214 | + new_original.rewind | |
| 215 | + | |
| 216 | + @queued_for_write = { :original => new_original } | |
| 217 | + post_process | |
| 218 | + | |
| 219 | + old_original.close if old_original.respond_to?(:close) | |
| 220 | + | |
| 221 | + save | |
| 222 | + else | |
| 223 | + true | |
| 224 | + end | |
| 225 | + end | |
| 226 | + | |
| 227 | + # Returns true if a file has been assigned. | |
| 228 | + def file? | |
| 229 | + !original_filename.blank? | |
| 230 | + end | |
| 231 | + | |
| 232 | + # Writes the attachment-specific attribute on the instance. For example, | |
| 233 | + # instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's | |
| 234 | + # "avatar_file_name" field (assuming the attachment is called avatar). | |
| 235 | + def instance_write(attr, value) | |
| 236 | + setter = :"#{name}_#{attr}=" | |
| 237 | + responds = instance.respond_to?(setter) | |
| 238 | + self.instance_variable_set("@_#{setter.to_s.chop}", value) | |
| 239 | + instance.send(setter, value) if responds || attr.to_s == "file_name" | |
| 240 | + end | |
| 241 | + | |
| 242 | + # Reads the attachment-specific attribute on the instance. See instance_write | |
| 243 | + # for more details. | |
| 244 | + def instance_read(attr) | |
| 245 | + getter = :"#{name}_#{attr}" | |
| 246 | + responds = instance.respond_to?(getter) | |
| 247 | + cached = self.instance_variable_get("@_#{getter}") | |
| 248 | + return cached if cached | |
| 249 | + instance.send(getter) if responds || attr.to_s == "file_name" | |
| 250 | + end | |
| 251 | + | |
| 252 | + private | |
| 253 | + | |
| 254 | + def ensure_required_accessors! #:nodoc: | |
| 255 | + %w(file_name).each do |field| | |
| 256 | + unless @instance.respond_to?("#{name}_#{field}") && @instance.respond_to?("#{name}_#{field}=") | |
| 257 | + raise PaperclipError.new("#{@instance.class} model missing required attr_accessor for '#{name}_#{field}'") | |
| 258 | + end | |
| 259 | + end | |
| 260 | + end | |
| 261 | + | |
| 262 | + def log message #:nodoc: | |
| 263 | + Paperclip.log(message) | |
| 264 | + end | |
| 265 | + | |
| 266 | + def valid_assignment? file #:nodoc: | |
| 267 | + file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type)) | |
| 268 | + end | |
| 269 | + | |
| 270 | + def validate #:nodoc: | |
| 271 | + unless @validation_errors | |
| 272 | + @validation_errors = @validations.inject({}) do |errors, validation| | |
| 273 | + name, options = validation | |
| 274 | + errors[name] = send(:"validate_#{name}", options) if allow_validation?(options) | |
| 275 | + errors | |
| 276 | + end | |
| 277 | + @validation_errors.reject!{|k,v| v == nil } | |
| 278 | + @errors.merge!(@validation_errors) | |
| 279 | + end | |
| 280 | + @validation_errors | |
| 281 | + end | |
| 282 | + | |
| 283 | + def allow_validation? options #:nodoc: | |
| 284 | + (options[:if].nil? || check_guard(options[:if])) && (options[:unless].nil? || !check_guard(options[:unless])) | |
| 285 | + end | |
| 286 | + | |
| 287 | + def check_guard guard #:nodoc: | |
| 288 | + if guard.respond_to? :call | |
| 289 | + guard.call(instance) | |
| 290 | + elsif ! guard.blank? | |
| 291 | + instance.send(guard.to_s) | |
| 292 | + end | |
| 293 | + end | |
| 294 | + | |
| 295 | + def validate_size options #:nodoc: | |
| 296 | + if file? && !options[:range].include?(size.to_i) | |
| 297 | + options[:message].gsub(/:min/, options[:min].to_s).gsub(/:max/, options[:max].to_s) | |
| 298 | + end | |
| 299 | + end | |
| 300 | + | |
| 301 | + def validate_presence options #:nodoc: | |
| 302 | + options[:message] unless file? | |
| 303 | + end | |
| 304 | + | |
| 305 | + def validate_content_type options #:nodoc: | |
| 306 | + valid_types = [options[:content_type]].flatten | |
| 307 | + unless original_filename.blank? | |
| 308 | + unless valid_types.blank? | |
| 309 | + content_type = instance_read(:content_type) | |
| 310 | + unless valid_types.any?{|t| content_type.nil? || t === content_type } | |
| 311 | + options[:message] || "is not one of the allowed file types." | |
| 312 | + end | |
| 313 | + end | |
| 314 | + end | |
| 315 | + end | |
| 316 | + | |
| 317 | + def normalize_style_definition #:nodoc: | |
| 318 | + @styles.each do |name, args| | |
| 319 | + unless args.is_a? Hash | |
| 320 | + dimensions, format = [args, nil].flatten[0..1] | |
| 321 | + format = nil if format.blank? | |
| 322 | + @styles[name] = { | |
| 323 | + :processors => @processors, | |
| 324 | + :geometry => dimensions, | |
| 325 | + :format => format, | |
| 326 | + :whiny => @whiny, | |
| 327 | + :convert_options => extra_options_for(name) | |
| 328 | + } | |
| 329 | + else | |
| 330 | + @styles[name] = { | |
| 331 | + :processors => @processors, | |
| 332 | + :whiny => @whiny, | |
| 333 | + :convert_options => extra_options_for(name) | |
| 334 | + }.merge(@styles[name]) | |
| 335 | + end | |
| 336 | + end | |
| 337 | + end | |
| 338 | + | |
| 339 | + def solidify_style_definitions #:nodoc: | |
| 340 | + @styles.each do |name, args| | |
| 341 | + @styles[name][:geometry] = @styles[name][:geometry].call(instance) if @styles[name][:geometry].respond_to?(:call) | |
| 342 | + @styles[name][:processors] = @styles[name][:processors].call(instance) if @styles[name][:processors].respond_to?(:call) | |
| 343 | + end | |
| 344 | + end | |
| 345 | + | |
| 346 | + def initialize_storage #:nodoc: | |
| 347 | + @storage_module = Paperclip::Storage.const_get(@storage.to_s.capitalize) | |
| 348 | + self.extend(@storage_module) | |
| 349 | + end | |
| 350 | + | |
| 351 | + def extra_options_for(style) #:nodoc: | |
| 352 | + all_options = convert_options[:all] | |
| 353 | + all_options = all_options.call(instance) if all_options.respond_to?(:call) | |
| 354 | + style_options = convert_options[style] | |
| 355 | + style_options = style_options.call(instance) if style_options.respond_to?(:call) | |
| 356 | + | |
| 357 | + [ style_options, all_options ].compact.join(" ") | |
| 358 | + end | |
| 359 | + | |
| 360 | + def post_process #:nodoc: | |
| 361 | + return if @queued_for_write[:original].nil? | |
| 362 | + solidify_style_definitions | |
| 363 | + return if fire_events(:before) | |
| 364 | + post_process_styles | |
| 365 | + return if fire_events(:after) | |
| 366 | + end | |
| 367 | + | |
| 368 | + def fire_events(which) #:nodoc: | |
| 369 | + return true if callback(:"#{which}_post_process") == false | |
| 370 | + return true if callback(:"#{which}_#{name}_post_process") == false | |
| 371 | + end | |
| 372 | + | |
| 373 | + def callback which #:nodoc: | |
| 374 | + instance.run_callbacks(which, @queued_for_write){|result, obj| result == false } | |
| 375 | + end | |
| 376 | + | |
| 377 | + def post_process_styles #:nodoc: | |
| 378 | + @styles.each do |name, args| | |
| 379 | + begin | |
| 380 | + raise RuntimeError.new("Style #{name} has no processors defined.") if args[:processors].blank? | |
| 381 | + @queued_for_write[name] = args[:processors].inject(@queued_for_write[:original]) do |file, processor| | |
| 382 | + Paperclip.processor(processor).make(file, args, self) | |
| 383 | + end | |
| 384 | + rescue PaperclipError => e | |
| 385 | + log("An error was received while processing: #{e.inspect}") | |
| 386 | + (@errors[:processing] ||= []) << e.message if @whiny | |
| 387 | + end | |
| 388 | + end | |
| 389 | + end | |
| 390 | + | |
| 391 | + def interpolate pattern, style = default_style #:nodoc: | |
| 392 | + Paperclip::Interpolations.interpolate(pattern, self, style) | |
| 393 | + end | |
| 394 | + | |
| 395 | + def queue_existing_for_delete #:nodoc: | |
| 396 | + return unless file? | |
| 397 | + @queued_for_delete += [:original, *@styles.keys].uniq.map do |style| | |
| 398 | + path(style) if exists?(style) | |
| 399 | + end.compact | |
| 400 | + instance_write(:file_name, nil) | |
| 401 | + instance_write(:content_type, nil) | |
| 402 | + instance_write(:file_size, nil) | |
| 403 | + instance_write(:updated_at, nil) | |
| 404 | + end | |
| 405 | + | |
| 406 | + def flush_errors #:nodoc: | |
| 407 | + @errors.each do |error, message| | |
| 408 | + [message].flatten.each {|m| instance.errors.add(name, m) } | |
| 409 | + end | |
| 410 | + end | |
| 411 | + | |
| 412 | + end | |
| 413 | +end | |
| 414 | + | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/callback_compatability.rb
0 → 100644
| ... | ... | @@ -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 | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/geometry.rb
0 → 100644
| ... | ... | @@ -0,0 +1,115 @@ |
| 1 | +module Paperclip | |
| 2 | + | |
| 3 | + # Defines the geometry of an image. | |
| 4 | + class Geometry | |
| 5 | + attr_accessor :height, :width, :modifier | |
| 6 | + | |
| 7 | + # Gives a Geometry representing the given height and width | |
| 8 | + def initialize width = nil, height = nil, modifier = nil | |
| 9 | + @height = height.to_f | |
| 10 | + @width = width.to_f | |
| 11 | + @modifier = modifier | |
| 12 | + end | |
| 13 | + | |
| 14 | + # Uses ImageMagick to determing the dimensions of a file, passed in as either a | |
| 15 | + # File or path. | |
| 16 | + def self.from_file file | |
| 17 | + file = file.path if file.respond_to? "path" | |
| 18 | + geometry = begin | |
| 19 | + Paperclip.run("identify", %Q[-format "%wx%h" "#{file}"[0]]) | |
| 20 | + rescue PaperclipCommandLineError | |
| 21 | + "" | |
| 22 | + end | |
| 23 | + parse(geometry) || | |
| 24 | + raise(NotIdentifiedByImageMagickError.new("#{file} is not recognized by the 'identify' command.")) | |
| 25 | + end | |
| 26 | + | |
| 27 | + # Parses a "WxH" formatted string, where W is the width and H is the height. | |
| 28 | + def self.parse string | |
| 29 | + if match = (string && string.match(/\b(\d*)x?(\d*)\b([\>\<\#\@\%^!])?/i)) | |
| 30 | + Geometry.new(*match[1,3]) | |
| 31 | + end | |
| 32 | + end | |
| 33 | + | |
| 34 | + # True if the dimensions represent a square | |
| 35 | + def square? | |
| 36 | + height == width | |
| 37 | + end | |
| 38 | + | |
| 39 | + # True if the dimensions represent a horizontal rectangle | |
| 40 | + def horizontal? | |
| 41 | + height < width | |
| 42 | + end | |
| 43 | + | |
| 44 | + # True if the dimensions represent a vertical rectangle | |
| 45 | + def vertical? | |
| 46 | + height > width | |
| 47 | + end | |
| 48 | + | |
| 49 | + # The aspect ratio of the dimensions. | |
| 50 | + def aspect | |
| 51 | + width / height | |
| 52 | + end | |
| 53 | + | |
| 54 | + # Returns the larger of the two dimensions | |
| 55 | + def larger | |
| 56 | + [height, width].max | |
| 57 | + end | |
| 58 | + | |
| 59 | + # Returns the smaller of the two dimensions | |
| 60 | + def smaller | |
| 61 | + [height, width].min | |
| 62 | + end | |
| 63 | + | |
| 64 | + # Returns the width and height in a format suitable to be passed to Geometry.parse | |
| 65 | + def to_s | |
| 66 | + s = "" | |
| 67 | + s << width.to_i.to_s if width > 0 | |
| 68 | + s << "x#{height.to_i}" if height > 0 | |
| 69 | + s << modifier.to_s | |
| 70 | + s | |
| 71 | + end | |
| 72 | + | |
| 73 | + # Same as to_s | |
| 74 | + def inspect | |
| 75 | + to_s | |
| 76 | + end | |
| 77 | + | |
| 78 | + # Returns the scaling and cropping geometries (in string-based ImageMagick format) | |
| 79 | + # neccessary to transform this Geometry into the Geometry given. If crop is true, | |
| 80 | + # then it is assumed the destination Geometry will be the exact final resolution. | |
| 81 | + # In this case, the source Geometry is scaled so that an image containing the | |
| 82 | + # destination Geometry would be completely filled by the source image, and any | |
| 83 | + # overhanging image would be cropped. Useful for square thumbnail images. The cropping | |
| 84 | + # is weighted at the center of the Geometry. | |
| 85 | + def transformation_to dst, crop = false | |
| 86 | + if crop | |
| 87 | + ratio = Geometry.new( dst.width / self.width, dst.height / self.height ) | |
| 88 | + scale_geometry, scale = scaling(dst, ratio) | |
| 89 | + crop_geometry = cropping(dst, ratio, scale) | |
| 90 | + else | |
| 91 | + scale_geometry = dst.to_s | |
| 92 | + end | |
| 93 | + | |
| 94 | + [ scale_geometry, crop_geometry ] | |
| 95 | + end | |
| 96 | + | |
| 97 | + private | |
| 98 | + | |
| 99 | + def scaling dst, ratio | |
| 100 | + if ratio.horizontal? || ratio.square? | |
| 101 | + [ "%dx" % dst.width, ratio.width ] | |
| 102 | + else | |
| 103 | + [ "x%d" % dst.height, ratio.height ] | |
| 104 | + end | |
| 105 | + end | |
| 106 | + | |
| 107 | + def cropping dst, ratio, scale | |
| 108 | + if ratio.horizontal? || ratio.square? | |
| 109 | + "%dx%d+%d+%d" % [ dst.width, dst.height, 0, (self.height * scale - dst.height) / 2 ] | |
| 110 | + else | |
| 111 | + "%dx%d+%d+%d" % [ dst.width, dst.height, (self.width * scale - dst.width) / 2, 0 ] | |
| 112 | + end | |
| 113 | + end | |
| 114 | + end | |
| 115 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/interpolations.rb
0 → 100644
| ... | ... | @@ -0,0 +1,105 @@ |
| 1 | +module Paperclip | |
| 2 | + # This module contains all the methods that are available for interpolation | |
| 3 | + # in paths and urls. To add your own (or override an existing one), you | |
| 4 | + # can either open this module and define it, or call the | |
| 5 | + # Paperclip.interpolates method. | |
| 6 | + module Interpolations | |
| 7 | + extend self | |
| 8 | + | |
| 9 | + # Hash assignment of interpolations. Included only for compatability, | |
| 10 | + # and is not intended for normal use. | |
| 11 | + def self.[]= name, block | |
| 12 | + define_method(name, &block) | |
| 13 | + end | |
| 14 | + | |
| 15 | + # Hash access of interpolations. Included only for compatability, | |
| 16 | + # and is not intended for normal use. | |
| 17 | + def self.[] name | |
| 18 | + method(name) | |
| 19 | + end | |
| 20 | + | |
| 21 | + # Returns a sorted list of all interpolations. | |
| 22 | + def self.all | |
| 23 | + self.instance_methods(false).sort | |
| 24 | + end | |
| 25 | + | |
| 26 | + # Perform the actual interpolation. Takes the pattern to interpolate | |
| 27 | + # and the arguments to pass, which are the attachment and style name. | |
| 28 | + def self.interpolate pattern, *args | |
| 29 | + all.reverse.inject( pattern.dup ) do |result, tag| | |
| 30 | + result.gsub(/:#{tag}/) do |match| | |
| 31 | + send( tag, *args ) | |
| 32 | + end | |
| 33 | + end | |
| 34 | + end | |
| 35 | + | |
| 36 | + # Returns the filename, the same way as ":basename.:extension" would. | |
| 37 | + def filename attachment, style | |
| 38 | + "#{basename(attachment, style)}.#{extension(attachment, style)}" | |
| 39 | + end | |
| 40 | + | |
| 41 | + # Returns the interpolated URL. Will raise an error if the url itself | |
| 42 | + # contains ":url" to prevent infinite recursion. This interpolation | |
| 43 | + # is used in the default :path to ease default specifications. | |
| 44 | + def url attachment, style | |
| 45 | + raise InfiniteInterpolationError if attachment.options[:url].include?(":url") | |
| 46 | + attachment.url(style, false) | |
| 47 | + end | |
| 48 | + | |
| 49 | + # Returns the timestamp as defined by the <attachment>_updated_at field | |
| 50 | + def timestamp attachment, style | |
| 51 | + attachment.instance_read(:updated_at).to_s | |
| 52 | + end | |
| 53 | + | |
| 54 | + # Returns the RAILS_ROOT constant. | |
| 55 | + def rails_root attachment, style | |
| 56 | + RAILS_ROOT | |
| 57 | + end | |
| 58 | + | |
| 59 | + # Returns the RAILS_ENV constant. | |
| 60 | + def rails_env attachment, style | |
| 61 | + RAILS_ENV | |
| 62 | + end | |
| 63 | + | |
| 64 | + # Returns the underscored, pluralized version of the class name. | |
| 65 | + # e.g. "users" for the User class. | |
| 66 | + def class attachment, style | |
| 67 | + attachment.instance.class.to_s.underscore.pluralize | |
| 68 | + end | |
| 69 | + | |
| 70 | + # Returns the basename of the file. e.g. "file" for "file.jpg" | |
| 71 | + def basename attachment, style | |
| 72 | + attachment.original_filename.gsub(/#{File.extname(attachment.original_filename)}$/, "") | |
| 73 | + end | |
| 74 | + | |
| 75 | + # Returns the extension of the file. e.g. "jpg" for "file.jpg" | |
| 76 | + # If the style has a format defined, it will return the format instead | |
| 77 | + # of the actual extension. | |
| 78 | + def extension attachment, style | |
| 79 | + ((style = attachment.styles[style]) && style[:format]) || | |
| 80 | + File.extname(attachment.original_filename).gsub(/^\.+/, "") | |
| 81 | + end | |
| 82 | + | |
| 83 | + # Returns the id of the instance. | |
| 84 | + def id attachment, style | |
| 85 | + attachment.instance.id | |
| 86 | + end | |
| 87 | + | |
| 88 | + # Returns the id of the instance in a split path form. e.g. returns | |
| 89 | + # 000/001/234 for an id of 1234. | |
| 90 | + def id_partition attachment, style | |
| 91 | + ("%09d" % attachment.instance.id).scan(/\d{3}/).join("/") | |
| 92 | + end | |
| 93 | + | |
| 94 | + # Returns the pluralized form of the attachment name. e.g. | |
| 95 | + # "avatars" for an attachment of :avatar | |
| 96 | + def attachment attachment, style | |
| 97 | + attachment.name.to_s.downcase.pluralize | |
| 98 | + end | |
| 99 | + | |
| 100 | + # Returns the style, or the default style if nil is supplied. | |
| 101 | + def style attachment, style | |
| 102 | + style || attachment.default_style | |
| 103 | + end | |
| 104 | + end | |
| 105 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/iostream.rb
0 → 100644
| ... | ... | @@ -0,0 +1,58 @@ |
| 1 | +# Provides method that can be included on File-type objects (IO, StringIO, Tempfile, etc) to allow stream copying | |
| 2 | +# and Tempfile conversion. | |
| 3 | +module IOStream | |
| 4 | + | |
| 5 | + # Returns a Tempfile containing the contents of the readable object. | |
| 6 | + def to_tempfile | |
| 7 | + tempfile = Tempfile.new("stream") | |
| 8 | + tempfile.binmode | |
| 9 | + self.stream_to(tempfile) | |
| 10 | + end | |
| 11 | + | |
| 12 | + # Copies one read-able object from one place to another in blocks, obviating the need to load | |
| 13 | + # the whole thing into memory. Defaults to 8k blocks. If this module is included in both | |
| 14 | + # StringIO and Tempfile, then either can have its data copied anywhere else without typing | |
| 15 | + # worries or memory overhead worries. Returns a File if a String is passed in as the destination | |
| 16 | + # and returns the IO or Tempfile as passed in if one is sent as the destination. | |
| 17 | + def stream_to path_or_file, in_blocks_of = 8192 | |
| 18 | + dstio = case path_or_file | |
| 19 | + when String then File.new(path_or_file, "wb+") | |
| 20 | + when IO then path_or_file | |
| 21 | + when Tempfile then path_or_file | |
| 22 | + end | |
| 23 | + buffer = "" | |
| 24 | + self.rewind | |
| 25 | + while self.read(in_blocks_of, buffer) do | |
| 26 | + dstio.write(buffer) | |
| 27 | + end | |
| 28 | + dstio.rewind | |
| 29 | + dstio | |
| 30 | + end | |
| 31 | +end | |
| 32 | + | |
| 33 | +class IO #:nodoc: | |
| 34 | + include IOStream | |
| 35 | +end | |
| 36 | + | |
| 37 | +%w( Tempfile StringIO ).each do |klass| | |
| 38 | + if Object.const_defined? klass | |
| 39 | + Object.const_get(klass).class_eval do | |
| 40 | + include IOStream | |
| 41 | + end | |
| 42 | + end | |
| 43 | +end | |
| 44 | + | |
| 45 | +# Corrects a bug in Windows when asking for Tempfile size. | |
| 46 | +if defined? Tempfile | |
| 47 | + class Tempfile | |
| 48 | + def size | |
| 49 | + if @tmpfile | |
| 50 | + @tmpfile.fsync | |
| 51 | + @tmpfile.flush | |
| 52 | + @tmpfile.stat.size | |
| 53 | + else | |
| 54 | + 0 | |
| 55 | + end | |
| 56 | + end | |
| 57 | + end | |
| 58 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/matchers.rb
0 → 100644
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/matchers/have_attached_file_matcher.rb
0 → 100644
| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | +module Paperclip | |
| 2 | + module Shoulda | |
| 3 | + module Matchers | |
| 4 | + def have_attached_file name | |
| 5 | + HaveAttachedFileMatcher.new(name) | |
| 6 | + end | |
| 7 | + | |
| 8 | + class HaveAttachedFileMatcher | |
| 9 | + def initialize attachment_name | |
| 10 | + @attachment_name = attachment_name | |
| 11 | + end | |
| 12 | + | |
| 13 | + def matches? subject | |
| 14 | + @subject = subject | |
| 15 | + responds? && has_column? && included? | |
| 16 | + end | |
| 17 | + | |
| 18 | + def failure_message | |
| 19 | + "Should have an attachment named #{@attachment_name}" | |
| 20 | + end | |
| 21 | + | |
| 22 | + def negative_failure_message | |
| 23 | + "Should not have an attachment named #{@attachment_name}" | |
| 24 | + end | |
| 25 | + | |
| 26 | + def description | |
| 27 | + "have an attachment named #{@attachment_name}" | |
| 28 | + end | |
| 29 | + | |
| 30 | + protected | |
| 31 | + | |
| 32 | + def responds? | |
| 33 | + methods = @subject.instance_methods.map(&:to_s) | |
| 34 | + methods.include?("#{@attachment_name}") && | |
| 35 | + methods.include?("#{@attachment_name}=") && | |
| 36 | + methods.include?("#{@attachment_name}?") | |
| 37 | + end | |
| 38 | + | |
| 39 | + def has_column? | |
| 40 | + @subject.column_names.include?("#{@attachment_name}_file_name") | |
| 41 | + end | |
| 42 | + | |
| 43 | + def included? | |
| 44 | + @subject.ancestors.include?(Paperclip::InstanceMethods) | |
| 45 | + end | |
| 46 | + end | |
| 47 | + end | |
| 48 | + end | |
| 49 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb
0 → 100644
| ... | ... | @@ -0,0 +1,66 @@ |
| 1 | +module Paperclip | |
| 2 | + module Shoulda | |
| 3 | + module Matchers | |
| 4 | + def validate_attachment_content_type name | |
| 5 | + ValidateAttachmentContentTypeMatcher.new(name) | |
| 6 | + end | |
| 7 | + | |
| 8 | + class ValidateAttachmentContentTypeMatcher | |
| 9 | + def initialize attachment_name | |
| 10 | + @attachment_name = attachment_name | |
| 11 | + end | |
| 12 | + | |
| 13 | + def allowing *types | |
| 14 | + @allowed_types = types.flatten | |
| 15 | + self | |
| 16 | + end | |
| 17 | + | |
| 18 | + def rejecting *types | |
| 19 | + @rejected_types = types.flatten | |
| 20 | + self | |
| 21 | + end | |
| 22 | + | |
| 23 | + def matches? subject | |
| 24 | + @subject = subject | |
| 25 | + @allowed_types && @rejected_types && | |
| 26 | + allowed_types_allowed? && rejected_types_rejected? | |
| 27 | + end | |
| 28 | + | |
| 29 | + def failure_message | |
| 30 | + "Content types #{@allowed_types.join(", ")} should be accepted" + | |
| 31 | + " and #{@rejected_types.join(", ")} rejected by #{@attachment_name}" | |
| 32 | + end | |
| 33 | + | |
| 34 | + def negative_failure_message | |
| 35 | + "Content types #{@allowed_types.join(", ")} should be rejected" + | |
| 36 | + " and #{@rejected_types.join(", ")} accepted by #{@attachment_name}" | |
| 37 | + end | |
| 38 | + | |
| 39 | + def description | |
| 40 | + "validate the content types allowed on attachment #{@attachment_name}" | |
| 41 | + end | |
| 42 | + | |
| 43 | + protected | |
| 44 | + | |
| 45 | + def allow_types?(types) | |
| 46 | + types.all? do |type| | |
| 47 | + file = StringIO.new(".") | |
| 48 | + file.content_type = type | |
| 49 | + attachment = @subject.new.attachment_for(@attachment_name) | |
| 50 | + attachment.assign(file) | |
| 51 | + attachment.errors[:content_type].nil? | |
| 52 | + end | |
| 53 | + end | |
| 54 | + | |
| 55 | + def allowed_types_allowed? | |
| 56 | + allow_types?(@allowed_types) | |
| 57 | + end | |
| 58 | + | |
| 59 | + def rejected_types_rejected? | |
| 60 | + not allow_types?(@rejected_types) | |
| 61 | + end | |
| 62 | + end | |
| 63 | + end | |
| 64 | + end | |
| 65 | +end | |
| 66 | + | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/matchers/validate_attachment_presence_matcher.rb
0 → 100644
| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | +module Paperclip | |
| 2 | + module Shoulda | |
| 3 | + module Matchers | |
| 4 | + def validate_attachment_presence name | |
| 5 | + ValidateAttachmentPresenceMatcher.new(name) | |
| 6 | + end | |
| 7 | + | |
| 8 | + class ValidateAttachmentPresenceMatcher | |
| 9 | + def initialize attachment_name | |
| 10 | + @attachment_name = attachment_name | |
| 11 | + end | |
| 12 | + | |
| 13 | + def matches? subject | |
| 14 | + @subject = subject | |
| 15 | + error_when_not_valid? && no_error_when_valid? | |
| 16 | + end | |
| 17 | + | |
| 18 | + def failure_message | |
| 19 | + "Attachment #{@attachment_name} should be required" | |
| 20 | + end | |
| 21 | + | |
| 22 | + def negative_failure_message | |
| 23 | + "Attachment #{@attachment_name} should not be required" | |
| 24 | + end | |
| 25 | + | |
| 26 | + def description | |
| 27 | + "require presence of attachment #{@attachment_name}" | |
| 28 | + end | |
| 29 | + | |
| 30 | + protected | |
| 31 | + | |
| 32 | + def error_when_not_valid? | |
| 33 | + @attachment = @subject.new.send(@attachment_name) | |
| 34 | + @attachment.assign(nil) | |
| 35 | + not @attachment.errors[:presence].nil? | |
| 36 | + end | |
| 37 | + | |
| 38 | + def no_error_when_valid? | |
| 39 | + @file = StringIO.new(".") | |
| 40 | + @attachment = @subject.new.send(@attachment_name) | |
| 41 | + @attachment.assign(@file) | |
| 42 | + @attachment.errors[:presence].nil? | |
| 43 | + end | |
| 44 | + end | |
| 45 | + end | |
| 46 | + end | |
| 47 | +end | |
| 48 | + | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/matchers/validate_attachment_size_matcher.rb
0 → 100644
| ... | ... | @@ -0,0 +1,83 @@ |
| 1 | +module Paperclip | |
| 2 | + module Shoulda | |
| 3 | + module Matchers | |
| 4 | + def validate_attachment_size name | |
| 5 | + ValidateAttachmentSizeMatcher.new(name) | |
| 6 | + end | |
| 7 | + | |
| 8 | + class ValidateAttachmentSizeMatcher | |
| 9 | + def initialize attachment_name | |
| 10 | + @attachment_name = attachment_name | |
| 11 | + @low, @high = 0, (1.0/0) | |
| 12 | + end | |
| 13 | + | |
| 14 | + def less_than size | |
| 15 | + @high = size | |
| 16 | + self | |
| 17 | + end | |
| 18 | + | |
| 19 | + def greater_than size | |
| 20 | + @low = size | |
| 21 | + self | |
| 22 | + end | |
| 23 | + | |
| 24 | + def in range | |
| 25 | + @low, @high = range.first, range.last | |
| 26 | + self | |
| 27 | + end | |
| 28 | + | |
| 29 | + def matches? subject | |
| 30 | + @subject = subject | |
| 31 | + lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high? | |
| 32 | + end | |
| 33 | + | |
| 34 | + def failure_message | |
| 35 | + "Attachment #{@attachment_name} must be between #{@low} and #{@high} bytes" | |
| 36 | + end | |
| 37 | + | |
| 38 | + def negative_failure_message | |
| 39 | + "Attachment #{@attachment_name} cannot be between #{@low} and #{@high} bytes" | |
| 40 | + end | |
| 41 | + | |
| 42 | + def description | |
| 43 | + "validate the size of attachment #{@attachment_name}" | |
| 44 | + end | |
| 45 | + | |
| 46 | + protected | |
| 47 | + | |
| 48 | + def override_method object, method, &replacement | |
| 49 | + (class << object; self; end).class_eval do | |
| 50 | + define_method(method, &replacement) | |
| 51 | + end | |
| 52 | + end | |
| 53 | + | |
| 54 | + def passes_validation_with_size(new_size) | |
| 55 | + file = StringIO.new(".") | |
| 56 | + override_method(file, :size){ new_size } | |
| 57 | + attachment = @subject.new.attachment_for(@attachment_name) | |
| 58 | + attachment.assign(file) | |
| 59 | + attachment.errors[:size].nil? | |
| 60 | + end | |
| 61 | + | |
| 62 | + def lower_than_low? | |
| 63 | + not passes_validation_with_size(@low - 1) | |
| 64 | + end | |
| 65 | + | |
| 66 | + def higher_than_low? | |
| 67 | + passes_validation_with_size(@low + 1) | |
| 68 | + end | |
| 69 | + | |
| 70 | + def lower_than_high? | |
| 71 | + return true if @high == (1.0/0) | |
| 72 | + passes_validation_with_size(@high - 1) | |
| 73 | + end | |
| 74 | + | |
| 75 | + def higher_than_high? | |
| 76 | + return true if @high == (1.0/0) | |
| 77 | + not passes_validation_with_size(@high + 1) | |
| 78 | + end | |
| 79 | + end | |
| 80 | + end | |
| 81 | + end | |
| 82 | +end | |
| 83 | + | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/processor.rb
0 → 100644
| ... | ... | @@ -0,0 +1,49 @@ |
| 1 | +module Paperclip | |
| 2 | + # Paperclip processors allow you to modify attached files when they are | |
| 3 | + # attached in any way you are able. Paperclip itself uses command-line | |
| 4 | + # programs for its included Thumbnail processor, but custom processors | |
| 5 | + # are not required to follow suit. | |
| 6 | + # | |
| 7 | + # Processors are required to be defined inside the Paperclip module and | |
| 8 | + # are also required to be a subclass of Paperclip::Processor. There is | |
| 9 | + # only one method you *must* implement to properly be a subclass: | |
| 10 | + # #make, but #initialize may also be of use. Both methods accept 3 | |
| 11 | + # arguments: the file that will be operated on (which is an instance of | |
| 12 | + # File), a hash of options that were defined in has_attached_file's | |
| 13 | + # style hash, and the Paperclip::Attachment itself. | |
| 14 | + # | |
| 15 | + # All #make needs to return is an instance of File (Tempfile is | |
| 16 | + # acceptable) which contains the results of the processing. | |
| 17 | + # | |
| 18 | + # See Paperclip.run for more information about using command-line | |
| 19 | + # utilities from within Processors. | |
| 20 | + class Processor | |
| 21 | + attr_accessor :file, :options, :attachment | |
| 22 | + | |
| 23 | + def initialize file, options = {}, attachment = nil | |
| 24 | + @file = file | |
| 25 | + @options = options | |
| 26 | + @attachment = attachment | |
| 27 | + end | |
| 28 | + | |
| 29 | + def make | |
| 30 | + end | |
| 31 | + | |
| 32 | + def self.make file, options = {}, attachment = nil | |
| 33 | + new(file, options, attachment).make | |
| 34 | + end | |
| 35 | + end | |
| 36 | + | |
| 37 | + # Due to how ImageMagick handles its image format conversion and how Tempfile | |
| 38 | + # handles its naming scheme, it is necessary to override how Tempfile makes | |
| 39 | + # its names so as to allow for file extensions. Idea taken from the comments | |
| 40 | + # on this blog post: | |
| 41 | + # http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions | |
| 42 | + class Tempfile < ::Tempfile | |
| 43 | + # Replaces Tempfile's +make_tmpname+ with one that honors file extensions. | |
| 44 | + def make_tmpname(basename, n) | |
| 45 | + extension = File.extname(basename) | |
| 46 | + sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension) | |
| 47 | + end | |
| 48 | + end | |
| 49 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/storage.rb
0 → 100644
| ... | ... | @@ -0,0 +1,237 @@ |
| 1 | +module Paperclip | |
| 2 | + module Storage | |
| 3 | + | |
| 4 | + # The default place to store attachments is in the filesystem. Files on the local | |
| 5 | + # filesystem can be very easily served by Apache without requiring a hit to your app. | |
| 6 | + # They also can be processed more easily after they've been saved, as they're just | |
| 7 | + # normal files. There is one Filesystem-specific option for has_attached_file. | |
| 8 | + # * +path+: The location of the repository of attachments on disk. This can (and, in | |
| 9 | + # almost all cases, should) be coordinated with the value of the +url+ option to | |
| 10 | + # allow files to be saved into a place where Apache can serve them without | |
| 11 | + # hitting your app. Defaults to | |
| 12 | + # ":rails_root/public/:attachment/:id/:style/:basename.:extension" | |
| 13 | + # By default this places the files in the app's public directory which can be served | |
| 14 | + # directly. If you are using capistrano for deployment, a good idea would be to | |
| 15 | + # make a symlink to the capistrano-created system directory from inside your app's | |
| 16 | + # public directory. | |
| 17 | + # See Paperclip::Attachment#interpolate for more information on variable interpolaton. | |
| 18 | + # :path => "/var/app/attachments/:class/:id/:style/:basename.:extension" | |
| 19 | + module Filesystem | |
| 20 | + def self.extended base | |
| 21 | + end | |
| 22 | + | |
| 23 | + def exists?(style = default_style) | |
| 24 | + if original_filename | |
| 25 | + File.exist?(path(style)) | |
| 26 | + else | |
| 27 | + false | |
| 28 | + end | |
| 29 | + end | |
| 30 | + | |
| 31 | + # Returns representation of the data of the file assigned to the given | |
| 32 | + # style, in the format most representative of the current storage. | |
| 33 | + def to_file style = default_style | |
| 34 | + @queued_for_write[style] || (File.new(path(style), 'rb') if exists?(style)) | |
| 35 | + end | |
| 36 | + | |
| 37 | + def flush_writes #:nodoc: | |
| 38 | + @queued_for_write.each do |style, file| | |
| 39 | + file.close | |
| 40 | + FileUtils.mkdir_p(File.dirname(path(style))) | |
| 41 | + log("saving #{path(style)}") | |
| 42 | + FileUtils.mv(file.path, path(style)) | |
| 43 | + FileUtils.chmod(0644, path(style)) | |
| 44 | + end | |
| 45 | + @queued_for_write = {} | |
| 46 | + end | |
| 47 | + | |
| 48 | + def flush_deletes #:nodoc: | |
| 49 | + @queued_for_delete.each do |path| | |
| 50 | + begin | |
| 51 | + log("deleting #{path}") | |
| 52 | + FileUtils.rm(path) if File.exist?(path) | |
| 53 | + rescue Errno::ENOENT => e | |
| 54 | + # ignore file-not-found, let everything else pass | |
| 55 | + end | |
| 56 | + begin | |
| 57 | + while(true) | |
| 58 | + path = File.dirname(path) | |
| 59 | + FileUtils.rmdir(path) | |
| 60 | + end | |
| 61 | + rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR | |
| 62 | + # Stop trying to remove parent directories | |
| 63 | + rescue SystemCallError => e | |
| 64 | + log("There was an unexpected error while deleting directories: #{e.class}") | |
| 65 | + # Ignore it | |
| 66 | + end | |
| 67 | + end | |
| 68 | + @queued_for_delete = [] | |
| 69 | + end | |
| 70 | + end | |
| 71 | + | |
| 72 | + # Amazon's S3 file hosting service is a scalable, easy place to store files for | |
| 73 | + # distribution. You can find out more about it at http://aws.amazon.com/s3 | |
| 74 | + # There are a few S3-specific options for has_attached_file: | |
| 75 | + # * +s3_credentials+: Takes a path, a File, or a Hash. The path (or File) must point | |
| 76 | + # to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon | |
| 77 | + # gives you. You can 'environment-space' this just like you do to your | |
| 78 | + # database.yml file, so different environments can use different accounts: | |
| 79 | + # development: | |
| 80 | + # access_key_id: 123... | |
| 81 | + # secret_access_key: 123... | |
| 82 | + # test: | |
| 83 | + # access_key_id: abc... | |
| 84 | + # secret_access_key: abc... | |
| 85 | + # production: | |
| 86 | + # access_key_id: 456... | |
| 87 | + # secret_access_key: 456... | |
| 88 | + # This is not required, however, and the file may simply look like this: | |
| 89 | + # access_key_id: 456... | |
| 90 | + # secret_access_key: 456... | |
| 91 | + # In which case, those access keys will be used in all environments. You can also | |
| 92 | + # put your bucket name in this file, instead of adding it to the code directly. | |
| 93 | + # This is useful when you want the same account but a different bucket for | |
| 94 | + # development versus production. | |
| 95 | + # * +s3_permissions+: This is a String that should be one of the "canned" access | |
| 96 | + # policies that S3 provides (more information can be found here: | |
| 97 | + # http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html#RESTCannedAccessPolicies) | |
| 98 | + # The default for Paperclip is "public-read". | |
| 99 | + # * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either | |
| 100 | + # 'http' or 'https'. Defaults to 'http' when your :s3_permissions are 'public-read' (the | |
| 101 | + # default), and 'https' when your :s3_permissions are anything else. | |
| 102 | + # * +s3_headers+: A hash of headers such as {'Expires' => 1.year.from_now.httpdate} | |
| 103 | + # * +bucket+: This is the name of the S3 bucket that will store your files. Remember | |
| 104 | + # that the bucket must be unique across all of Amazon S3. If the bucket does not exist | |
| 105 | + # Paperclip will attempt to create it. The bucket name will not be interpolated. | |
| 106 | + # You can define the bucket as a Proc if you want to determine it's name at runtime. | |
| 107 | + # Paperclip will call that Proc with attachment as the only argument. | |
| 108 | + # * +s3_host_alias+: The fully-qualified domain name (FQDN) that is the alias to the | |
| 109 | + # S3 domain of your bucket. Used with the :s3_alias_url url interpolation. See the | |
| 110 | + # link in the +url+ entry for more information about S3 domains and buckets. | |
| 111 | + # * +url+: There are three options for the S3 url. You can choose to have the bucket's name | |
| 112 | + # placed domain-style (bucket.s3.amazonaws.com) or path-style (s3.amazonaws.com/bucket). | |
| 113 | + # Lastly, you can specify a CNAME (which requires the CNAME to be specified as | |
| 114 | + # :s3_alias_url. You can read more about CNAMEs and S3 at | |
| 115 | + # http://docs.amazonwebservices.com/AmazonS3/latest/index.html?VirtualHosting.html | |
| 116 | + # Normally, this won't matter in the slightest and you can leave the default (which is | |
| 117 | + # path-style, or :s3_path_url). But in some cases paths don't work and you need to use | |
| 118 | + # the domain-style (:s3_domain_url). Anything else here will be treated like path-style. | |
| 119 | + # NOTE: If you use a CNAME for use with CloudFront, you can NOT specify https as your | |
| 120 | + # :s3_protocol; This is *not supported* by S3/CloudFront. Finally, when using the host | |
| 121 | + # alias, the :bucket parameter is ignored, as the hostname is used as the bucket name | |
| 122 | + # by S3. | |
| 123 | + # * +path+: This is the key under the bucket in which the file will be stored. The | |
| 124 | + # URL will be constructed from the bucket and the path. This is what you will want | |
| 125 | + # to interpolate. Keys should be unique, like filenames, and despite the fact that | |
| 126 | + # S3 (strictly speaking) does not support directories, you can still use a / to | |
| 127 | + # separate parts of your file name. | |
| 128 | + module S3 | |
| 129 | + def self.extended base | |
| 130 | + require 'aws/s3' | |
| 131 | + base.instance_eval do | |
| 132 | + @s3_credentials = parse_credentials(@options[:s3_credentials]) | |
| 133 | + @bucket = @options[:bucket] || @s3_credentials[:bucket] | |
| 134 | + @bucket = @bucket.call(self) if @bucket.is_a?(Proc) | |
| 135 | + @s3_options = @options[:s3_options] || {} | |
| 136 | + @s3_permissions = @options[:s3_permissions] || :public_read | |
| 137 | + @s3_protocol = @options[:s3_protocol] || (@s3_permissions == :public_read ? 'http' : 'https') | |
| 138 | + @s3_headers = @options[:s3_headers] || {} | |
| 139 | + @s3_host_alias = @options[:s3_host_alias] | |
| 140 | + @url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/) | |
| 141 | + AWS::S3::Base.establish_connection!( @s3_options.merge( | |
| 142 | + :access_key_id => @s3_credentials[:access_key_id], | |
| 143 | + :secret_access_key => @s3_credentials[:secret_access_key] | |
| 144 | + )) | |
| 145 | + end | |
| 146 | + Paperclip.interpolates(:s3_alias_url) do |attachment, style| | |
| 147 | + "#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}" | |
| 148 | + end | |
| 149 | + Paperclip.interpolates(:s3_path_url) do |attachment, style| | |
| 150 | + "#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}" | |
| 151 | + end | |
| 152 | + Paperclip.interpolates(:s3_domain_url) do |attachment, style| | |
| 153 | + "#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}" | |
| 154 | + end | |
| 155 | + end | |
| 156 | + | |
| 157 | + def bucket_name | |
| 158 | + @bucket | |
| 159 | + end | |
| 160 | + | |
| 161 | + def s3_host_alias | |
| 162 | + @s3_host_alias | |
| 163 | + end | |
| 164 | + | |
| 165 | + def parse_credentials creds | |
| 166 | + creds = find_credentials(creds).stringify_keys | |
| 167 | + (creds[RAILS_ENV] || creds).symbolize_keys | |
| 168 | + end | |
| 169 | + | |
| 170 | + def exists?(style = default_style) | |
| 171 | + if original_filename | |
| 172 | + AWS::S3::S3Object.exists?(path(style), bucket_name) | |
| 173 | + else | |
| 174 | + false | |
| 175 | + end | |
| 176 | + end | |
| 177 | + | |
| 178 | + def s3_protocol | |
| 179 | + @s3_protocol | |
| 180 | + end | |
| 181 | + | |
| 182 | + # Returns representation of the data of the file assigned to the given | |
| 183 | + # style, in the format most representative of the current storage. | |
| 184 | + def to_file style = default_style | |
| 185 | + return @queued_for_write[style] if @queued_for_write[style] | |
| 186 | + file = Tempfile.new(path(style)) | |
| 187 | + file.write(AWS::S3::S3Object.value(path(style), bucket_name)) | |
| 188 | + file.rewind | |
| 189 | + return file | |
| 190 | + end | |
| 191 | + | |
| 192 | + def flush_writes #:nodoc: | |
| 193 | + @queued_for_write.each do |style, file| | |
| 194 | + begin | |
| 195 | + log("saving #{path(style)}") | |
| 196 | + AWS::S3::S3Object.store(path(style), | |
| 197 | + file, | |
| 198 | + bucket_name, | |
| 199 | + {:content_type => instance_read(:content_type), | |
| 200 | + :access => @s3_permissions, | |
| 201 | + }.merge(@s3_headers)) | |
| 202 | + rescue AWS::S3::ResponseError => e | |
| 203 | + raise | |
| 204 | + end | |
| 205 | + end | |
| 206 | + @queued_for_write = {} | |
| 207 | + end | |
| 208 | + | |
| 209 | + def flush_deletes #:nodoc: | |
| 210 | + @queued_for_delete.each do |path| | |
| 211 | + begin | |
| 212 | + log("deleting #{path}") | |
| 213 | + AWS::S3::S3Object.delete(path, bucket_name) | |
| 214 | + rescue AWS::S3::ResponseError | |
| 215 | + # Ignore this. | |
| 216 | + end | |
| 217 | + end | |
| 218 | + @queued_for_delete = [] | |
| 219 | + end | |
| 220 | + | |
| 221 | + def find_credentials creds | |
| 222 | + case creds | |
| 223 | + when File | |
| 224 | + YAML.load_file(creds.path) | |
| 225 | + when String | |
| 226 | + YAML.load_file(creds) | |
| 227 | + when Hash | |
| 228 | + creds | |
| 229 | + else | |
| 230 | + raise ArgumentError, "Credentials are not a path, file, or hash." | |
| 231 | + end | |
| 232 | + end | |
| 233 | + private :find_credentials | |
| 234 | + | |
| 235 | + end | |
| 236 | + end | |
| 237 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/thumbnail.rb
0 → 100644
| ... | ... | @@ -0,0 +1,73 @@ |
| 1 | +module Paperclip | |
| 2 | + # Handles thumbnailing images that are uploaded. | |
| 3 | + class Thumbnail < Processor | |
| 4 | + | |
| 5 | + attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options, :source_file_options | |
| 6 | + | |
| 7 | + # Creates a Thumbnail object set to work on the +file+ given. It | |
| 8 | + # will attempt to transform the image into one defined by +target_geometry+ | |
| 9 | + # which is a "WxH"-style string. +format+ will be inferred from the +file+ | |
| 10 | + # unless specified. Thumbnail creation will raise no errors unless | |
| 11 | + # +whiny+ is true (which it is, by default. If +convert_options+ is | |
| 12 | + # set, the options will be appended to the convert command upon image conversion | |
| 13 | + def initialize file, options = {}, attachment = nil | |
| 14 | + super | |
| 15 | + geometry = options[:geometry] | |
| 16 | + @file = file | |
| 17 | + @crop = geometry[-1,1] == '#' | |
| 18 | + @target_geometry = Geometry.parse geometry | |
| 19 | + @current_geometry = Geometry.from_file @file | |
| 20 | + @source_file_options = options[:source_file_options] | |
| 21 | + @convert_options = options[:convert_options] | |
| 22 | + @whiny = options[:whiny].nil? ? true : options[:whiny] | |
| 23 | + @format = options[:format] | |
| 24 | + | |
| 25 | + @current_format = File.extname(@file.path) | |
| 26 | + @basename = File.basename(@file.path, @current_format) | |
| 27 | + end | |
| 28 | + | |
| 29 | + # Returns true if the +target_geometry+ is meant to crop. | |
| 30 | + def crop? | |
| 31 | + @crop | |
| 32 | + end | |
| 33 | + | |
| 34 | + # Returns true if the image is meant to make use of additional convert options. | |
| 35 | + def convert_options? | |
| 36 | + not @convert_options.blank? | |
| 37 | + end | |
| 38 | + | |
| 39 | + # Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile | |
| 40 | + # that contains the new image. | |
| 41 | + def make | |
| 42 | + src = @file | |
| 43 | + dst = Tempfile.new([@basename, @format].compact.join(".")) | |
| 44 | + dst.binmode | |
| 45 | + | |
| 46 | + command = <<-end_command | |
| 47 | + #{ source_file_options } | |
| 48 | + "#{ File.expand_path(src.path) }[0]" | |
| 49 | + #{ transformation_command } | |
| 50 | + "#{ File.expand_path(dst.path) }" | |
| 51 | + end_command | |
| 52 | + | |
| 53 | + begin | |
| 54 | + success = Paperclip.run("convert", command.gsub(/\s+/, " ")) | |
| 55 | + rescue PaperclipCommandLineError | |
| 56 | + raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny | |
| 57 | + end | |
| 58 | + | |
| 59 | + dst | |
| 60 | + end | |
| 61 | + | |
| 62 | + # Returns the command ImageMagick's +convert+ needs to transform the image | |
| 63 | + # into the thumbnail. | |
| 64 | + def transformation_command | |
| 65 | + scale, crop = @current_geometry.transformation_to(@target_geometry, crop?) | |
| 66 | + trans = "" | |
| 67 | + trans << " -resize \"#{scale}\"" unless scale.blank? | |
| 68 | + trans << " -crop \"#{crop}\" +repage" if crop | |
| 69 | + trans << " #{convert_options}" if convert_options? | |
| 70 | + trans | |
| 71 | + end | |
| 72 | + end | |
| 73 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/lib/paperclip/upfile.rb
0 → 100644
| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | +module Paperclip | |
| 2 | + # The Upfile module is a convenience module for adding uploaded-file-type methods | |
| 3 | + # to the +File+ class. Useful for testing. | |
| 4 | + # user.avatar = File.new("test/test_avatar.jpg") | |
| 5 | + module Upfile | |
| 6 | + | |
| 7 | + # Infer the MIME-type of the file from the extension. | |
| 8 | + def content_type | |
| 9 | + type = (self.path.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase | |
| 10 | + case type | |
| 11 | + when %r"jpe?g" then "image/jpeg" | |
| 12 | + when %r"tiff?" then "image/tiff" | |
| 13 | + when %r"png", "gif", "bmp" then "image/#{type}" | |
| 14 | + when "txt" then "text/plain" | |
| 15 | + when %r"html?" then "text/html" | |
| 16 | + when "csv", "xml", "css", "js" then "text/#{type}" | |
| 17 | + else "application/x-#{type}" | |
| 18 | + end | |
| 19 | + end | |
| 20 | + | |
| 21 | + # Returns the file's normal name. | |
| 22 | + def original_filename | |
| 23 | + File.basename(self.path) | |
| 24 | + end | |
| 25 | + | |
| 26 | + # Returns the size of the file. | |
| 27 | + def size | |
| 28 | + File.size(self) | |
| 29 | + end | |
| 30 | + end | |
| 31 | +end | |
| 32 | + | |
| 33 | +if defined? StringIO | |
| 34 | + class StringIO | |
| 35 | + attr_accessor :original_filename, :content_type | |
| 36 | + def original_filename | |
| 37 | + @original_filename ||= "stringio.txt" | |
| 38 | + end | |
| 39 | + def content_type | |
| 40 | + @content_type ||= "text/plain" | |
| 41 | + end | |
| 42 | + end | |
| 43 | +end | |
| 44 | + | |
| 45 | +class File #:nodoc: | |
| 46 | + include Paperclip::Upfile | |
| 47 | +end | |
| 48 | + | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/shoulda_macros/paperclip.rb
0 → 100644
| ... | ... | @@ -0,0 +1,68 @@ |
| 1 | +require 'paperclip/matchers' | |
| 2 | + | |
| 3 | +module Paperclip | |
| 4 | + # =Paperclip Shoulda Macros | |
| 5 | + # | |
| 6 | + # These macros are intended for use with shoulda, and will be included into | |
| 7 | + # your tests automatically. All of the macros use the standard shoulda | |
| 8 | + # assumption that the name of the test is based on the name of the model | |
| 9 | + # you're testing (that is, UserTest is the test for the User model), and | |
| 10 | + # will load that class for testing purposes. | |
| 11 | + module Shoulda | |
| 12 | + include Matchers | |
| 13 | + # This will test whether you have defined your attachment correctly by | |
| 14 | + # checking for all the required fields exist after the definition of the | |
| 15 | + # attachment. | |
| 16 | + def should_have_attached_file name | |
| 17 | + klass = self.name.gsub(/Test$/, '').constantize | |
| 18 | + matcher = have_attached_file name | |
| 19 | + should matcher.description do | |
| 20 | + assert_accepts(matcher, klass) | |
| 21 | + end | |
| 22 | + end | |
| 23 | + | |
| 24 | + # Tests for validations on the presence of the attachment. | |
| 25 | + def should_validate_attachment_presence name | |
| 26 | + klass = self.name.gsub(/Test$/, '').constantize | |
| 27 | + matcher = validate_attachment_presence name | |
| 28 | + should matcher.description do | |
| 29 | + assert_accepts(matcher, klass) | |
| 30 | + end | |
| 31 | + end | |
| 32 | + | |
| 33 | + # Tests that you have content_type validations specified. There are two | |
| 34 | + # options, :valid and :invalid. Both accept an array of strings. The | |
| 35 | + # strings should be a list of content types which will pass and fail | |
| 36 | + # validation, respectively. | |
| 37 | + def should_validate_attachment_content_type name, options = {} | |
| 38 | + klass = self.name.gsub(/Test$/, '').constantize | |
| 39 | + valid = [options[:valid]].flatten | |
| 40 | + invalid = [options[:invalid]].flatten | |
| 41 | + matcher = validate_attachment_content_type(name).allowing(valid).rejecting(invalid) | |
| 42 | + should matcher.description do | |
| 43 | + assert_accepts(matcher, klass) | |
| 44 | + end | |
| 45 | + end | |
| 46 | + | |
| 47 | + # Tests to ensure that you have file size validations turned on. You | |
| 48 | + # can pass the same options to this that you can to | |
| 49 | + # validate_attachment_file_size - :less_than, :greater_than, and :in. | |
| 50 | + # :less_than checks that a file is less than a certain size, :greater_than | |
| 51 | + # checks that a file is more than a certain size, and :in takes a Range or | |
| 52 | + # Array which specifies the lower and upper limits of the file size. | |
| 53 | + def should_validate_attachment_size name, options = {} | |
| 54 | + klass = self.name.gsub(/Test$/, '').constantize | |
| 55 | + min = options[:greater_than] || (options[:in] && options[:in].first) || 0 | |
| 56 | + max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0) | |
| 57 | + range = (min..max) | |
| 58 | + matcher = validate_attachment_size(name).in(range) | |
| 59 | + should matcher.description do | |
| 60 | + assert_accepts(matcher, klass) | |
| 61 | + end | |
| 62 | + end | |
| 63 | + end | |
| 64 | +end | |
| 65 | + | |
| 66 | +class Test::Unit::TestCase #:nodoc: | |
| 67 | + extend Paperclip::Shoulda | |
| 68 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/tasks/paperclip_tasks.rake
0 → 100644
| ... | ... | @@ -0,0 +1,79 @@ |
| 1 | +def obtain_class | |
| 2 | + class_name = ENV['CLASS'] || ENV['class'] | |
| 3 | + raise "Must specify CLASS" unless class_name | |
| 4 | + @klass = Object.const_get(class_name) | |
| 5 | +end | |
| 6 | + | |
| 7 | +def obtain_attachments | |
| 8 | + name = ENV['ATTACHMENT'] || ENV['attachment'] | |
| 9 | + raise "Class #{@klass.name} has no attachments specified" unless @klass.respond_to?(:attachment_definitions) | |
| 10 | + if !name.blank? && @klass.attachment_definitions.keys.include?(name) | |
| 11 | + [ name ] | |
| 12 | + else | |
| 13 | + @klass.attachment_definitions.keys | |
| 14 | + end | |
| 15 | +end | |
| 16 | + | |
| 17 | +def for_all_attachments | |
| 18 | + klass = obtain_class | |
| 19 | + names = obtain_attachments | |
| 20 | + ids = klass.connection.select_values(klass.send(:construct_finder_sql, :select => 'id')) | |
| 21 | + | |
| 22 | + ids.each do |id| | |
| 23 | + instance = klass.find(id) | |
| 24 | + names.each do |name| | |
| 25 | + result = if instance.send("#{ name }?") | |
| 26 | + yield(instance, name) | |
| 27 | + else | |
| 28 | + true | |
| 29 | + end | |
| 30 | + print result ? "." : "x"; $stdout.flush | |
| 31 | + end | |
| 32 | + end | |
| 33 | + puts " Done." | |
| 34 | +end | |
| 35 | + | |
| 36 | +namespace :paperclip do | |
| 37 | + desc "Refreshes both metadata and thumbnails." | |
| 38 | + task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"] | |
| 39 | + | |
| 40 | + namespace :refresh do | |
| 41 | + desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)." | |
| 42 | + task :thumbnails => :environment do | |
| 43 | + errors = [] | |
| 44 | + for_all_attachments do |instance, name| | |
| 45 | + result = instance.send(name).reprocess! | |
| 46 | + errors << [instance.id, instance.errors] unless instance.errors.blank? | |
| 47 | + result | |
| 48 | + end | |
| 49 | + errors.each{|e| puts "#{e.first}: #{e.last.full_messages.inspect}" } | |
| 50 | + end | |
| 51 | + | |
| 52 | + desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)." | |
| 53 | + task :metadata => :environment do | |
| 54 | + for_all_attachments do |instance, name| | |
| 55 | + if file = instance.send(name).to_file | |
| 56 | + instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip) | |
| 57 | + instance.send("#{name}_content_type=", file.content_type.strip) | |
| 58 | + instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size") | |
| 59 | + instance.save(false) | |
| 60 | + else | |
| 61 | + true | |
| 62 | + end | |
| 63 | + end | |
| 64 | + end | |
| 65 | + end | |
| 66 | + | |
| 67 | + desc "Cleans out invalid attachments. Useful after you've added new validations." | |
| 68 | + task :clean => :environment do | |
| 69 | + for_all_attachments do |instance, name| | |
| 70 | + instance.send(name).send(:validate) | |
| 71 | + if instance.send(name).valid? | |
| 72 | + true | |
| 73 | + else | |
| 74 | + instance.send("#{name}=", nil) | |
| 75 | + instance.save | |
| 76 | + end | |
| 77 | + end | |
| 78 | + end | |
| 79 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/attachment_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,779 @@ |
| 1 | +# encoding: utf-8 | |
| 2 | +require 'test/helper' | |
| 3 | + | |
| 4 | +class Dummy | |
| 5 | + # This is a dummy class | |
| 6 | +end | |
| 7 | + | |
| 8 | +class AttachmentTest < Test::Unit::TestCase | |
| 9 | + should "return the path based on the url by default" do | |
| 10 | + @attachment = attachment :url => "/:class/:id/:basename" | |
| 11 | + @model = @attachment.instance | |
| 12 | + @model.id = 1234 | |
| 13 | + @model.avatar_file_name = "fake.jpg" | |
| 14 | + assert_equal "#{RAILS_ROOT}/public/fake_models/1234/fake", @attachment.path | |
| 15 | + end | |
| 16 | + | |
| 17 | + should "call a proc sent to check_guard" do | |
| 18 | + @dummy = Dummy.new | |
| 19 | + @dummy.expects(:one).returns(:one) | |
| 20 | + assert_equal :one, @dummy.avatar.send(:check_guard, lambda{|x| x.one }) | |
| 21 | + end | |
| 22 | + | |
| 23 | + should "call a method name sent to check_guard" do | |
| 24 | + @dummy = Dummy.new | |
| 25 | + @dummy.expects(:one).returns(:one) | |
| 26 | + assert_equal :one, @dummy.avatar.send(:check_guard, :one) | |
| 27 | + end | |
| 28 | + | |
| 29 | + context "Attachment default_options" do | |
| 30 | + setup do | |
| 31 | + rebuild_model | |
| 32 | + @old_default_options = Paperclip::Attachment.default_options.dup | |
| 33 | + @new_default_options = @old_default_options.merge({ | |
| 34 | + :path => "argle/bargle", | |
| 35 | + :url => "fooferon", | |
| 36 | + :default_url => "not here.png" | |
| 37 | + }) | |
| 38 | + end | |
| 39 | + | |
| 40 | + teardown do | |
| 41 | + Paperclip::Attachment.default_options.merge! @old_default_options | |
| 42 | + end | |
| 43 | + | |
| 44 | + should "be overrideable" do | |
| 45 | + Paperclip::Attachment.default_options.merge!(@new_default_options) | |
| 46 | + @new_default_options.keys.each do |key| | |
| 47 | + assert_equal @new_default_options[key], | |
| 48 | + Paperclip::Attachment.default_options[key] | |
| 49 | + end | |
| 50 | + end | |
| 51 | + | |
| 52 | + context "without an Attachment" do | |
| 53 | + setup do | |
| 54 | + @dummy = Dummy.new | |
| 55 | + end | |
| 56 | + | |
| 57 | + should "return false when asked exists?" do | |
| 58 | + assert !@dummy.avatar.exists? | |
| 59 | + end | |
| 60 | + end | |
| 61 | + | |
| 62 | + context "on an Attachment" do | |
| 63 | + setup do | |
| 64 | + @dummy = Dummy.new | |
| 65 | + @attachment = @dummy.avatar | |
| 66 | + end | |
| 67 | + | |
| 68 | + Paperclip::Attachment.default_options.keys.each do |key| | |
| 69 | + should "be the default_options for #{key}" do | |
| 70 | + assert_equal @old_default_options[key], | |
| 71 | + @attachment.instance_variable_get("@#{key}"), | |
| 72 | + key | |
| 73 | + end | |
| 74 | + end | |
| 75 | + | |
| 76 | + context "when redefined" do | |
| 77 | + setup do | |
| 78 | + Paperclip::Attachment.default_options.merge!(@new_default_options) | |
| 79 | + @dummy = Dummy.new | |
| 80 | + @attachment = @dummy.avatar | |
| 81 | + end | |
| 82 | + | |
| 83 | + Paperclip::Attachment.default_options.keys.each do |key| | |
| 84 | + should "be the new default_options for #{key}" do | |
| 85 | + assert_equal @new_default_options[key], | |
| 86 | + @attachment.instance_variable_get("@#{key}"), | |
| 87 | + key | |
| 88 | + end | |
| 89 | + end | |
| 90 | + end | |
| 91 | + end | |
| 92 | + end | |
| 93 | + | |
| 94 | + context "An attachment with similarly named interpolations" do | |
| 95 | + setup do | |
| 96 | + rebuild_model :path => ":id.omg/:id-bbq/:idwhat/:id_partition.wtf" | |
| 97 | + @dummy = Dummy.new | |
| 98 | + @dummy.stubs(:id).returns(1024) | |
| 99 | + @file = File.new(File.join(File.dirname(__FILE__), | |
| 100 | + "fixtures", | |
| 101 | + "5k.png"), 'rb') | |
| 102 | + @dummy.avatar = @file | |
| 103 | + end | |
| 104 | + | |
| 105 | + teardown { @file.close } | |
| 106 | + | |
| 107 | + should "make sure that they are interpolated correctly" do | |
| 108 | + assert_equal "1024.omg/1024-bbq/1024what/000/001/024.wtf", @dummy.avatar.path | |
| 109 | + end | |
| 110 | + end | |
| 111 | + | |
| 112 | + context "An attachment with a :rails_env interpolation" do | |
| 113 | + setup do | |
| 114 | + @rails_env = "blah" | |
| 115 | + @id = 1024 | |
| 116 | + rebuild_model :path => ":rails_env/:id.png" | |
| 117 | + @dummy = Dummy.new | |
| 118 | + @dummy.stubs(:id).returns(@id) | |
| 119 | + @file = StringIO.new(".") | |
| 120 | + @dummy.avatar = @file | |
| 121 | + end | |
| 122 | + | |
| 123 | + should "return the proper path" do | |
| 124 | + temporary_rails_env(@rails_env) { | |
| 125 | + assert_equal "#{@rails_env}/#{@id}.png", @dummy.avatar.path | |
| 126 | + } | |
| 127 | + end | |
| 128 | + end | |
| 129 | + | |
| 130 | + context "An attachment with a default style and an extension interpolation" do | |
| 131 | + setup do | |
| 132 | + @attachment = attachment :path => ":basename.:extension", | |
| 133 | + :styles => { :default => ["100x100", :png] }, | |
| 134 | + :default_style => :default | |
| 135 | + @file = StringIO.new("...") | |
| 136 | + @file.expects(:original_filename).returns("file.jpg") | |
| 137 | + end | |
| 138 | + should "return the right extension for the path" do | |
| 139 | + @attachment.assign(@file) | |
| 140 | + assert_equal "file.png", @attachment.path | |
| 141 | + end | |
| 142 | + end | |
| 143 | + | |
| 144 | + context "An attachment with :convert_options" do | |
| 145 | + setup do | |
| 146 | + rebuild_model :styles => { | |
| 147 | + :thumb => "100x100", | |
| 148 | + :large => "400x400" | |
| 149 | + }, | |
| 150 | + :convert_options => { | |
| 151 | + :all => "-do_stuff", | |
| 152 | + :thumb => "-thumbnailize" | |
| 153 | + } | |
| 154 | + @dummy = Dummy.new | |
| 155 | + @dummy.avatar | |
| 156 | + end | |
| 157 | + | |
| 158 | + should "report the correct options when sent #extra_options_for(:thumb)" do | |
| 159 | + assert_equal "-thumbnailize -do_stuff", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect | |
| 160 | + end | |
| 161 | + | |
| 162 | + should "report the correct options when sent #extra_options_for(:large)" do | |
| 163 | + assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large) | |
| 164 | + end | |
| 165 | + | |
| 166 | + before_should "call extra_options_for(:thumb/:large)" do | |
| 167 | + Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb) | |
| 168 | + Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large) | |
| 169 | + end | |
| 170 | + end | |
| 171 | + | |
| 172 | + context "An attachment with :convert_options that is a proc" do | |
| 173 | + setup do | |
| 174 | + rebuild_model :styles => { | |
| 175 | + :thumb => "100x100", | |
| 176 | + :large => "400x400" | |
| 177 | + }, | |
| 178 | + :convert_options => { | |
| 179 | + :all => lambda{|i| i.all }, | |
| 180 | + :thumb => lambda{|i| i.thumb } | |
| 181 | + } | |
| 182 | + Dummy.class_eval do | |
| 183 | + def all; "-all"; end | |
| 184 | + def thumb; "-thumb"; end | |
| 185 | + end | |
| 186 | + @dummy = Dummy.new | |
| 187 | + @dummy.avatar | |
| 188 | + end | |
| 189 | + | |
| 190 | + should "report the correct options when sent #extra_options_for(:thumb)" do | |
| 191 | + assert_equal "-thumb -all", @dummy.avatar.send(:extra_options_for, :thumb), @dummy.avatar.convert_options.inspect | |
| 192 | + end | |
| 193 | + | |
| 194 | + should "report the correct options when sent #extra_options_for(:large)" do | |
| 195 | + assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large) | |
| 196 | + end | |
| 197 | + | |
| 198 | + before_should "call extra_options_for(:thumb/:large)" do | |
| 199 | + Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb) | |
| 200 | + Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large) | |
| 201 | + end | |
| 202 | + end | |
| 203 | + | |
| 204 | + context "An attachment with :path that is a proc" do | |
| 205 | + setup do | |
| 206 | + rebuild_model :path => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" } | |
| 207 | + | |
| 208 | + @file = File.new(File.join(File.dirname(__FILE__), | |
| 209 | + "fixtures", | |
| 210 | + "5k.png"), 'rb') | |
| 211 | + @dummyA = Dummy.new(:other => 'a') | |
| 212 | + @dummyA.avatar = @file | |
| 213 | + @dummyB = Dummy.new(:other => 'b') | |
| 214 | + @dummyB.avatar = @file | |
| 215 | + end | |
| 216 | + | |
| 217 | + teardown { @file.close } | |
| 218 | + | |
| 219 | + should "return correct path" do | |
| 220 | + assert_equal "path/a.png", @dummyA.avatar.path | |
| 221 | + assert_equal "path/b.png", @dummyB.avatar.path | |
| 222 | + end | |
| 223 | + end | |
| 224 | + | |
| 225 | + context "An attachment with :styles that is a proc" do | |
| 226 | + setup do | |
| 227 | + rebuild_model :styles => lambda{ |attachment| {:thumb => "50x50#", :large => "400x400"} } | |
| 228 | + | |
| 229 | + @attachment = Dummy.new.avatar | |
| 230 | + end | |
| 231 | + | |
| 232 | + should "have the correct geometry" do | |
| 233 | + assert_equal "50x50#", @attachment.styles[:thumb][:geometry] | |
| 234 | + end | |
| 235 | + end | |
| 236 | + | |
| 237 | + context "An attachment with :url that is a proc" do | |
| 238 | + setup do | |
| 239 | + rebuild_model :url => lambda{ |attachment| "path/#{attachment.instance.other}.:extension" } | |
| 240 | + | |
| 241 | + @file = File.new(File.join(File.dirname(__FILE__), | |
| 242 | + "fixtures", | |
| 243 | + "5k.png"), 'rb') | |
| 244 | + @dummyA = Dummy.new(:other => 'a') | |
| 245 | + @dummyA.avatar = @file | |
| 246 | + @dummyB = Dummy.new(:other => 'b') | |
| 247 | + @dummyB.avatar = @file | |
| 248 | + end | |
| 249 | + | |
| 250 | + teardown { @file.close } | |
| 251 | + | |
| 252 | + should "return correct url" do | |
| 253 | + assert_equal "path/a.png", @dummyA.avatar.url(:original, false) | |
| 254 | + assert_equal "path/b.png", @dummyB.avatar.url(:original, false) | |
| 255 | + end | |
| 256 | + end | |
| 257 | + | |
| 258 | + geometry_specs = [ | |
| 259 | + [ lambda{|z| "50x50#" }, :png ], | |
| 260 | + lambda{|z| "50x50#" }, | |
| 261 | + { :geometry => lambda{|z| "50x50#" } } | |
| 262 | + ] | |
| 263 | + geometry_specs.each do |geometry_spec| | |
| 264 | + context "An attachment geometry like #{geometry_spec}" do | |
| 265 | + setup do | |
| 266 | + rebuild_model :styles => { :normal => geometry_spec } | |
| 267 | + @attachment = Dummy.new.avatar | |
| 268 | + end | |
| 269 | + | |
| 270 | + should "not run the procs immediately" do | |
| 271 | + assert_kind_of Proc, @attachment.styles[:normal][:geometry] | |
| 272 | + end | |
| 273 | + | |
| 274 | + context "when assigned" do | |
| 275 | + setup do | |
| 276 | + @file = StringIO.new(".") | |
| 277 | + @attachment.assign(@file) | |
| 278 | + end | |
| 279 | + | |
| 280 | + should "have the correct geometry" do | |
| 281 | + assert_equal "50x50#", @attachment.styles[:normal][:geometry] | |
| 282 | + end | |
| 283 | + end | |
| 284 | + end | |
| 285 | + end | |
| 286 | + | |
| 287 | + context "An attachment with both 'normal' and hash-style styles" do | |
| 288 | + setup do | |
| 289 | + rebuild_model :styles => { | |
| 290 | + :normal => ["50x50#", :png], | |
| 291 | + :hash => { :geometry => "50x50#", :format => :png } | |
| 292 | + } | |
| 293 | + @dummy = Dummy.new | |
| 294 | + @attachment = @dummy.avatar | |
| 295 | + end | |
| 296 | + | |
| 297 | + [:processors, :whiny, :convert_options, :geometry, :format].each do |field| | |
| 298 | + should "have the same #{field} field" do | |
| 299 | + assert_equal @attachment.styles[:normal][field], @attachment.styles[:hash][field] | |
| 300 | + end | |
| 301 | + end | |
| 302 | + end | |
| 303 | + | |
| 304 | + context "An attachment with :processors that is a proc" do | |
| 305 | + setup do | |
| 306 | + rebuild_model :styles => { :normal => '' }, :processors => lambda { |a| [ :test ] } | |
| 307 | + @attachment = Dummy.new.avatar | |
| 308 | + end | |
| 309 | + | |
| 310 | + should "not run the proc immediately" do | |
| 311 | + assert_kind_of Proc, @attachment.styles[:normal][:processors] | |
| 312 | + end | |
| 313 | + | |
| 314 | + context "when assigned" do | |
| 315 | + setup do | |
| 316 | + @attachment.assign(StringIO.new(".")) | |
| 317 | + end | |
| 318 | + | |
| 319 | + should "have the correct processors" do | |
| 320 | + assert_equal [ :test ], @attachment.styles[:normal][:processors] | |
| 321 | + end | |
| 322 | + end | |
| 323 | + end | |
| 324 | + | |
| 325 | + context "An attachment with erroring processor" do | |
| 326 | + setup do | |
| 327 | + rebuild_model :processor => [:thumbnail], :styles => { :small => '' }, :whiny_thumbnails => true | |
| 328 | + @dummy = Dummy.new | |
| 329 | + Paperclip::Thumbnail.expects(:make).raises(Paperclip::PaperclipError, "cannot be processed.") | |
| 330 | + @file = StringIO.new("...") | |
| 331 | + @file.stubs(:to_tempfile).returns(@file) | |
| 332 | + @dummy.avatar = @file | |
| 333 | + end | |
| 334 | + | |
| 335 | + should "correctly forward processing error message to the instance" do | |
| 336 | + @dummy.valid? | |
| 337 | + assert_contains @dummy.errors.full_messages, "Avatar cannot be processed." | |
| 338 | + end | |
| 339 | + end | |
| 340 | + | |
| 341 | + context "An attachment with multiple processors" do | |
| 342 | + setup do | |
| 343 | + class Paperclip::Test < Paperclip::Processor; end | |
| 344 | + @style_params = { :once => {:one => 1, :two => 2} } | |
| 345 | + rebuild_model :processors => [:thumbnail, :test], :styles => @style_params | |
| 346 | + @dummy = Dummy.new | |
| 347 | + @file = StringIO.new("...") | |
| 348 | + @file.stubs(:to_tempfile).returns(@file) | |
| 349 | + Paperclip::Test.stubs(:make).returns(@file) | |
| 350 | + Paperclip::Thumbnail.stubs(:make).returns(@file) | |
| 351 | + end | |
| 352 | + | |
| 353 | + context "when assigned" do | |
| 354 | + setup { @dummy.avatar = @file } | |
| 355 | + | |
| 356 | + before_should "call #make on all specified processors" do | |
| 357 | + expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""}) | |
| 358 | + Paperclip::Thumbnail.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file) | |
| 359 | + Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file) | |
| 360 | + end | |
| 361 | + | |
| 362 | + before_should "call #make with attachment passed as third argument" do | |
| 363 | + expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""}) | |
| 364 | + Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file) | |
| 365 | + end | |
| 366 | + end | |
| 367 | + end | |
| 368 | + | |
| 369 | + context "An attachment with no processors defined" do | |
| 370 | + setup do | |
| 371 | + rebuild_model :processors => [], :styles => {:something => 1} | |
| 372 | + @dummy = Dummy.new | |
| 373 | + @file = StringIO.new("...") | |
| 374 | + end | |
| 375 | + should "raise when assigned to" do | |
| 376 | + assert_raises(RuntimeError){ @dummy.avatar = @file } | |
| 377 | + end | |
| 378 | + end | |
| 379 | + | |
| 380 | + context "Assigning an attachment with post_process hooks" do | |
| 381 | + setup do | |
| 382 | + rebuild_model :styles => { :something => "100x100#" } | |
| 383 | + Dummy.class_eval do | |
| 384 | + before_avatar_post_process :do_before_avatar | |
| 385 | + after_avatar_post_process :do_after_avatar | |
| 386 | + before_post_process :do_before_all | |
| 387 | + after_post_process :do_after_all | |
| 388 | + def do_before_avatar; end | |
| 389 | + def do_after_avatar; end | |
| 390 | + def do_before_all; end | |
| 391 | + def do_after_all; end | |
| 392 | + end | |
| 393 | + @file = StringIO.new(".") | |
| 394 | + @file.stubs(:to_tempfile).returns(@file) | |
| 395 | + @dummy = Dummy.new | |
| 396 | + Paperclip::Thumbnail.stubs(:make).returns(@file) | |
| 397 | + @attachment = @dummy.avatar | |
| 398 | + end | |
| 399 | + | |
| 400 | + should "call the defined callbacks when assigned" do | |
| 401 | + @dummy.expects(:do_before_avatar).with() | |
| 402 | + @dummy.expects(:do_after_avatar).with() | |
| 403 | + @dummy.expects(:do_before_all).with() | |
| 404 | + @dummy.expects(:do_after_all).with() | |
| 405 | + Paperclip::Thumbnail.expects(:make).returns(@file) | |
| 406 | + @dummy.avatar = @file | |
| 407 | + end | |
| 408 | + | |
| 409 | + should "not cancel the processing if a before_post_process returns nil" do | |
| 410 | + @dummy.expects(:do_before_avatar).with().returns(nil) | |
| 411 | + @dummy.expects(:do_after_avatar).with() | |
| 412 | + @dummy.expects(:do_before_all).with().returns(nil) | |
| 413 | + @dummy.expects(:do_after_all).with() | |
| 414 | + Paperclip::Thumbnail.expects(:make).returns(@file) | |
| 415 | + @dummy.avatar = @file | |
| 416 | + end | |
| 417 | + | |
| 418 | + should "cancel the processing if a before_post_process returns false" do | |
| 419 | + @dummy.expects(:do_before_avatar).never | |
| 420 | + @dummy.expects(:do_after_avatar).never | |
| 421 | + @dummy.expects(:do_before_all).with().returns(false) | |
| 422 | + @dummy.expects(:do_after_all).never | |
| 423 | + Paperclip::Thumbnail.expects(:make).never | |
| 424 | + @dummy.avatar = @file | |
| 425 | + end | |
| 426 | + | |
| 427 | + should "cancel the processing if a before_avatar_post_process returns false" do | |
| 428 | + @dummy.expects(:do_before_avatar).with().returns(false) | |
| 429 | + @dummy.expects(:do_after_avatar).never | |
| 430 | + @dummy.expects(:do_before_all).with().returns(true) | |
| 431 | + @dummy.expects(:do_after_all).never | |
| 432 | + Paperclip::Thumbnail.expects(:make).never | |
| 433 | + @dummy.avatar = @file | |
| 434 | + end | |
| 435 | + end | |
| 436 | + | |
| 437 | + context "Assigning an attachment" do | |
| 438 | + setup do | |
| 439 | + rebuild_model :styles => { :something => "100x100#" } | |
| 440 | + @file = StringIO.new(".") | |
| 441 | + @file.expects(:original_filename).returns("5k.png\n\n") | |
| 442 | + @file.expects(:content_type).returns("image/png\n\n") | |
| 443 | + @file.stubs(:to_tempfile).returns(@file) | |
| 444 | + @dummy = Dummy.new | |
| 445 | + Paperclip::Thumbnail.expects(:make).returns(@file) | |
| 446 | + @dummy.expects(:run_callbacks).with(:before_avatar_post_process, {:original => @file}) | |
| 447 | + @dummy.expects(:run_callbacks).with(:before_post_process, {:original => @file}) | |
| 448 | + @dummy.expects(:run_callbacks).with(:after_avatar_post_process, {:original => @file, :something => @file}) | |
| 449 | + @dummy.expects(:run_callbacks).with(:after_post_process, {:original => @file, :something => @file}) | |
| 450 | + @attachment = @dummy.avatar | |
| 451 | + @dummy.avatar = @file | |
| 452 | + end | |
| 453 | + | |
| 454 | + should "strip whitespace from original_filename field" do | |
| 455 | + assert_equal "5k.png", @dummy.avatar.original_filename | |
| 456 | + end | |
| 457 | + | |
| 458 | + should "strip whitespace from content_type field" do | |
| 459 | + assert_equal "image/png", @dummy.avatar.instance.avatar_content_type | |
| 460 | + end | |
| 461 | + end | |
| 462 | + | |
| 463 | + context "Attachment with strange letters" do | |
| 464 | + setup do | |
| 465 | + rebuild_model | |
| 466 | + | |
| 467 | + @not_file = mock | |
| 468 | + @tempfile = mock | |
| 469 | + @not_file.stubs(:nil?).returns(false) | |
| 470 | + @not_file.expects(:size).returns(10) | |
| 471 | + @tempfile.expects(:size).returns(10) | |
| 472 | + @not_file.expects(:to_tempfile).returns(@tempfile) | |
| 473 | + @not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n") | |
| 474 | + @not_file.expects(:content_type).returns("image/png\r\n") | |
| 475 | + | |
| 476 | + @dummy = Dummy.new | |
| 477 | + @attachment = @dummy.avatar | |
| 478 | + @attachment.expects(:valid_assignment?).with(@not_file).returns(true) | |
| 479 | + @attachment.expects(:queue_existing_for_delete) | |
| 480 | + @attachment.expects(:post_process) | |
| 481 | + @attachment.expects(:valid?).returns(true) | |
| 482 | + @attachment.expects(:validate) | |
| 483 | + @dummy.avatar = @not_file | |
| 484 | + end | |
| 485 | + | |
| 486 | + should "remove strange letters and replace with underscore (_)" do | |
| 487 | + assert_equal "sheep_say_b_.png", @dummy.avatar.original_filename | |
| 488 | + end | |
| 489 | + | |
| 490 | + end | |
| 491 | + | |
| 492 | + context "An attachment" do | |
| 493 | + setup do | |
| 494 | + @old_defaults = Paperclip::Attachment.default_options.dup | |
| 495 | + Paperclip::Attachment.default_options.merge!({ | |
| 496 | + :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 497 | + }) | |
| 498 | + FileUtils.rm_rf("tmp") | |
| 499 | + rebuild_model | |
| 500 | + @instance = Dummy.new | |
| 501 | + @attachment = Paperclip::Attachment.new(:avatar, @instance) | |
| 502 | + @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | |
| 503 | + end | |
| 504 | + | |
| 505 | + teardown do | |
| 506 | + @file.close | |
| 507 | + Paperclip::Attachment.default_options.merge!(@old_defaults) | |
| 508 | + end | |
| 509 | + | |
| 510 | + should "raise if there are not the correct columns when you try to assign" do | |
| 511 | + @other_attachment = Paperclip::Attachment.new(:not_here, @instance) | |
| 512 | + assert_raises(Paperclip::PaperclipError) do | |
| 513 | + @other_attachment.assign(@file) | |
| 514 | + end | |
| 515 | + end | |
| 516 | + | |
| 517 | + should "return its default_url when no file assigned" do | |
| 518 | + assert @attachment.to_file.nil? | |
| 519 | + assert_equal "/avatars/original/missing.png", @attachment.url | |
| 520 | + assert_equal "/avatars/blah/missing.png", @attachment.url(:blah) | |
| 521 | + end | |
| 522 | + | |
| 523 | + should "return nil as path when no file assigned" do | |
| 524 | + assert @attachment.to_file.nil? | |
| 525 | + assert_equal nil, @attachment.path | |
| 526 | + assert_equal nil, @attachment.path(:blah) | |
| 527 | + end | |
| 528 | + | |
| 529 | + context "with a file assigned in the database" do | |
| 530 | + setup do | |
| 531 | + @attachment.stubs(:instance_read).with(:file_name).returns("5k.png") | |
| 532 | + @attachment.stubs(:instance_read).with(:content_type).returns("image/png") | |
| 533 | + @attachment.stubs(:instance_read).with(:file_size).returns(12345) | |
| 534 | + now = Time.now | |
| 535 | + Time.stubs(:now).returns(now) | |
| 536 | + @attachment.stubs(:instance_read).with(:updated_at).returns(Time.now) | |
| 537 | + end | |
| 538 | + | |
| 539 | + should "return a correct url even if the file does not exist" do | |
| 540 | + assert_nil @attachment.to_file | |
| 541 | + assert_match %r{^/system/avatars/#{@instance.id}/blah/5k\.png}, @attachment.url(:blah) | |
| 542 | + end | |
| 543 | + | |
| 544 | + should "make sure the updated_at mtime is in the url if it is defined" do | |
| 545 | + assert_match %r{#{Time.now.to_i}$}, @attachment.url(:blah) | |
| 546 | + end | |
| 547 | + | |
| 548 | + should "make sure the updated_at mtime is NOT in the url if false is passed to the url method" do | |
| 549 | + assert_no_match %r{#{Time.now.to_i}$}, @attachment.url(:blah, false) | |
| 550 | + end | |
| 551 | + | |
| 552 | + context "with the updated_at field removed" do | |
| 553 | + setup do | |
| 554 | + @attachment.stubs(:instance_read).with(:updated_at).returns(nil) | |
| 555 | + end | |
| 556 | + | |
| 557 | + should "only return the url without the updated_at when sent #url" do | |
| 558 | + assert_match "/avatars/#{@instance.id}/blah/5k.png", @attachment.url(:blah) | |
| 559 | + end | |
| 560 | + end | |
| 561 | + | |
| 562 | + should "return the proper path when filename has a single .'s" do | |
| 563 | + assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.png"), File.expand_path(@attachment.path) | |
| 564 | + end | |
| 565 | + | |
| 566 | + should "return the proper path when filename has multiple .'s" do | |
| 567 | + @attachment.stubs(:instance_read).with(:file_name).returns("5k.old.png") | |
| 568 | + assert_equal File.expand_path("./test/../tmp/avatars/dummies/original/#{@instance.id}/5k.old.png"), File.expand_path(@attachment.path) | |
| 569 | + end | |
| 570 | + | |
| 571 | + context "when expecting three styles" do | |
| 572 | + setup do | |
| 573 | + styles = {:styles => { :large => ["400x400", :png], | |
| 574 | + :medium => ["100x100", :gif], | |
| 575 | + :small => ["32x32#", :jpg]}} | |
| 576 | + @attachment = Paperclip::Attachment.new(:avatar, | |
| 577 | + @instance, | |
| 578 | + styles) | |
| 579 | + end | |
| 580 | + | |
| 581 | + context "and assigned a file" do | |
| 582 | + setup do | |
| 583 | + now = Time.now | |
| 584 | + Time.stubs(:now).returns(now) | |
| 585 | + @attachment.assign(@file) | |
| 586 | + end | |
| 587 | + | |
| 588 | + should "be dirty" do | |
| 589 | + assert @attachment.dirty? | |
| 590 | + end | |
| 591 | + | |
| 592 | + context "and saved" do | |
| 593 | + setup do | |
| 594 | + @attachment.save | |
| 595 | + end | |
| 596 | + | |
| 597 | + should "return the real url" do | |
| 598 | + file = @attachment.to_file | |
| 599 | + assert file | |
| 600 | + assert_match %r{^/system/avatars/#{@instance.id}/original/5k\.png}, @attachment.url | |
| 601 | + assert_match %r{^/system/avatars/#{@instance.id}/small/5k\.jpg}, @attachment.url(:small) | |
| 602 | + file.close | |
| 603 | + end | |
| 604 | + | |
| 605 | + should "commit the files to disk" do | |
| 606 | + [:large, :medium, :small].each do |style| | |
| 607 | + io = @attachment.to_file(style) | |
| 608 | + assert File.exists?(io) | |
| 609 | + assert ! io.is_a?(::Tempfile) | |
| 610 | + io.close | |
| 611 | + end | |
| 612 | + end | |
| 613 | + | |
| 614 | + should "save the files as the right formats and sizes" do | |
| 615 | + [[:large, 400, 61, "PNG"], | |
| 616 | + [:medium, 100, 15, "GIF"], | |
| 617 | + [:small, 32, 32, "JPEG"]].each do |style| | |
| 618 | + cmd = %Q[identify -format "%w %h %b %m" "#{@attachment.path(style.first)}"] | |
| 619 | + out = `#{cmd}` | |
| 620 | + width, height, size, format = out.split(" ") | |
| 621 | + assert_equal style[1].to_s, width.to_s | |
| 622 | + assert_equal style[2].to_s, height.to_s | |
| 623 | + assert_equal style[3].to_s, format.to_s | |
| 624 | + end | |
| 625 | + end | |
| 626 | + | |
| 627 | + should "still have its #file attribute not be nil" do | |
| 628 | + assert ! (file = @attachment.to_file).nil? | |
| 629 | + file.close | |
| 630 | + end | |
| 631 | + | |
| 632 | + context "and trying to delete" do | |
| 633 | + setup do | |
| 634 | + @existing_names = @attachment.styles.keys.collect do |style| | |
| 635 | + @attachment.path(style) | |
| 636 | + end | |
| 637 | + end | |
| 638 | + | |
| 639 | + should "delete the files after assigning nil" do | |
| 640 | + @attachment.expects(:instance_write).with(:file_name, nil) | |
| 641 | + @attachment.expects(:instance_write).with(:content_type, nil) | |
| 642 | + @attachment.expects(:instance_write).with(:file_size, nil) | |
| 643 | + @attachment.expects(:instance_write).with(:updated_at, nil) | |
| 644 | + @attachment.assign nil | |
| 645 | + @attachment.save | |
| 646 | + @existing_names.each{|f| assert ! File.exists?(f) } | |
| 647 | + end | |
| 648 | + | |
| 649 | + should "delete the files when you call #clear and #save" do | |
| 650 | + @attachment.expects(:instance_write).with(:file_name, nil) | |
| 651 | + @attachment.expects(:instance_write).with(:content_type, nil) | |
| 652 | + @attachment.expects(:instance_write).with(:file_size, nil) | |
| 653 | + @attachment.expects(:instance_write).with(:updated_at, nil) | |
| 654 | + @attachment.clear | |
| 655 | + @attachment.save | |
| 656 | + @existing_names.each{|f| assert ! File.exists?(f) } | |
| 657 | + end | |
| 658 | + | |
| 659 | + should "delete the files when you call #delete" do | |
| 660 | + @attachment.expects(:instance_write).with(:file_name, nil) | |
| 661 | + @attachment.expects(:instance_write).with(:content_type, nil) | |
| 662 | + @attachment.expects(:instance_write).with(:file_size, nil) | |
| 663 | + @attachment.expects(:instance_write).with(:updated_at, nil) | |
| 664 | + @attachment.destroy | |
| 665 | + @existing_names.each{|f| assert ! File.exists?(f) } | |
| 666 | + end | |
| 667 | + end | |
| 668 | + end | |
| 669 | + end | |
| 670 | + end | |
| 671 | + | |
| 672 | + end | |
| 673 | + | |
| 674 | + context "when trying a nonexistant storage type" do | |
| 675 | + setup do | |
| 676 | + rebuild_model :storage => :not_here | |
| 677 | + end | |
| 678 | + | |
| 679 | + should "not be able to find the module" do | |
| 680 | + assert_raise(NameError){ Dummy.new.avatar } | |
| 681 | + end | |
| 682 | + end | |
| 683 | + end | |
| 684 | + | |
| 685 | + context "An attachment with only a avatar_file_name column" do | |
| 686 | + setup do | |
| 687 | + ActiveRecord::Base.connection.create_table :dummies, :force => true do |table| | |
| 688 | + table.column :avatar_file_name, :string | |
| 689 | + end | |
| 690 | + rebuild_class | |
| 691 | + @dummy = Dummy.new | |
| 692 | + @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | |
| 693 | + end | |
| 694 | + | |
| 695 | + teardown { @file.close } | |
| 696 | + | |
| 697 | + should "not error when assigned an attachment" do | |
| 698 | + assert_nothing_raised { @dummy.avatar = @file } | |
| 699 | + end | |
| 700 | + | |
| 701 | + should "return the time when sent #avatar_updated_at" do | |
| 702 | + now = Time.now | |
| 703 | + Time.stubs(:now).returns(now) | |
| 704 | + @dummy.avatar = @file | |
| 705 | + assert now, @dummy.avatar.updated_at | |
| 706 | + end | |
| 707 | + | |
| 708 | + should "return nil when reloaded and sent #avatar_updated_at" do | |
| 709 | + @dummy.save | |
| 710 | + @dummy.reload | |
| 711 | + assert_nil @dummy.avatar.updated_at | |
| 712 | + end | |
| 713 | + | |
| 714 | + should "return the right value when sent #avatar_file_size" do | |
| 715 | + @dummy.avatar = @file | |
| 716 | + assert_equal @file.size, @dummy.avatar.size | |
| 717 | + end | |
| 718 | + | |
| 719 | + context "and avatar_updated_at column" do | |
| 720 | + setup do | |
| 721 | + ActiveRecord::Base.connection.add_column :dummies, :avatar_updated_at, :timestamp | |
| 722 | + rebuild_class | |
| 723 | + @dummy = Dummy.new | |
| 724 | + end | |
| 725 | + | |
| 726 | + should "not error when assigned an attachment" do | |
| 727 | + assert_nothing_raised { @dummy.avatar = @file } | |
| 728 | + end | |
| 729 | + | |
| 730 | + should "return the right value when sent #avatar_updated_at" do | |
| 731 | + now = Time.now | |
| 732 | + Time.stubs(:now).returns(now) | |
| 733 | + @dummy.avatar = @file | |
| 734 | + assert_equal now.to_i, @dummy.avatar.updated_at | |
| 735 | + end | |
| 736 | + end | |
| 737 | + | |
| 738 | + context "and avatar_content_type column" do | |
| 739 | + setup do | |
| 740 | + ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string | |
| 741 | + rebuild_class | |
| 742 | + @dummy = Dummy.new | |
| 743 | + end | |
| 744 | + | |
| 745 | + should "not error when assigned an attachment" do | |
| 746 | + assert_nothing_raised { @dummy.avatar = @file } | |
| 747 | + end | |
| 748 | + | |
| 749 | + should "return the right value when sent #avatar_content_type" do | |
| 750 | + @dummy.avatar = @file | |
| 751 | + assert_equal "image/png", @dummy.avatar.content_type | |
| 752 | + end | |
| 753 | + end | |
| 754 | + | |
| 755 | + context "and avatar_file_size column" do | |
| 756 | + setup do | |
| 757 | + ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer | |
| 758 | + rebuild_class | |
| 759 | + @dummy = Dummy.new | |
| 760 | + end | |
| 761 | + | |
| 762 | + should "not error when assigned an attachment" do | |
| 763 | + assert_nothing_raised { @dummy.avatar = @file } | |
| 764 | + end | |
| 765 | + | |
| 766 | + should "return the right value when sent #avatar_file_size" do | |
| 767 | + @dummy.avatar = @file | |
| 768 | + assert_equal @file.size, @dummy.avatar.size | |
| 769 | + end | |
| 770 | + | |
| 771 | + should "return the right value when saved, reloaded, and sent #avatar_file_size" do | |
| 772 | + @dummy.avatar = @file | |
| 773 | + @dummy.save | |
| 774 | + @dummy = Dummy.find(@dummy.id) | |
| 775 | + assert_equal @file.size, @dummy.avatar.size | |
| 776 | + end | |
| 777 | + end | |
| 778 | + end | |
| 779 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/database.yml
0 → 100644
11.8 KB
1.58 KB
4.35 KB
vendor/gems/tristandunn-paperclip-2.3.1/test/fixtures/bad.png
0 → 100644
| ... | ... | @@ -0,0 +1 @@ |
| 1 | +This is not an image. | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/fixtures/s3.yml
0 → 100644
vendor/gems/tristandunn-paperclip-2.3.1/test/fixtures/text.txt
0 → 100644
No preview for this file type
vendor/gems/tristandunn-paperclip-2.3.1/test/geometry_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,177 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class GeometryTest < Test::Unit::TestCase | |
| 4 | + context "Paperclip::Geometry" do | |
| 5 | + should "correctly report its given dimensions" do | |
| 6 | + assert @geo = Paperclip::Geometry.new(1024, 768) | |
| 7 | + assert_equal 1024, @geo.width | |
| 8 | + assert_equal 768, @geo.height | |
| 9 | + end | |
| 10 | + | |
| 11 | + should "set height to 0 if height dimension is missing" do | |
| 12 | + assert @geo = Paperclip::Geometry.new(1024) | |
| 13 | + assert_equal 1024, @geo.width | |
| 14 | + assert_equal 0, @geo.height | |
| 15 | + end | |
| 16 | + | |
| 17 | + should "set width to 0 if width dimension is missing" do | |
| 18 | + assert @geo = Paperclip::Geometry.new(nil, 768) | |
| 19 | + assert_equal 0, @geo.width | |
| 20 | + assert_equal 768, @geo.height | |
| 21 | + end | |
| 22 | + | |
| 23 | + should "be generated from a WxH-formatted string" do | |
| 24 | + assert @geo = Paperclip::Geometry.parse("800x600") | |
| 25 | + assert_equal 800, @geo.width | |
| 26 | + assert_equal 600, @geo.height | |
| 27 | + end | |
| 28 | + | |
| 29 | + should "be generated from a xH-formatted string" do | |
| 30 | + assert @geo = Paperclip::Geometry.parse("x600") | |
| 31 | + assert_equal 0, @geo.width | |
| 32 | + assert_equal 600, @geo.height | |
| 33 | + end | |
| 34 | + | |
| 35 | + should "be generated from a Wx-formatted string" do | |
| 36 | + assert @geo = Paperclip::Geometry.parse("800x") | |
| 37 | + assert_equal 800, @geo.width | |
| 38 | + assert_equal 0, @geo.height | |
| 39 | + end | |
| 40 | + | |
| 41 | + should "be generated from a W-formatted string" do | |
| 42 | + assert @geo = Paperclip::Geometry.parse("800") | |
| 43 | + assert_equal 800, @geo.width | |
| 44 | + assert_equal 0, @geo.height | |
| 45 | + end | |
| 46 | + | |
| 47 | + should "ensure the modifier is nil if not present" do | |
| 48 | + assert @geo = Paperclip::Geometry.parse("123x456") | |
| 49 | + assert_nil @geo.modifier | |
| 50 | + end | |
| 51 | + | |
| 52 | + should "treat x and X the same in geometries" do | |
| 53 | + @lower = Paperclip::Geometry.parse("123x456") | |
| 54 | + @upper = Paperclip::Geometry.parse("123X456") | |
| 55 | + assert_equal 123, @lower.width | |
| 56 | + assert_equal 123, @upper.width | |
| 57 | + assert_equal 456, @lower.height | |
| 58 | + assert_equal 456, @upper.height | |
| 59 | + end | |
| 60 | + | |
| 61 | + ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod| | |
| 62 | + should "ensure the modifier #{mod.inspect} is preserved" do | |
| 63 | + assert @geo = Paperclip::Geometry.parse("123x456#{mod}") | |
| 64 | + assert_equal mod, @geo.modifier | |
| 65 | + assert_equal "123x456#{mod}", @geo.to_s | |
| 66 | + end | |
| 67 | + end | |
| 68 | + | |
| 69 | + ['>', '<', '#', '@', '%', '^', '!', nil].each do |mod| | |
| 70 | + should "ensure the modifier #{mod.inspect} is preserved with no height" do | |
| 71 | + assert @geo = Paperclip::Geometry.parse("123x#{mod}") | |
| 72 | + assert_equal mod, @geo.modifier | |
| 73 | + assert_equal "123#{mod}", @geo.to_s | |
| 74 | + end | |
| 75 | + end | |
| 76 | + | |
| 77 | + should "make sure the modifier gets passed during transformation_to" do | |
| 78 | + assert @src = Paperclip::Geometry.parse("123x456") | |
| 79 | + assert @dst = Paperclip::Geometry.parse("123x456>") | |
| 80 | + assert_equal ["123x456>", nil], @src.transformation_to(@dst) | |
| 81 | + end | |
| 82 | + | |
| 83 | + should "generate correct ImageMagick formatting string for W-formatted string" do | |
| 84 | + assert @geo = Paperclip::Geometry.parse("800") | |
| 85 | + assert_equal "800", @geo.to_s | |
| 86 | + end | |
| 87 | + | |
| 88 | + should "generate correct ImageMagick formatting string for Wx-formatted string" do | |
| 89 | + assert @geo = Paperclip::Geometry.parse("800x") | |
| 90 | + assert_equal "800", @geo.to_s | |
| 91 | + end | |
| 92 | + | |
| 93 | + should "generate correct ImageMagick formatting string for xH-formatted string" do | |
| 94 | + assert @geo = Paperclip::Geometry.parse("x600") | |
| 95 | + assert_equal "x600", @geo.to_s | |
| 96 | + end | |
| 97 | + | |
| 98 | + should "generate correct ImageMagick formatting string for WxH-formatted string" do | |
| 99 | + assert @geo = Paperclip::Geometry.parse("800x600") | |
| 100 | + assert_equal "800x600", @geo.to_s | |
| 101 | + end | |
| 102 | + | |
| 103 | + should "be generated from a file" do | |
| 104 | + file = File.join(File.dirname(__FILE__), "fixtures", "5k.png") | |
| 105 | + file = File.new(file, 'rb') | |
| 106 | + assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) } | |
| 107 | + assert @geo.height > 0 | |
| 108 | + assert @geo.width > 0 | |
| 109 | + end | |
| 110 | + | |
| 111 | + should "be generated from a file path" do | |
| 112 | + file = File.join(File.dirname(__FILE__), "fixtures", "5k.png") | |
| 113 | + assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) } | |
| 114 | + assert @geo.height > 0 | |
| 115 | + assert @geo.width > 0 | |
| 116 | + end | |
| 117 | + | |
| 118 | + should "not generate from a bad file" do | |
| 119 | + file = "/home/This File Does Not Exist.omg" | |
| 120 | + assert_raise(Paperclip::NotIdentifiedByImageMagickError){ @geo = Paperclip::Geometry.from_file(file) } | |
| 121 | + end | |
| 122 | + | |
| 123 | + [['vertical', 900, 1440, true, false, false, 1440, 900, 0.625], | |
| 124 | + ['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333], | |
| 125 | + ['square', 100, 100, false, false, true, 100, 100, 1]].each do |args| | |
| 126 | + context "performing calculations on a #{args[0]} viewport" do | |
| 127 | + setup do | |
| 128 | + @geo = Paperclip::Geometry.new(args[1], args[2]) | |
| 129 | + end | |
| 130 | + | |
| 131 | + should "#{args[3] ? "" : "not"} be vertical" do | |
| 132 | + assert_equal args[3], @geo.vertical? | |
| 133 | + end | |
| 134 | + | |
| 135 | + should "#{args[4] ? "" : "not"} be horizontal" do | |
| 136 | + assert_equal args[4], @geo.horizontal? | |
| 137 | + end | |
| 138 | + | |
| 139 | + should "#{args[5] ? "" : "not"} be square" do | |
| 140 | + assert_equal args[5], @geo.square? | |
| 141 | + end | |
| 142 | + | |
| 143 | + should "report that #{args[6]} is the larger dimension" do | |
| 144 | + assert_equal args[6], @geo.larger | |
| 145 | + end | |
| 146 | + | |
| 147 | + should "report that #{args[7]} is the smaller dimension" do | |
| 148 | + assert_equal args[7], @geo.smaller | |
| 149 | + end | |
| 150 | + | |
| 151 | + should "have an aspect ratio of #{args[8]}" do | |
| 152 | + assert_in_delta args[8], @geo.aspect, 0.0001 | |
| 153 | + end | |
| 154 | + end | |
| 155 | + end | |
| 156 | + | |
| 157 | + [[ [1000, 100], [64, 64], "x64", "64x64+288+0" ], | |
| 158 | + [ [100, 1000], [50, 950], "x950", "50x950+22+0" ], | |
| 159 | + [ [100, 1000], [50, 25], "50x", "50x25+0+237" ]]. each do |args| | |
| 160 | + context "of #{args[0].inspect} and given a Geometry #{args[1].inspect} and sent transform_to" do | |
| 161 | + setup do | |
| 162 | + @geo = Paperclip::Geometry.new(*args[0]) | |
| 163 | + @dst = Paperclip::Geometry.new(*args[1]) | |
| 164 | + @scale, @crop = @geo.transformation_to @dst, true | |
| 165 | + end | |
| 166 | + | |
| 167 | + should "be able to return the correct scaling transformation geometry #{args[2]}" do | |
| 168 | + assert_equal args[2], @scale | |
| 169 | + end | |
| 170 | + | |
| 171 | + should "be able to return the correct crop transformation geometry #{args[3]}" do | |
| 172 | + assert_equal args[3], @crop | |
| 173 | + end | |
| 174 | + end | |
| 175 | + end | |
| 176 | + end | |
| 177 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,99 @@ |
| 1 | +require 'rubygems' | |
| 2 | +require 'test/unit' | |
| 3 | +require 'shoulda' | |
| 4 | +require 'mocha' | |
| 5 | +require 'tempfile' | |
| 6 | + | |
| 7 | +gem 'sqlite3-ruby' | |
| 8 | + | |
| 9 | +require 'active_record' | |
| 10 | +require 'active_support' | |
| 11 | +begin | |
| 12 | + require 'ruby-debug' | |
| 13 | +rescue LoadError | |
| 14 | + puts "ruby-debug not loaded" | |
| 15 | +end | |
| 16 | + | |
| 17 | +ROOT = File.join(File.dirname(__FILE__), '..') | |
| 18 | +RAILS_ROOT = ROOT | |
| 19 | +RAILS_ENV = "test" | |
| 20 | + | |
| 21 | +$LOAD_PATH << File.join(ROOT, 'lib') | |
| 22 | +$LOAD_PATH << File.join(ROOT, 'lib', 'paperclip') | |
| 23 | + | |
| 24 | +require File.join(ROOT, 'lib', 'paperclip.rb') | |
| 25 | + | |
| 26 | +require 'shoulda_macros/paperclip' | |
| 27 | + | |
| 28 | +FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures") | |
| 29 | +config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) | |
| 30 | +ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log") | |
| 31 | +ActiveRecord::Base.establish_connection(config['test']) | |
| 32 | + | |
| 33 | +def reset_class class_name | |
| 34 | + ActiveRecord::Base.send(:include, Paperclip) | |
| 35 | + Object.send(:remove_const, class_name) rescue nil | |
| 36 | + klass = Object.const_set(class_name, Class.new(ActiveRecord::Base)) | |
| 37 | + klass.class_eval{ include Paperclip } | |
| 38 | + klass | |
| 39 | +end | |
| 40 | + | |
| 41 | +def reset_table table_name, &block | |
| 42 | + block ||= lambda { |table| true } | |
| 43 | + ActiveRecord::Base.connection.create_table :dummies, {:force => true}, &block | |
| 44 | +end | |
| 45 | + | |
| 46 | +def modify_table table_name, &block | |
| 47 | + ActiveRecord::Base.connection.change_table :dummies, &block | |
| 48 | +end | |
| 49 | + | |
| 50 | +def rebuild_model options = {} | |
| 51 | + ActiveRecord::Base.connection.create_table :dummies, :force => true do |table| | |
| 52 | + table.column :other, :string | |
| 53 | + table.column :avatar_file_name, :string | |
| 54 | + table.column :avatar_content_type, :string | |
| 55 | + table.column :avatar_file_size, :integer | |
| 56 | + table.column :avatar_updated_at, :datetime | |
| 57 | + end | |
| 58 | + rebuild_class options | |
| 59 | +end | |
| 60 | + | |
| 61 | +def rebuild_class options = {} | |
| 62 | + ActiveRecord::Base.send(:include, Paperclip) | |
| 63 | + Object.send(:remove_const, "Dummy") rescue nil | |
| 64 | + Object.const_set("Dummy", Class.new(ActiveRecord::Base)) | |
| 65 | + Dummy.class_eval do | |
| 66 | + include Paperclip | |
| 67 | + has_attached_file :avatar, options | |
| 68 | + end | |
| 69 | +end | |
| 70 | + | |
| 71 | +def temporary_rails_env(new_env) | |
| 72 | + old_env = Object.const_defined?("RAILS_ENV") ? RAILS_ENV : nil | |
| 73 | + silence_warnings do | |
| 74 | + Object.const_set("RAILS_ENV", new_env) | |
| 75 | + end | |
| 76 | + yield | |
| 77 | + silence_warnings do | |
| 78 | + Object.const_set("RAILS_ENV", old_env) | |
| 79 | + end | |
| 80 | +end | |
| 81 | + | |
| 82 | +class FakeModel | |
| 83 | + attr_accessor :avatar_file_name, | |
| 84 | + :avatar_file_size, | |
| 85 | + :avatar_last_updated, | |
| 86 | + :avatar_content_type, | |
| 87 | + :id | |
| 88 | + | |
| 89 | + def errors | |
| 90 | + @errors ||= [] | |
| 91 | + end | |
| 92 | + | |
| 93 | + def run_callbacks name, *args | |
| 94 | + end | |
| 95 | +end | |
| 96 | + | |
| 97 | +def attachment options | |
| 98 | + Paperclip::Attachment.new(:avatar, FakeModel.new, options) | |
| 99 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/integration_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,483 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class IntegrationTest < Test::Unit::TestCase | |
| 4 | + context "Many models at once" do | |
| 5 | + setup do | |
| 6 | + rebuild_model | |
| 7 | + @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | |
| 8 | + 300.times do |i| | |
| 9 | + Dummy.create! :avatar => @file | |
| 10 | + end | |
| 11 | + end | |
| 12 | + | |
| 13 | + should "not exceed the open file limit" do | |
| 14 | + assert_nothing_raised do | |
| 15 | + dummies = Dummy.find(:all) | |
| 16 | + dummies.each { |dummy| dummy.avatar } | |
| 17 | + end | |
| 18 | + end | |
| 19 | + end | |
| 20 | + | |
| 21 | + context "An attachment" do | |
| 22 | + setup do | |
| 23 | + rebuild_model :styles => { :thumb => "50x50#" } | |
| 24 | + @dummy = Dummy.new | |
| 25 | + @file = File.new(File.join(File.dirname(__FILE__), | |
| 26 | + "fixtures", | |
| 27 | + "5k.png"), 'rb') | |
| 28 | + @dummy.avatar = @file | |
| 29 | + assert @dummy.save | |
| 30 | + end | |
| 31 | + | |
| 32 | + teardown { @file.close } | |
| 33 | + | |
| 34 | + should "create its thumbnails properly" do | |
| 35 | + assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:thumb)}"` | |
| 36 | + end | |
| 37 | + | |
| 38 | + context "redefining its attachment styles" do | |
| 39 | + setup do | |
| 40 | + Dummy.class_eval do | |
| 41 | + has_attached_file :avatar, :styles => { :thumb => "150x25#" } | |
| 42 | + has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } } | |
| 43 | + end | |
| 44 | + @d2 = Dummy.find(@dummy.id) | |
| 45 | + @d2.avatar.reprocess! | |
| 46 | + @d2.save | |
| 47 | + end | |
| 48 | + | |
| 49 | + should "create its thumbnails properly" do | |
| 50 | + assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"` | |
| 51 | + assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"` | |
| 52 | + end | |
| 53 | + end | |
| 54 | + end | |
| 55 | + | |
| 56 | + context "A model that modifies its original" do | |
| 57 | + setup do | |
| 58 | + rebuild_model :styles => { :original => "2x2#" } | |
| 59 | + @dummy = Dummy.new | |
| 60 | + @file = File.new(File.join(File.dirname(__FILE__), | |
| 61 | + "fixtures", | |
| 62 | + "5k.png"), 'rb') | |
| 63 | + @dummy.avatar = @file | |
| 64 | + end | |
| 65 | + | |
| 66 | + should "report the file size of the processed file and not the original" do | |
| 67 | + assert_not_equal @file.size, @dummy.avatar.size | |
| 68 | + end | |
| 69 | + | |
| 70 | + teardown { @file.close } | |
| 71 | + end | |
| 72 | + | |
| 73 | + context "A model with attachments scoped under an id" do | |
| 74 | + setup do | |
| 75 | + rebuild_model :styles => { :large => "100x100", | |
| 76 | + :medium => "50x50" }, | |
| 77 | + :path => ":rails_root/tmp/:id/:attachments/:style.:extension" | |
| 78 | + @dummy = Dummy.new | |
| 79 | + @file = File.new(File.join(File.dirname(__FILE__), | |
| 80 | + "fixtures", | |
| 81 | + "5k.png"), 'rb') | |
| 82 | + @dummy.avatar = @file | |
| 83 | + end | |
| 84 | + | |
| 85 | + teardown { @file.close } | |
| 86 | + | |
| 87 | + context "when saved" do | |
| 88 | + setup do | |
| 89 | + @dummy.save | |
| 90 | + @saved_path = @dummy.avatar.path(:large) | |
| 91 | + end | |
| 92 | + | |
| 93 | + should "have a large file in the right place" do | |
| 94 | + assert File.exists?(@dummy.avatar.path(:large)) | |
| 95 | + end | |
| 96 | + | |
| 97 | + context "and deleted" do | |
| 98 | + setup do | |
| 99 | + @dummy.avatar.clear | |
| 100 | + @dummy.save | |
| 101 | + end | |
| 102 | + | |
| 103 | + should "not have a large file in the right place anymore" do | |
| 104 | + assert ! File.exists?(@saved_path) | |
| 105 | + end | |
| 106 | + | |
| 107 | + should "not have its next two parent directories" do | |
| 108 | + assert ! File.exists?(File.dirname(@saved_path)) | |
| 109 | + assert ! File.exists?(File.dirname(File.dirname(@saved_path))) | |
| 110 | + end | |
| 111 | + | |
| 112 | + before_should "not die if an unexpected SystemCallError happens" do | |
| 113 | + FileUtils.stubs(:rmdir).raises(Errno::EPIPE) | |
| 114 | + end | |
| 115 | + end | |
| 116 | + end | |
| 117 | + end | |
| 118 | + | |
| 119 | + context "A model with no attachment validation" do | |
| 120 | + setup do | |
| 121 | + rebuild_model :styles => { :large => "300x300>", | |
| 122 | + :medium => "100x100", | |
| 123 | + :thumb => ["32x32#", :gif] }, | |
| 124 | + :default_style => :medium, | |
| 125 | + :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 126 | + :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 127 | + @dummy = Dummy.new | |
| 128 | + end | |
| 129 | + | |
| 130 | + should "have its definition return false when asked about whiny_thumbnails" do | |
| 131 | + assert ! Dummy.attachment_definitions[:avatar][:whiny_thumbnails] | |
| 132 | + end | |
| 133 | + | |
| 134 | + context "when validates_attachment_thumbnails is called" do | |
| 135 | + setup do | |
| 136 | + Dummy.validates_attachment_thumbnails :avatar | |
| 137 | + end | |
| 138 | + | |
| 139 | + should "have its definition return true when asked about whiny_thumbnails" do | |
| 140 | + assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails] | |
| 141 | + end | |
| 142 | + end | |
| 143 | + | |
| 144 | + context "redefined to have attachment validations" do | |
| 145 | + setup do | |
| 146 | + rebuild_model :styles => { :large => "300x300>", | |
| 147 | + :medium => "100x100", | |
| 148 | + :thumb => ["32x32#", :gif] }, | |
| 149 | + :whiny_thumbnails => true, | |
| 150 | + :default_style => :medium, | |
| 151 | + :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 152 | + :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 153 | + end | |
| 154 | + | |
| 155 | + should "have its definition return true when asked about whiny_thumbnails" do | |
| 156 | + assert_equal true, Dummy.attachment_definitions[:avatar][:whiny_thumbnails] | |
| 157 | + end | |
| 158 | + end | |
| 159 | + end | |
| 160 | + | |
| 161 | + context "A model with no convert_options setting" do | |
| 162 | + setup do | |
| 163 | + rebuild_model :styles => { :large => "300x300>", | |
| 164 | + :medium => "100x100", | |
| 165 | + :thumb => ["32x32#", :gif] }, | |
| 166 | + :default_style => :medium, | |
| 167 | + :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 168 | + :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 169 | + @dummy = Dummy.new | |
| 170 | + end | |
| 171 | + | |
| 172 | + should "have its definition return nil when asked about convert_options" do | |
| 173 | + assert ! Dummy.attachment_definitions[:avatar][:convert_options] | |
| 174 | + end | |
| 175 | + | |
| 176 | + context "redefined to have convert_options setting" do | |
| 177 | + setup do | |
| 178 | + rebuild_model :styles => { :large => "300x300>", | |
| 179 | + :medium => "100x100", | |
| 180 | + :thumb => ["32x32#", :gif] }, | |
| 181 | + :convert_options => "-strip -depth 8", | |
| 182 | + :default_style => :medium, | |
| 183 | + :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 184 | + :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 185 | + end | |
| 186 | + | |
| 187 | + should "have its definition return convert_options value when asked about convert_options" do | |
| 188 | + assert_equal "-strip -depth 8", Dummy.attachment_definitions[:avatar][:convert_options] | |
| 189 | + end | |
| 190 | + end | |
| 191 | + end | |
| 192 | + | |
| 193 | + context "A model with a filesystem attachment" do | |
| 194 | + setup do | |
| 195 | + rebuild_model :styles => { :large => "300x300>", | |
| 196 | + :medium => "100x100", | |
| 197 | + :thumb => ["32x32#", :gif] }, | |
| 198 | + :whiny_thumbnails => true, | |
| 199 | + :default_style => :medium, | |
| 200 | + :url => "/:attachment/:class/:style/:id/:basename.:extension", | |
| 201 | + :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension" | |
| 202 | + @dummy = Dummy.new | |
| 203 | + @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | |
| 204 | + @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb') | |
| 205 | + | |
| 206 | + assert @dummy.avatar = @file | |
| 207 | + assert @dummy.valid? | |
| 208 | + assert @dummy.save | |
| 209 | + end | |
| 210 | + | |
| 211 | + should "write and delete its files" do | |
| 212 | + [["434x66", :original], | |
| 213 | + ["300x46", :large], | |
| 214 | + ["100x15", :medium], | |
| 215 | + ["32x32", :thumb]].each do |geo, style| | |
| 216 | + cmd = %Q[identify -format "%wx%h" "#{@dummy.avatar.path(style)}"] | |
| 217 | + assert_equal geo, `#{cmd}`.chomp, cmd | |
| 218 | + end | |
| 219 | + | |
| 220 | + saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) } | |
| 221 | + | |
| 222 | + @d2 = Dummy.find(@dummy.id) | |
| 223 | + assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path}"`.chomp | |
| 224 | + assert_equal "434x66", `identify -format "%wx%h" "#{@d2.avatar.path(:original)}"`.chomp | |
| 225 | + assert_equal "300x46", `identify -format "%wx%h" "#{@d2.avatar.path(:large)}"`.chomp | |
| 226 | + assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp | |
| 227 | + assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp | |
| 228 | + | |
| 229 | + @dummy.avatar = "not a valid file but not nil" | |
| 230 | + assert_equal File.basename(@file.path), @dummy.avatar_file_name | |
| 231 | + assert @dummy.valid? | |
| 232 | + assert @dummy.save | |
| 233 | + | |
| 234 | + saved_paths.each do |p| | |
| 235 | + assert File.exists?(p) | |
| 236 | + end | |
| 237 | + | |
| 238 | + @dummy.avatar.clear | |
| 239 | + assert_nil @dummy.avatar_file_name | |
| 240 | + assert @dummy.valid? | |
| 241 | + assert @dummy.save | |
| 242 | + | |
| 243 | + saved_paths.each do |p| | |
| 244 | + assert ! File.exists?(p) | |
| 245 | + end | |
| 246 | + | |
| 247 | + @d2 = Dummy.find(@dummy.id) | |
| 248 | + assert_nil @d2.avatar_file_name | |
| 249 | + end | |
| 250 | + | |
| 251 | + should "work exactly the same when new as when reloaded" do | |
| 252 | + @d2 = Dummy.find(@dummy.id) | |
| 253 | + | |
| 254 | + assert_equal @dummy.avatar_file_name, @d2.avatar_file_name | |
| 255 | + [:thumb, :medium, :large, :original].each do |style| | |
| 256 | + assert_equal @dummy.avatar.path(style), @d2.avatar.path(style) | |
| 257 | + end | |
| 258 | + | |
| 259 | + saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.path(s) } | |
| 260 | + | |
| 261 | + @d2.avatar.clear | |
| 262 | + assert @d2.save | |
| 263 | + | |
| 264 | + saved_paths.each do |p| | |
| 265 | + assert ! File.exists?(p) | |
| 266 | + end | |
| 267 | + end | |
| 268 | + | |
| 269 | + should "know the difference between good files, bad files, and not files" do | |
| 270 | + expected = @dummy.avatar.to_file | |
| 271 | + @dummy.avatar = "not a file" | |
| 272 | + assert @dummy.valid? | |
| 273 | + assert_equal expected.path, @dummy.avatar.path | |
| 274 | + expected.close | |
| 275 | + | |
| 276 | + @dummy.avatar = @bad_file | |
| 277 | + assert ! @dummy.valid? | |
| 278 | + end | |
| 279 | + | |
| 280 | + should "know the difference between good files, bad files, and not files when validating" do | |
| 281 | + Dummy.validates_attachment_presence :avatar | |
| 282 | + @d2 = Dummy.find(@dummy.id) | |
| 283 | + @d2.avatar = @file | |
| 284 | + assert @d2.valid?, @d2.errors.full_messages.inspect | |
| 285 | + @d2.avatar = @bad_file | |
| 286 | + assert ! @d2.valid? | |
| 287 | + end | |
| 288 | + | |
| 289 | + should "be able to reload without saving and not have the file disappear" do | |
| 290 | + @dummy.avatar = @file | |
| 291 | + assert @dummy.save | |
| 292 | + @dummy.avatar.clear | |
| 293 | + assert_nil @dummy.avatar_file_name | |
| 294 | + @dummy.reload | |
| 295 | + assert_equal "5k.png", @dummy.avatar_file_name | |
| 296 | + end | |
| 297 | + | |
| 298 | + context "that is assigned its file from another Paperclip attachment" do | |
| 299 | + setup do | |
| 300 | + @dummy2 = Dummy.new | |
| 301 | + @file2 = File.new(File.join(FIXTURES_DIR, "12k.png"), 'rb') | |
| 302 | + assert @dummy2.avatar = @file2 | |
| 303 | + @dummy2.save | |
| 304 | + end | |
| 305 | + | |
| 306 | + should "work when assigned a file" do | |
| 307 | + assert_not_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`, | |
| 308 | + `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"` | |
| 309 | + | |
| 310 | + assert @dummy.avatar = @dummy2.avatar | |
| 311 | + @dummy.save | |
| 312 | + assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`, | |
| 313 | + `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"` | |
| 314 | + end | |
| 315 | + end | |
| 316 | + | |
| 317 | + end | |
| 318 | + | |
| 319 | + context "A model with an attachments association and a Paperclip attachment" do | |
| 320 | + setup do | |
| 321 | + Dummy.class_eval do | |
| 322 | + has_many :attachments, :class_name => 'Dummy' | |
| 323 | + end | |
| 324 | + | |
| 325 | + @dummy = Dummy.new | |
| 326 | + @dummy.avatar = File.new(File.join(File.dirname(__FILE__), | |
| 327 | + "fixtures", | |
| 328 | + "5k.png"), 'rb') | |
| 329 | + end | |
| 330 | + | |
| 331 | + should "should not error when saving" do | |
| 332 | + assert_nothing_raised do | |
| 333 | + @dummy.save! | |
| 334 | + end | |
| 335 | + end | |
| 336 | + end | |
| 337 | + | |
| 338 | + if ENV['S3_TEST_BUCKET'] | |
| 339 | + def s3_files_for attachment | |
| 340 | + [:thumb, :medium, :large, :original].inject({}) do |files, style| | |
| 341 | + data = `curl "#{attachment.url(style)}" 2>/dev/null`.chomp | |
| 342 | + t = Tempfile.new("paperclip-test") | |
| 343 | + t.binmode | |
| 344 | + t.write(data) | |
| 345 | + t.rewind | |
| 346 | + files[style] = t | |
| 347 | + files | |
| 348 | + end | |
| 349 | + end | |
| 350 | + | |
| 351 | + def s3_headers_for attachment, style | |
| 352 | + `curl --head "#{attachment.url(style)}" 2>/dev/null`.split("\n").inject({}) do |h,head| | |
| 353 | + split_head = head.chomp.split(/\s*:\s*/, 2) | |
| 354 | + h[split_head.first.downcase] = split_head.last unless split_head.empty? | |
| 355 | + h | |
| 356 | + end | |
| 357 | + end | |
| 358 | + | |
| 359 | + context "A model with an S3 attachment" do | |
| 360 | + setup do | |
| 361 | + rebuild_model :styles => { :large => "300x300>", | |
| 362 | + :medium => "100x100", | |
| 363 | + :thumb => ["32x32#", :gif] }, | |
| 364 | + :storage => :s3, | |
| 365 | + :whiny_thumbnails => true, | |
| 366 | + # :s3_options => {:logger => Logger.new(StringIO.new)}, | |
| 367 | + :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")), | |
| 368 | + :default_style => :medium, | |
| 369 | + :bucket => ENV['S3_TEST_BUCKET'], | |
| 370 | + :path => ":class/:attachment/:id/:style/:basename.:extension" | |
| 371 | + @dummy = Dummy.new | |
| 372 | + @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | |
| 373 | + @bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"), 'rb') | |
| 374 | + | |
| 375 | + assert @dummy.avatar = @file | |
| 376 | + assert @dummy.valid? | |
| 377 | + assert @dummy.save | |
| 378 | + | |
| 379 | + @files_on_s3 = s3_files_for @dummy.avatar | |
| 380 | + end | |
| 381 | + | |
| 382 | + should "have the same contents as the original" do | |
| 383 | + @file.rewind | |
| 384 | + assert_equal @file.read, @files_on_s3[:original].read | |
| 385 | + end | |
| 386 | + | |
| 387 | + should "write and delete its files" do | |
| 388 | + [["434x66", :original], | |
| 389 | + ["300x46", :large], | |
| 390 | + ["100x15", :medium], | |
| 391 | + ["32x32", :thumb]].each do |geo, style| | |
| 392 | + cmd = %Q[identify -format "%wx%h" "#{@files_on_s3[style].path}"] | |
| 393 | + assert_equal geo, `#{cmd}`.chomp, cmd | |
| 394 | + end | |
| 395 | + | |
| 396 | + @d2 = Dummy.find(@dummy.id) | |
| 397 | + @d2_files = s3_files_for @d2.avatar | |
| 398 | + [["434x66", :original], | |
| 399 | + ["300x46", :large], | |
| 400 | + ["100x15", :medium], | |
| 401 | + ["32x32", :thumb]].each do |geo, style| | |
| 402 | + cmd = %Q[identify -format "%wx%h" "#{@d2_files[style].path}"] | |
| 403 | + assert_equal geo, `#{cmd}`.chomp, cmd | |
| 404 | + end | |
| 405 | + | |
| 406 | + @dummy.avatar = "not a valid file but not nil" | |
| 407 | + assert_equal File.basename(@file.path), @dummy.avatar_file_name | |
| 408 | + assert @dummy.valid? | |
| 409 | + assert @dummy.save | |
| 410 | + | |
| 411 | + [:thumb, :medium, :large, :original].each do |style| | |
| 412 | + assert @dummy.avatar.exists?(style) | |
| 413 | + end | |
| 414 | + | |
| 415 | + @dummy.avatar.clear | |
| 416 | + assert_nil @dummy.avatar_file_name | |
| 417 | + assert @dummy.valid? | |
| 418 | + assert @dummy.save | |
| 419 | + | |
| 420 | + [:thumb, :medium, :large, :original].each do |style| | |
| 421 | + assert ! @dummy.avatar.exists?(style) | |
| 422 | + end | |
| 423 | + | |
| 424 | + @d2 = Dummy.find(@dummy.id) | |
| 425 | + assert_nil @d2.avatar_file_name | |
| 426 | + end | |
| 427 | + | |
| 428 | + should "work exactly the same when new as when reloaded" do | |
| 429 | + @d2 = Dummy.find(@dummy.id) | |
| 430 | + | |
| 431 | + assert_equal @dummy.avatar_file_name, @d2.avatar_file_name | |
| 432 | + [:thumb, :medium, :large, :original].each do |style| | |
| 433 | + assert_equal @dummy.avatar.to_file(style).read, @d2.avatar.to_file(style).read | |
| 434 | + end | |
| 435 | + | |
| 436 | + saved_keys = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_file(s) } | |
| 437 | + | |
| 438 | + @d2.avatar.clear | |
| 439 | + assert @d2.save | |
| 440 | + | |
| 441 | + [:thumb, :medium, :large, :original].each do |style| | |
| 442 | + assert ! @dummy.avatar.exists?(style) | |
| 443 | + end | |
| 444 | + end | |
| 445 | + | |
| 446 | + should "know the difference between good files, bad files, not files, and nil" do | |
| 447 | + expected = @dummy.avatar.to_file | |
| 448 | + @dummy.avatar = "not a file" | |
| 449 | + assert @dummy.valid? | |
| 450 | + assert_equal expected.read, @dummy.avatar.to_file.read | |
| 451 | + | |
| 452 | + @dummy.avatar = @bad_file | |
| 453 | + assert ! @dummy.valid? | |
| 454 | + @dummy.avatar = nil | |
| 455 | + assert @dummy.valid? | |
| 456 | + | |
| 457 | + Dummy.validates_attachment_presence :avatar | |
| 458 | + @d2 = Dummy.find(@dummy.id) | |
| 459 | + @d2.avatar = @file | |
| 460 | + assert @d2.valid? | |
| 461 | + @d2.avatar = @bad_file | |
| 462 | + assert ! @d2.valid? | |
| 463 | + @d2.avatar = nil | |
| 464 | + assert ! @d2.valid? | |
| 465 | + end | |
| 466 | + | |
| 467 | + should "be able to reload without saving and not have the file disappear" do | |
| 468 | + @dummy.avatar = @file | |
| 469 | + assert @dummy.save | |
| 470 | + @dummy.avatar = nil | |
| 471 | + assert_nil @dummy.avatar_file_name | |
| 472 | + @dummy.reload | |
| 473 | + assert_equal "5k.png", @dummy.avatar_file_name | |
| 474 | + end | |
| 475 | + | |
| 476 | + should "have the right content type" do | |
| 477 | + headers = s3_headers_for(@dummy.avatar, :original) | |
| 478 | + assert_equal 'image/png', headers['content-type'] | |
| 479 | + end | |
| 480 | + end | |
| 481 | + end | |
| 482 | +end | |
| 483 | + | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/interpolations_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,120 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class InterpolationsTest < Test::Unit::TestCase | |
| 4 | + should "return all methods but the infrastructure when sent #all" do | |
| 5 | + methods = Paperclip::Interpolations.all | |
| 6 | + assert ! methods.include?(:[]) | |
| 7 | + assert ! methods.include?(:[]=) | |
| 8 | + assert ! methods.include?(:all) | |
| 9 | + methods.each do |m| | |
| 10 | + assert Paperclip::Interpolations.respond_to? m | |
| 11 | + end | |
| 12 | + end | |
| 13 | + | |
| 14 | + should "return the RAILS_ROOT" do | |
| 15 | + assert_equal RAILS_ROOT, Paperclip::Interpolations.rails_root(:attachment, :style) | |
| 16 | + end | |
| 17 | + | |
| 18 | + should "return the RAILS_ENV" do | |
| 19 | + assert_equal RAILS_ENV, Paperclip::Interpolations.rails_env(:attachment, :style) | |
| 20 | + end | |
| 21 | + | |
| 22 | + should "return the class of the instance" do | |
| 23 | + attachment = mock | |
| 24 | + attachment.expects(:instance).returns(attachment) | |
| 25 | + attachment.expects(:class).returns("Thing") | |
| 26 | + assert_equal "things", Paperclip::Interpolations.class(attachment, :style) | |
| 27 | + end | |
| 28 | + | |
| 29 | + should "return the basename of the file" do | |
| 30 | + attachment = mock | |
| 31 | + attachment.expects(:original_filename).returns("one.jpg").times(2) | |
| 32 | + assert_equal "one", Paperclip::Interpolations.basename(attachment, :style) | |
| 33 | + end | |
| 34 | + | |
| 35 | + should "return the extension of the file" do | |
| 36 | + attachment = mock | |
| 37 | + attachment.expects(:original_filename).returns("one.jpg") | |
| 38 | + attachment.expects(:styles).returns({}) | |
| 39 | + assert_equal "jpg", Paperclip::Interpolations.extension(attachment, :style) | |
| 40 | + end | |
| 41 | + | |
| 42 | + should "return the extension of the file as the format if defined in the style" do | |
| 43 | + attachment = mock | |
| 44 | + attachment.expects(:original_filename).never | |
| 45 | + attachment.expects(:styles).returns({:style => {:format => "png"}}) | |
| 46 | + assert_equal "png", Paperclip::Interpolations.extension(attachment, :style) | |
| 47 | + end | |
| 48 | + | |
| 49 | + should "return the id of the attachment" do | |
| 50 | + attachment = mock | |
| 51 | + attachment.expects(:id).returns(23) | |
| 52 | + attachment.expects(:instance).returns(attachment) | |
| 53 | + assert_equal 23, Paperclip::Interpolations.id(attachment, :style) | |
| 54 | + end | |
| 55 | + | |
| 56 | + should "return the partitioned id of the attachment" do | |
| 57 | + attachment = mock | |
| 58 | + attachment.expects(:id).returns(23) | |
| 59 | + attachment.expects(:instance).returns(attachment) | |
| 60 | + assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style) | |
| 61 | + end | |
| 62 | + | |
| 63 | + should "return the name of the attachment" do | |
| 64 | + attachment = mock | |
| 65 | + attachment.expects(:name).returns("file") | |
| 66 | + assert_equal "files", Paperclip::Interpolations.attachment(attachment, :style) | |
| 67 | + end | |
| 68 | + | |
| 69 | + should "return the style" do | |
| 70 | + assert_equal :style, Paperclip::Interpolations.style(:attachment, :style) | |
| 71 | + end | |
| 72 | + | |
| 73 | + should "return the default style" do | |
| 74 | + attachment = mock | |
| 75 | + attachment.expects(:default_style).returns(:default_style) | |
| 76 | + assert_equal :default_style, Paperclip::Interpolations.style(attachment, nil) | |
| 77 | + end | |
| 78 | + | |
| 79 | + should "reinterpolate :url" do | |
| 80 | + attachment = mock | |
| 81 | + attachment.expects(:options).returns({:url => ":id"}) | |
| 82 | + attachment.expects(:url).with(:style, false).returns("1234") | |
| 83 | + assert_equal "1234", Paperclip::Interpolations.url(attachment, :style) | |
| 84 | + end | |
| 85 | + | |
| 86 | + should "raise if infinite loop detcted reinterpolating :url" do | |
| 87 | + attachment = mock | |
| 88 | + attachment.expects(:options).returns({:url => ":url"}) | |
| 89 | + assert_raises(Paperclip::InfiniteInterpolationError){ Paperclip::Interpolations.url(attachment, :style) } | |
| 90 | + end | |
| 91 | + | |
| 92 | + should "return the filename as basename.extension" do | |
| 93 | + attachment = mock | |
| 94 | + attachment.expects(:styles).returns({}) | |
| 95 | + attachment.expects(:original_filename).returns("one.jpg").times(3) | |
| 96 | + assert_equal "one.jpg", Paperclip::Interpolations.filename(attachment, :style) | |
| 97 | + end | |
| 98 | + | |
| 99 | + should "return the filename as basename.extension when format supplied" do | |
| 100 | + attachment = mock | |
| 101 | + attachment.expects(:styles).returns({:style => {:format => :png}}) | |
| 102 | + attachment.expects(:original_filename).returns("one.jpg").times(2) | |
| 103 | + assert_equal "one.png", Paperclip::Interpolations.filename(attachment, :style) | |
| 104 | + end | |
| 105 | + | |
| 106 | + should "return the timestamp" do | |
| 107 | + now = Time.now | |
| 108 | + attachment = mock | |
| 109 | + attachment.expects(:instance_read).with(:updated_at).returns(now) | |
| 110 | + assert_equal now.to_s, Paperclip::Interpolations.timestamp(attachment, :style) | |
| 111 | + end | |
| 112 | + | |
| 113 | + should "call all expected interpolations with the given arguments" do | |
| 114 | + Paperclip::Interpolations.expects(:id).with(:attachment, :style).returns(1234) | |
| 115 | + Paperclip::Interpolations.expects(:attachment).with(:attachment, :style).returns("attachments") | |
| 116 | + Paperclip::Interpolations.expects(:notreal).never | |
| 117 | + value = Paperclip::Interpolations.interpolate(":notreal/:id/:attachment", :attachment, :style) | |
| 118 | + assert_equal ":notreal/1234/attachments", value | |
| 119 | + end | |
| 120 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/iostream_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,71 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class IOStreamTest < Test::Unit::TestCase | |
| 4 | + context "IOStream" do | |
| 5 | + should "be included in IO, File, Tempfile, and StringIO" do | |
| 6 | + [IO, File, Tempfile, StringIO].each do |klass| | |
| 7 | + assert klass.included_modules.include?(IOStream), "Not in #{klass}" | |
| 8 | + end | |
| 9 | + end | |
| 10 | + end | |
| 11 | + | |
| 12 | + context "A file" do | |
| 13 | + setup do | |
| 14 | + @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | |
| 15 | + end | |
| 16 | + | |
| 17 | + teardown { @file.close } | |
| 18 | + | |
| 19 | + context "that is sent #stream_to" do | |
| 20 | + | |
| 21 | + context "and given a String" do | |
| 22 | + setup do | |
| 23 | + FileUtils.mkdir_p(File.join(ROOT, 'tmp')) | |
| 24 | + assert @result = @file.stream_to(File.join(ROOT, 'tmp', 'iostream.string.test')) | |
| 25 | + end | |
| 26 | + | |
| 27 | + should "return a File" do | |
| 28 | + assert @result.is_a?(File) | |
| 29 | + end | |
| 30 | + | |
| 31 | + should "contain the same data as the original file" do | |
| 32 | + @file.rewind; @result.rewind | |
| 33 | + assert_equal @file.read, @result.read | |
| 34 | + end | |
| 35 | + end | |
| 36 | + | |
| 37 | + context "and given a Tempfile" do | |
| 38 | + setup do | |
| 39 | + tempfile = Tempfile.new('iostream.test') | |
| 40 | + tempfile.binmode | |
| 41 | + assert @result = @file.stream_to(tempfile) | |
| 42 | + end | |
| 43 | + | |
| 44 | + should "return a Tempfile" do | |
| 45 | + assert @result.is_a?(Tempfile) | |
| 46 | + end | |
| 47 | + | |
| 48 | + should "contain the same data as the original file" do | |
| 49 | + @file.rewind; @result.rewind | |
| 50 | + assert_equal @file.read, @result.read | |
| 51 | + end | |
| 52 | + end | |
| 53 | + | |
| 54 | + end | |
| 55 | + | |
| 56 | + context "that is sent #to_tempfile" do | |
| 57 | + setup do | |
| 58 | + assert @tempfile = @file.to_tempfile | |
| 59 | + end | |
| 60 | + | |
| 61 | + should "convert it to a Tempfile" do | |
| 62 | + assert @tempfile.is_a?(Tempfile) | |
| 63 | + end | |
| 64 | + | |
| 65 | + should "have the Tempfile contain the same data as the file" do | |
| 66 | + @file.rewind; @tempfile.rewind | |
| 67 | + assert_equal @file.read, @tempfile.read | |
| 68 | + end | |
| 69 | + end | |
| 70 | + end | |
| 71 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/matchers/have_attached_file_matcher_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class HaveAttachedFileMatcherTest < Test::Unit::TestCase | |
| 4 | + context "have_attached_file" do | |
| 5 | + setup do | |
| 6 | + @dummy_class = reset_class "Dummy" | |
| 7 | + reset_table "dummies" | |
| 8 | + @matcher = self.class.have_attached_file(:avatar) | |
| 9 | + end | |
| 10 | + | |
| 11 | + should "reject a class with no attachment" do | |
| 12 | + assert_rejects @matcher, @dummy_class | |
| 13 | + end | |
| 14 | + | |
| 15 | + should "accept a class with an attachment" do | |
| 16 | + modify_table("dummies"){|d| d.string :avatar_file_name } | |
| 17 | + @dummy_class.has_attached_file :avatar | |
| 18 | + assert_accepts @matcher, @dummy_class | |
| 19 | + end | |
| 20 | + end | |
| 21 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/matchers/validate_attachment_content_type_matcher_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase | |
| 4 | + context "validate_attachment_content_type" do | |
| 5 | + setup do | |
| 6 | + reset_table("dummies") do |d| | |
| 7 | + d.string :avatar_file_name | |
| 8 | + end | |
| 9 | + @dummy_class = reset_class "Dummy" | |
| 10 | + @dummy_class.has_attached_file :avatar | |
| 11 | + @matcher = self.class.validate_attachment_content_type(:avatar). | |
| 12 | + allowing(%w(image/png image/jpeg)). | |
| 13 | + rejecting(%w(audio/mp3 application/octet-stream)) | |
| 14 | + end | |
| 15 | + | |
| 16 | + should "reject a class with no validation" do | |
| 17 | + assert_rejects @matcher, @dummy_class | |
| 18 | + end | |
| 19 | + | |
| 20 | + should "reject a class with a validation that doesn't match" do | |
| 21 | + @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{audio/.*} | |
| 22 | + assert_rejects @matcher, @dummy_class | |
| 23 | + end | |
| 24 | + | |
| 25 | + should "accept a class with a validation" do | |
| 26 | + @dummy_class.validates_attachment_content_type :avatar, :content_type => %r{image/.*} | |
| 27 | + assert_accepts @matcher, @dummy_class | |
| 28 | + end | |
| 29 | + end | |
| 30 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/matchers/validate_attachment_presence_matcher_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase | |
| 4 | + context "validate_attachment_presence" do | |
| 5 | + setup do | |
| 6 | + reset_table("dummies"){|d| d.string :avatar_file_name } | |
| 7 | + @dummy_class = reset_class "Dummy" | |
| 8 | + @dummy_class.has_attached_file :avatar | |
| 9 | + @matcher = self.class.validate_attachment_presence(:avatar) | |
| 10 | + end | |
| 11 | + | |
| 12 | + should "reject a class with no validation" do | |
| 13 | + assert_rejects @matcher, @dummy_class | |
| 14 | + end | |
| 15 | + | |
| 16 | + should "accept a class with a validation" do | |
| 17 | + @dummy_class.validates_attachment_presence :avatar | |
| 18 | + assert_accepts @matcher, @dummy_class | |
| 19 | + end | |
| 20 | + end | |
| 21 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/matchers/validate_attachment_size_matcher_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,50 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase | |
| 4 | + context "validate_attachment_size" do | |
| 5 | + setup do | |
| 6 | + reset_table("dummies") do |d| | |
| 7 | + d.string :avatar_file_name | |
| 8 | + end | |
| 9 | + @dummy_class = reset_class "Dummy" | |
| 10 | + @dummy_class.has_attached_file :avatar | |
| 11 | + end | |
| 12 | + | |
| 13 | + context "of limited size" do | |
| 14 | + setup{ @matcher = self.class.validate_attachment_size(:avatar).in(256..1024) } | |
| 15 | + | |
| 16 | + should "reject a class with no validation" do | |
| 17 | + assert_rejects @matcher, @dummy_class | |
| 18 | + end | |
| 19 | + | |
| 20 | + should "reject a class with a validation that's too high" do | |
| 21 | + @dummy_class.validates_attachment_size :avatar, :in => 256..2048 | |
| 22 | + assert_rejects @matcher, @dummy_class | |
| 23 | + end | |
| 24 | + | |
| 25 | + should "reject a class with a validation that's too low" do | |
| 26 | + @dummy_class.validates_attachment_size :avatar, :in => 0..1024 | |
| 27 | + assert_rejects @matcher, @dummy_class | |
| 28 | + end | |
| 29 | + | |
| 30 | + should "accept a class with a validation that matches" do | |
| 31 | + @dummy_class.validates_attachment_size :avatar, :in => 256..1024 | |
| 32 | + assert_accepts @matcher, @dummy_class | |
| 33 | + end | |
| 34 | + end | |
| 35 | + | |
| 36 | + context "validates_attachment_size with infinite range" do | |
| 37 | + setup{ @matcher = self.class.validate_attachment_size(:avatar) } | |
| 38 | + | |
| 39 | + should "accept a class with an upper limit" do | |
| 40 | + @dummy_class.validates_attachment_size :avatar, :less_than => 1 | |
| 41 | + assert_accepts @matcher, @dummy_class | |
| 42 | + end | |
| 43 | + | |
| 44 | + should "accept a class with no upper limit" do | |
| 45 | + @dummy_class.validates_attachment_size :avatar, :greater_than => 1 | |
| 46 | + assert_accepts @matcher, @dummy_class | |
| 47 | + end | |
| 48 | + end | |
| 49 | + end | |
| 50 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/paperclip_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,312 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class PaperclipTest < Test::Unit::TestCase | |
| 4 | + [:image_magick_path, :command_path].each do |path| | |
| 5 | + context "Calling Paperclip.run with #{path} specified" do | |
| 6 | + setup do | |
| 7 | + Paperclip.options[:image_magick_path] = nil | |
| 8 | + Paperclip.options[:command_path] = nil | |
| 9 | + Paperclip.options[path] = "/usr/bin" | |
| 10 | + end | |
| 11 | + | |
| 12 | + should "return the expected path for path_for_command" do | |
| 13 | + assert_equal "/usr/bin/convert", Paperclip.path_for_command("convert") | |
| 14 | + end | |
| 15 | + | |
| 16 | + should "execute the right command" do | |
| 17 | + Paperclip.expects(:path_for_command).with("convert").returns("/usr/bin/convert") | |
| 18 | + Paperclip.expects(:bit_bucket).returns("/dev/null") | |
| 19 | + Paperclip.expects(:"`").with("/usr/bin/convert one.jpg two.jpg 2>/dev/null") | |
| 20 | + Paperclip.run("convert", "one.jpg two.jpg") | |
| 21 | + end | |
| 22 | + end | |
| 23 | + end | |
| 24 | + | |
| 25 | + context "Calling Paperclip.run with no path specified" do | |
| 26 | + setup do | |
| 27 | + Paperclip.options[:image_magick_path] = nil | |
| 28 | + Paperclip.options[:command_path] = nil | |
| 29 | + end | |
| 30 | + | |
| 31 | + should "return the expected path fro path_for_command" do | |
| 32 | + assert_equal "convert", Paperclip.path_for_command("convert") | |
| 33 | + end | |
| 34 | + | |
| 35 | + should "execute the right command" do | |
| 36 | + Paperclip.expects(:path_for_command).with("convert").returns("convert") | |
| 37 | + Paperclip.expects(:bit_bucket).returns("/dev/null") | |
| 38 | + Paperclip.expects(:"`").with("convert one.jpg two.jpg 2>/dev/null") | |
| 39 | + Paperclip.run("convert", "one.jpg two.jpg") | |
| 40 | + end | |
| 41 | + end | |
| 42 | + | |
| 43 | + context "Calling Paperclip.run and logging" do | |
| 44 | + setup do | |
| 45 | + Paperclip.options[:image_magick_path] = nil | |
| 46 | + Paperclip.options[:command_path] = nil | |
| 47 | + Paperclip.stubs(:bit_bucket).returns("/dev/null") | |
| 48 | + Paperclip.stubs(:log) | |
| 49 | + Paperclip.stubs(:"`").with("this is the command 2>/dev/null") | |
| 50 | + end | |
| 51 | + | |
| 52 | + should "log the command when :log_command is true" do | |
| 53 | + Paperclip.options[:log_command] = true | |
| 54 | + Paperclip.run("this","is the command") | |
| 55 | + assert_received(Paperclip, :log) do |p| | |
| 56 | + p.with("this is the command 2>/dev/null") | |
| 57 | + end | |
| 58 | + assert_received(Paperclip, :`) do |p| | |
| 59 | + p.with("this is the command 2>/dev/null") | |
| 60 | + end | |
| 61 | + end | |
| 62 | + | |
| 63 | + should "not log the command when :log_command is false" do | |
| 64 | + Paperclip.options[:log_command] = false | |
| 65 | + Paperclip.run("this","is the command") | |
| 66 | + assert_received(Paperclip, :log) do |p| | |
| 67 | + p.with("this is the command 2>/dev/null").never | |
| 68 | + end | |
| 69 | + assert_received(Paperclip, :`) do |p| | |
| 70 | + p.with("this is the command 2>/dev/null") | |
| 71 | + end | |
| 72 | + end | |
| 73 | + end | |
| 74 | + | |
| 75 | + context "Paperclip.bit_bucket" do | |
| 76 | + context "on systems without /dev/null" do | |
| 77 | + setup do | |
| 78 | + File.expects(:exists?).with("/dev/null").returns(false) | |
| 79 | + end | |
| 80 | + | |
| 81 | + should "return 'NUL'" do | |
| 82 | + assert_equal "NUL", Paperclip.bit_bucket | |
| 83 | + end | |
| 84 | + end | |
| 85 | + | |
| 86 | + context "on systems with /dev/null" do | |
| 87 | + setup do | |
| 88 | + File.expects(:exists?).with("/dev/null").returns(true) | |
| 89 | + end | |
| 90 | + | |
| 91 | + should "return '/dev/null'" do | |
| 92 | + assert_equal "/dev/null", Paperclip.bit_bucket | |
| 93 | + end | |
| 94 | + end | |
| 95 | + end | |
| 96 | + | |
| 97 | + should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do | |
| 98 | + assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) } | |
| 99 | + end | |
| 100 | + | |
| 101 | + should "raise when sent #processor and the name of a class that doesn't exist" do | |
| 102 | + assert_raises(NameError){ Paperclip.processor(:boogey_man) } | |
| 103 | + end | |
| 104 | + | |
| 105 | + should "return a class when sent #processor and the name of a class under Paperclip" do | |
| 106 | + assert_equal ::Paperclip::Thumbnail, Paperclip.processor(:thumbnail) | |
| 107 | + end | |
| 108 | + | |
| 109 | + context "An ActiveRecord model with an 'avatar' attachment" do | |
| 110 | + setup do | |
| 111 | + rebuild_model :path => "tmp/:class/omg/:style.:extension" | |
| 112 | + @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb') | |
| 113 | + end | |
| 114 | + | |
| 115 | + teardown { @file.close } | |
| 116 | + | |
| 117 | + should "not error when trying to also create a 'blah' attachment" do | |
| 118 | + assert_nothing_raised do | |
| 119 | + Dummy.class_eval do | |
| 120 | + has_attached_file :blah | |
| 121 | + end | |
| 122 | + end | |
| 123 | + end | |
| 124 | + | |
| 125 | + context "that is attr_protected" do | |
| 126 | + setup do | |
| 127 | + Dummy.class_eval do | |
| 128 | + attr_protected :avatar | |
| 129 | + end | |
| 130 | + @dummy = Dummy.new | |
| 131 | + end | |
| 132 | + | |
| 133 | + should "not assign the avatar on mass-set" do | |
| 134 | + @dummy.attributes = { :other => "I'm set!", | |
| 135 | + :avatar => @file } | |
| 136 | + | |
| 137 | + assert_equal "I'm set!", @dummy.other | |
| 138 | + assert ! @dummy.avatar? | |
| 139 | + end | |
| 140 | + | |
| 141 | + should "still allow assigment on normal set" do | |
| 142 | + @dummy.other = "I'm set!" | |
| 143 | + @dummy.avatar = @file | |
| 144 | + | |
| 145 | + assert_equal "I'm set!", @dummy.other | |
| 146 | + assert @dummy.avatar? | |
| 147 | + end | |
| 148 | + end | |
| 149 | + | |
| 150 | + context "with a subclass" do | |
| 151 | + setup do | |
| 152 | + class ::SubDummy < Dummy; end | |
| 153 | + end | |
| 154 | + | |
| 155 | + should "be able to use the attachment from the subclass" do | |
| 156 | + assert_nothing_raised do | |
| 157 | + @subdummy = SubDummy.create(:avatar => @file) | |
| 158 | + end | |
| 159 | + end | |
| 160 | + | |
| 161 | + should "be able to see the attachment definition from the subclass's class" do | |
| 162 | + assert_equal "tmp/:class/omg/:style.:extension", | |
| 163 | + SubDummy.attachment_definitions[:avatar][:path] | |
| 164 | + end | |
| 165 | + | |
| 166 | + teardown do | |
| 167 | + Object.send(:remove_const, "SubDummy") rescue nil | |
| 168 | + end | |
| 169 | + end | |
| 170 | + | |
| 171 | + should "have an #avatar method" do | |
| 172 | + assert Dummy.new.respond_to?(:avatar) | |
| 173 | + end | |
| 174 | + | |
| 175 | + should "have an #avatar= method" do | |
| 176 | + assert Dummy.new.respond_to?(:avatar=) | |
| 177 | + end | |
| 178 | + | |
| 179 | + context "that is valid" do | |
| 180 | + setup do | |
| 181 | + @dummy = Dummy.new | |
| 182 | + @dummy.avatar = @file | |
| 183 | + end | |
| 184 | + | |
| 185 | + should "be valid" do | |
| 186 | + assert @dummy.valid? | |
| 187 | + end | |
| 188 | + | |
| 189 | + context "then has a validation added that makes it invalid" do | |
| 190 | + setup do | |
| 191 | + assert @dummy.save | |
| 192 | + Dummy.class_eval do | |
| 193 | + validates_attachment_content_type :avatar, :content_type => ["text/plain"] | |
| 194 | + end | |
| 195 | + @dummy2 = Dummy.find(@dummy.id) | |
| 196 | + end | |
| 197 | + | |
| 198 | + should "be invalid when reloaded" do | |
| 199 | + assert ! @dummy2.valid?, @dummy2.errors.inspect | |
| 200 | + end | |
| 201 | + | |
| 202 | + should "be able to call #valid? twice without having duplicate errors" do | |
| 203 | + @dummy2.avatar.valid? | |
| 204 | + first_errors = @dummy2.avatar.errors | |
| 205 | + @dummy2.avatar.valid? | |
| 206 | + assert_equal first_errors, @dummy2.avatar.errors | |
| 207 | + end | |
| 208 | + end | |
| 209 | + end | |
| 210 | + | |
| 211 | + context "a validation with an if guard clause" do | |
| 212 | + setup do | |
| 213 | + Dummy.send(:"validates_attachment_presence", :avatar, :if => lambda{|i| i.foo }) | |
| 214 | + @dummy = Dummy.new | |
| 215 | + end | |
| 216 | + | |
| 217 | + should "attempt validation if the guard returns true" do | |
| 218 | + @dummy.expects(:foo).returns(true) | |
| 219 | + @dummy.avatar.expects(:validate_presence).returns(nil) | |
| 220 | + @dummy.valid? | |
| 221 | + end | |
| 222 | + | |
| 223 | + should "not attempt validation if the guard returns false" do | |
| 224 | + @dummy.expects(:foo).returns(false) | |
| 225 | + @dummy.avatar.expects(:validate_presence).never | |
| 226 | + @dummy.valid? | |
| 227 | + end | |
| 228 | + end | |
| 229 | + | |
| 230 | + context "a validation with an unless guard clause" do | |
| 231 | + setup do | |
| 232 | + Dummy.send(:"validates_attachment_presence", :avatar, :unless => lambda{|i| i.foo }) | |
| 233 | + @dummy = Dummy.new | |
| 234 | + end | |
| 235 | + | |
| 236 | + should "attempt validation if the guard returns true" do | |
| 237 | + @dummy.expects(:foo).returns(false) | |
| 238 | + @dummy.avatar.expects(:validate_presence).returns(nil) | |
| 239 | + @dummy.valid? | |
| 240 | + end | |
| 241 | + | |
| 242 | + should "not attempt validation if the guard returns false" do | |
| 243 | + @dummy.expects(:foo).returns(true) | |
| 244 | + @dummy.avatar.expects(:validate_presence).never | |
| 245 | + @dummy.valid? | |
| 246 | + end | |
| 247 | + end | |
| 248 | + | |
| 249 | + def self.should_validate validation, options, valid_file, invalid_file | |
| 250 | + context "with #{validation} validation and #{options.inspect} options" do | |
| 251 | + setup do | |
| 252 | + Dummy.send(:"validates_attachment_#{validation}", :avatar, options) | |
| 253 | + @dummy = Dummy.new | |
| 254 | + end | |
| 255 | + context "and assigning nil" do | |
| 256 | + setup do | |
| 257 | + @dummy.avatar = nil | |
| 258 | + @dummy.valid? | |
| 259 | + end | |
| 260 | + if validation == :presence | |
| 261 | + should "have an error on the attachment" do | |
| 262 | + assert @dummy.errors.on(:avatar) | |
| 263 | + end | |
| 264 | + else | |
| 265 | + should "not have an error on the attachment" do | |
| 266 | + assert_nil @dummy.errors.on(:avatar) | |
| 267 | + end | |
| 268 | + end | |
| 269 | + end | |
| 270 | + context "and assigned a valid file" do | |
| 271 | + setup do | |
| 272 | + @dummy.avatar = valid_file | |
| 273 | + @dummy.valid? | |
| 274 | + end | |
| 275 | + should "not have an error when assigned a valid file" do | |
| 276 | + assert ! @dummy.avatar.errors.key?(validation) | |
| 277 | + end | |
| 278 | + should "not have an error on the attachment" do | |
| 279 | + assert_nil @dummy.errors.on(:avatar) | |
| 280 | + end | |
| 281 | + end | |
| 282 | + context "and assigned an invalid file" do | |
| 283 | + setup do | |
| 284 | + @dummy.avatar = invalid_file | |
| 285 | + @dummy.valid? | |
| 286 | + end | |
| 287 | + should "have an error when assigned a valid file" do | |
| 288 | + assert_not_nil @dummy.avatar.errors[validation] | |
| 289 | + end | |
| 290 | + should "have an error on the attachment" do | |
| 291 | + assert @dummy.errors.on(:avatar) | |
| 292 | + end | |
| 293 | + end | |
| 294 | + end | |
| 295 | + end | |
| 296 | + | |
| 297 | + [[:presence, {}, "5k.png", nil], | |
| 298 | + [:size, {:in => 1..10240}, nil, "12k.png"], | |
| 299 | + [:size, {:less_than => 10240}, "5k.png", "12k.png"], | |
| 300 | + [:size, {:greater_than => 8096}, "12k.png", "5k.png"], | |
| 301 | + [:content_type, {:content_type => "image/png"}, "5k.png", "text.txt"], | |
| 302 | + [:content_type, {:content_type => "text/plain"}, "text.txt", "5k.png"], | |
| 303 | + [:content_type, {:content_type => %r{image/.*}}, "5k.png", "text.txt"]].each do |args| | |
| 304 | + validation, options, valid_file, invalid_file = args | |
| 305 | + valid_file &&= File.open(File.join(FIXTURES_DIR, valid_file), "rb") | |
| 306 | + invalid_file &&= File.open(File.join(FIXTURES_DIR, invalid_file), "rb") | |
| 307 | + | |
| 308 | + should_validate validation, options, valid_file, invalid_file | |
| 309 | + end | |
| 310 | + | |
| 311 | + end | |
| 312 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/processor_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class ProcessorTest < Test::Unit::TestCase | |
| 4 | + should "instantiate and call #make when sent #make to the class" do | |
| 5 | + processor = mock | |
| 6 | + processor.expects(:make).with() | |
| 7 | + Paperclip::Processor.expects(:new).with(:one, :two, :three).returns(processor) | |
| 8 | + Paperclip::Processor.make(:one, :two, :three) | |
| 9 | + end | |
| 10 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/storage_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,273 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class StorageTest < Test::Unit::TestCase | |
| 4 | + context "Parsing S3 credentials" do | |
| 5 | + setup do | |
| 6 | + AWS::S3::Base.stubs(:establish_connection!) | |
| 7 | + rebuild_model :storage => :s3, | |
| 8 | + :bucket => "testing", | |
| 9 | + :s3_credentials => {:not => :important} | |
| 10 | + | |
| 11 | + @dummy = Dummy.new | |
| 12 | + @avatar = @dummy.avatar | |
| 13 | + | |
| 14 | + @current_env = RAILS_ENV | |
| 15 | + end | |
| 16 | + | |
| 17 | + teardown do | |
| 18 | + Object.const_set("RAILS_ENV", @current_env) | |
| 19 | + end | |
| 20 | + | |
| 21 | + should "get the correct credentials when RAILS_ENV is production" do | |
| 22 | + Object.const_set('RAILS_ENV', "production") | |
| 23 | + assert_equal({:key => "12345"}, | |
| 24 | + @avatar.parse_credentials('production' => {:key => '12345'}, | |
| 25 | + :development => {:key => "54321"})) | |
| 26 | + end | |
| 27 | + | |
| 28 | + should "get the correct credentials when RAILS_ENV is development" do | |
| 29 | + Object.const_set('RAILS_ENV', "development") | |
| 30 | + assert_equal({:key => "54321"}, | |
| 31 | + @avatar.parse_credentials('production' => {:key => '12345'}, | |
| 32 | + :development => {:key => "54321"})) | |
| 33 | + end | |
| 34 | + | |
| 35 | + should "return the argument if the key does not exist" do | |
| 36 | + Object.const_set('RAILS_ENV', "not really an env") | |
| 37 | + assert_equal({:test => "12345"}, @avatar.parse_credentials(:test => "12345")) | |
| 38 | + end | |
| 39 | + end | |
| 40 | + | |
| 41 | + context "" do | |
| 42 | + setup do | |
| 43 | + AWS::S3::Base.stubs(:establish_connection!) | |
| 44 | + rebuild_model :storage => :s3, | |
| 45 | + :s3_credentials => {}, | |
| 46 | + :bucket => "bucket", | |
| 47 | + :path => ":attachment/:basename.:extension", | |
| 48 | + :url => ":s3_path_url" | |
| 49 | + @dummy = Dummy.new | |
| 50 | + @dummy.avatar = StringIO.new(".") | |
| 51 | + end | |
| 52 | + | |
| 53 | + should "return a url based on an S3 path" do | |
| 54 | + assert_match %r{^http://s3.amazonaws.com/bucket/avatars/stringio.txt}, @dummy.avatar.url | |
| 55 | + end | |
| 56 | + end | |
| 57 | + context "" do | |
| 58 | + setup do | |
| 59 | + AWS::S3::Base.stubs(:establish_connection!) | |
| 60 | + rebuild_model :storage => :s3, | |
| 61 | + :s3_credentials => {}, | |
| 62 | + :bucket => "bucket", | |
| 63 | + :path => ":attachment/:basename.:extension", | |
| 64 | + :url => ":s3_domain_url" | |
| 65 | + @dummy = Dummy.new | |
| 66 | + @dummy.avatar = StringIO.new(".") | |
| 67 | + end | |
| 68 | + | |
| 69 | + should "return a url based on an S3 subdomain" do | |
| 70 | + assert_match %r{^http://bucket.s3.amazonaws.com/avatars/stringio.txt}, @dummy.avatar.url | |
| 71 | + end | |
| 72 | + end | |
| 73 | + context "" do | |
| 74 | + setup do | |
| 75 | + AWS::S3::Base.stubs(:establish_connection!) | |
| 76 | + rebuild_model :storage => :s3, | |
| 77 | + :s3_credentials => { | |
| 78 | + :production => { :bucket => "prod_bucket" }, | |
| 79 | + :development => { :bucket => "dev_bucket" } | |
| 80 | + }, | |
| 81 | + :s3_host_alias => "something.something.com", | |
| 82 | + :path => ":attachment/:basename.:extension", | |
| 83 | + :url => ":s3_alias_url" | |
| 84 | + @dummy = Dummy.new | |
| 85 | + @dummy.avatar = StringIO.new(".") | |
| 86 | + end | |
| 87 | + | |
| 88 | + should "return a url based on the host_alias" do | |
| 89 | + assert_match %r{^http://something.something.com/avatars/stringio.txt}, @dummy.avatar.url | |
| 90 | + end | |
| 91 | + end | |
| 92 | + | |
| 93 | + context "Parsing S3 credentials with a bucket in them" do | |
| 94 | + setup do | |
| 95 | + AWS::S3::Base.stubs(:establish_connection!) | |
| 96 | + rebuild_model :storage => :s3, | |
| 97 | + :s3_credentials => { | |
| 98 | + :production => { :bucket => "prod_bucket" }, | |
| 99 | + :development => { :bucket => "dev_bucket" } | |
| 100 | + } | |
| 101 | + @dummy = Dummy.new | |
| 102 | + @old_env = RAILS_ENV | |
| 103 | + end | |
| 104 | + | |
| 105 | + teardown{ Object.const_set("RAILS_ENV", @old_env) } | |
| 106 | + | |
| 107 | + should "get the right bucket in production" do | |
| 108 | + Object.const_set("RAILS_ENV", "production") | |
| 109 | + assert_equal "prod_bucket", @dummy.avatar.bucket_name | |
| 110 | + end | |
| 111 | + | |
| 112 | + should "get the right bucket in development" do | |
| 113 | + Object.const_set("RAILS_ENV", "development") | |
| 114 | + assert_equal "dev_bucket", @dummy.avatar.bucket_name | |
| 115 | + end | |
| 116 | + end | |
| 117 | + | |
| 118 | + context "An attachment with S3 storage" do | |
| 119 | + setup do | |
| 120 | + rebuild_model :storage => :s3, | |
| 121 | + :bucket => "testing", | |
| 122 | + :path => ":attachment/:style/:basename.:extension", | |
| 123 | + :s3_credentials => { | |
| 124 | + 'access_key_id' => "12345", | |
| 125 | + 'secret_access_key' => "54321" | |
| 126 | + } | |
| 127 | + end | |
| 128 | + | |
| 129 | + should "be extended by the S3 module" do | |
| 130 | + assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3) | |
| 131 | + end | |
| 132 | + | |
| 133 | + should "not be extended by the Filesystem module" do | |
| 134 | + assert ! Dummy.new.avatar.is_a?(Paperclip::Storage::Filesystem) | |
| 135 | + end | |
| 136 | + | |
| 137 | + context "when assigned" do | |
| 138 | + setup do | |
| 139 | + @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb') | |
| 140 | + @dummy = Dummy.new | |
| 141 | + @dummy.avatar = @file | |
| 142 | + end | |
| 143 | + | |
| 144 | + teardown { @file.close } | |
| 145 | + | |
| 146 | + should "not get a bucket to get a URL" do | |
| 147 | + @dummy.avatar.expects(:s3).never | |
| 148 | + @dummy.avatar.expects(:s3_bucket).never | |
| 149 | + assert_match %r{^http://s3\.amazonaws\.com/testing/avatars/original/5k\.png}, @dummy.avatar.url | |
| 150 | + end | |
| 151 | + | |
| 152 | + context "and saved" do | |
| 153 | + setup do | |
| 154 | + AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path, anything, 'testing', :content_type => 'image/png', :access => :public_read) | |
| 155 | + @dummy.save | |
| 156 | + end | |
| 157 | + | |
| 158 | + should "succeed" do | |
| 159 | + assert true | |
| 160 | + end | |
| 161 | + end | |
| 162 | + | |
| 163 | + context "and remove" do | |
| 164 | + setup do | |
| 165 | + AWS::S3::S3Object.stubs(:exists?).returns(true) | |
| 166 | + AWS::S3::S3Object.stubs(:delete) | |
| 167 | + @dummy.destroy_attached_files | |
| 168 | + end | |
| 169 | + | |
| 170 | + should "succeed" do | |
| 171 | + assert true | |
| 172 | + end | |
| 173 | + end | |
| 174 | + end | |
| 175 | + end | |
| 176 | + | |
| 177 | + context "An attachment with S3 storage and bucket defined as a Proc" do | |
| 178 | + setup do | |
| 179 | + AWS::S3::Base.stubs(:establish_connection!) | |
| 180 | + rebuild_model :storage => :s3, | |
| 181 | + :bucket => lambda { |attachment| "bucket_#{attachment.instance.other}" }, | |
| 182 | + :s3_credentials => {:not => :important} | |
| 183 | + end | |
| 184 | + | |
| 185 | + should "get the right bucket name" do | |
| 186 | + assert "bucket_a", Dummy.new(:other => 'a').avatar.bucket_name | |
| 187 | + assert "bucket_b", Dummy.new(:other => 'b').avatar.bucket_name | |
| 188 | + end | |
| 189 | + end | |
| 190 | + | |
| 191 | + context "An attachment with S3 storage and specific s3 headers set" do | |
| 192 | + setup do | |
| 193 | + AWS::S3::Base.stubs(:establish_connection!) | |
| 194 | + rebuild_model :storage => :s3, | |
| 195 | + :bucket => "testing", | |
| 196 | + :path => ":attachment/:style/:basename.:extension", | |
| 197 | + :s3_credentials => { | |
| 198 | + 'access_key_id' => "12345", | |
| 199 | + 'secret_access_key' => "54321" | |
| 200 | + }, | |
| 201 | + :s3_headers => {'Cache-Control' => 'max-age=31557600'} | |
| 202 | + end | |
| 203 | + | |
| 204 | + context "when assigned" do | |
| 205 | + setup do | |
| 206 | + @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb') | |
| 207 | + @dummy = Dummy.new | |
| 208 | + @dummy.avatar = @file | |
| 209 | + end | |
| 210 | + | |
| 211 | + teardown { @file.close } | |
| 212 | + | |
| 213 | + context "and saved" do | |
| 214 | + setup do | |
| 215 | + AWS::S3::Base.stubs(:establish_connection!) | |
| 216 | + AWS::S3::S3Object.stubs(:store).with(@dummy.avatar.path, | |
| 217 | + anything, | |
| 218 | + 'testing', | |
| 219 | + :content_type => 'image/png', | |
| 220 | + :access => :public_read, | |
| 221 | + 'Cache-Control' => 'max-age=31557600') | |
| 222 | + @dummy.save | |
| 223 | + end | |
| 224 | + | |
| 225 | + should "succeed" do | |
| 226 | + assert true | |
| 227 | + end | |
| 228 | + end | |
| 229 | + end | |
| 230 | + end | |
| 231 | + | |
| 232 | + unless ENV["S3_TEST_BUCKET"].blank? | |
| 233 | + context "Using S3 for real, an attachment with S3 storage" do | |
| 234 | + setup do | |
| 235 | + rebuild_model :styles => { :thumb => "100x100", :square => "32x32#" }, | |
| 236 | + :storage => :s3, | |
| 237 | + :bucket => ENV["S3_TEST_BUCKET"], | |
| 238 | + :path => ":class/:attachment/:id/:style.:extension", | |
| 239 | + :s3_credentials => File.new(File.join(File.dirname(__FILE__), "s3.yml")) | |
| 240 | + | |
| 241 | + Dummy.delete_all | |
| 242 | + @dummy = Dummy.new | |
| 243 | + end | |
| 244 | + | |
| 245 | + should "be extended by the S3 module" do | |
| 246 | + assert Dummy.new.avatar.is_a?(Paperclip::Storage::S3) | |
| 247 | + end | |
| 248 | + | |
| 249 | + context "when assigned" do | |
| 250 | + setup do | |
| 251 | + @file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb') | |
| 252 | + @dummy.avatar = @file | |
| 253 | + end | |
| 254 | + | |
| 255 | + teardown { @file.close } | |
| 256 | + | |
| 257 | + should "still return a Tempfile when sent #to_file" do | |
| 258 | + assert_equal Tempfile, @dummy.avatar.to_file.class | |
| 259 | + end | |
| 260 | + | |
| 261 | + context "and saved" do | |
| 262 | + setup do | |
| 263 | + @dummy.save | |
| 264 | + end | |
| 265 | + | |
| 266 | + should "be on S3" do | |
| 267 | + assert true | |
| 268 | + end | |
| 269 | + end | |
| 270 | + end | |
| 271 | + end | |
| 272 | + end | |
| 273 | +end | ... | ... |
vendor/gems/tristandunn-paperclip-2.3.1/test/thumbnail_test.rb
0 → 100644
| ... | ... | @@ -0,0 +1,227 @@ |
| 1 | +require 'test/helper' | |
| 2 | + | |
| 3 | +class ThumbnailTest < Test::Unit::TestCase | |
| 4 | + | |
| 5 | + context "A Paperclip Tempfile" do | |
| 6 | + setup do | |
| 7 | + @tempfile = Paperclip::Tempfile.new("file.jpg") | |
| 8 | + end | |
| 9 | + | |
| 10 | + should "have its path contain a real extension" do | |
| 11 | + assert_equal ".jpg", File.extname(@tempfile.path) | |
| 12 | + end | |
| 13 | + | |
| 14 | + should "be a real Tempfile" do | |
| 15 | + assert @tempfile.is_a?(::Tempfile) | |
| 16 | + end | |
| 17 | + end | |
| 18 | + | |
| 19 | + context "Another Paperclip Tempfile" do | |
| 20 | + setup do | |
| 21 | + @tempfile = Paperclip::Tempfile.new("file") | |
| 22 | + end | |
| 23 | + | |
| 24 | + should "not have an extension if not given one" do | |
| 25 | + assert_equal "", File.extname(@tempfile.path) | |
| 26 | + end | |
| 27 | + | |
| 28 | + should "still be a real Tempfile" do | |
| 29 | + assert @tempfile.is_a?(::Tempfile) | |
| 30 | + end | |
| 31 | + end | |
| 32 | + | |
| 33 | + context "An image" do | |
| 34 | + setup do | |
| 35 | + @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb') | |
| 36 | + end | |
| 37 | + | |
| 38 | + teardown { @file.close } | |
| 39 | + | |
| 40 | + [["600x600>", "434x66"], | |
| 41 | + ["400x400>", "400x61"], | |
| 42 | + ["32x32<", "434x66"] | |
| 43 | + ].each do |args| | |
| 44 | + context "being thumbnailed with a geometry of #{args[0]}" do | |
| 45 | + setup do | |
| 46 | + @thumb = Paperclip::Thumbnail.new(@file, :geometry => args[0]) | |
| 47 | + end | |
| 48 | + | |
| 49 | + should "start with dimensions of 434x66" do | |
| 50 | + cmd = %Q[identify -format "%wx%h" "#{@file.path}"] | |
| 51 | + assert_equal "434x66", `#{cmd}`.chomp | |
| 52 | + end | |
| 53 | + | |
| 54 | + should "report the correct target geometry" do | |
| 55 | + assert_equal args[0], @thumb.target_geometry.to_s | |
| 56 | + end | |
| 57 | + | |
| 58 | + context "when made" do | |
| 59 | + setup do | |
| 60 | + @thumb_result = @thumb.make | |
| 61 | + end | |
| 62 | + | |
| 63 | + should "be the size we expect it to be" do | |
| 64 | + cmd = %Q[identify -format "%wx%h" "#{@thumb_result.path}"] | |
| 65 | + assert_equal args[1], `#{cmd}`.chomp | |
| 66 | + end | |
| 67 | + end | |
| 68 | + end | |
| 69 | + end | |
| 70 | + | |
| 71 | + context "being thumbnailed at 100x50 with cropping" do | |
| 72 | + setup do | |
| 73 | + @thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x50#") | |
| 74 | + end | |
| 75 | + | |
| 76 | + should "report its correct current and target geometries" do | |
| 77 | + assert_equal "100x50#", @thumb.target_geometry.to_s | |
| 78 | + assert_equal "434x66", @thumb.current_geometry.to_s | |
| 79 | + end | |
| 80 | + | |
| 81 | + should "report its correct format" do | |
| 82 | + assert_nil @thumb.format | |
| 83 | + end | |
| 84 | + | |
| 85 | + should "have whiny turned on by default" do | |
| 86 | + assert @thumb.whiny | |
| 87 | + end | |
| 88 | + | |
| 89 | + should "have convert_options set to nil by default" do | |
| 90 | + assert_equal nil, @thumb.convert_options | |
| 91 | + end | |
| 92 | + | |
| 93 | + should "send the right command to convert when sent #make" do | |
| 94 | + Paperclip.expects(:"`").with do |arg| | |
| 95 | + arg.match %r{convert\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+\"x50\"\s+-crop\s+\"100x50\+114\+0\"\s+\+repage\s+".*?"} | |
| 96 | + end | |
| 97 | + @thumb.make | |
| 98 | + end | |
| 99 | + | |
| 100 | + should "create the thumbnail when sent #make" do | |
| 101 | + dst = @thumb.make | |
| 102 | + assert_match /100x50/, `identify "#{dst.path}"` | |
| 103 | + end | |
| 104 | + end | |
| 105 | + | |
| 106 | + context "being thumbnailed with source file options set" do | |
| 107 | + setup do | |
| 108 | + @thumb = Paperclip::Thumbnail.new(@file, | |
| 109 | + :geometry => "100x50#", | |
| 110 | + :source_file_options => "-strip") | |
| 111 | + end | |
| 112 | + | |
| 113 | + should "have source_file_options value set" do | |
| 114 | + assert_equal "-strip", @thumb.source_file_options | |
| 115 | + end | |
| 116 | + | |
| 117 | + should "send the right command to convert when sent #make" do | |
| 118 | + Paperclip.expects(:"`").with do |arg| | |
| 119 | + arg.match %r{convert\s+-strip\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+"x50"\s+-crop\s+"100x50\+114\+0"\s+\+repage\s+".*?"} | |
| 120 | + end | |
| 121 | + @thumb.make | |
| 122 | + end | |
| 123 | + | |
| 124 | + should "create the thumbnail when sent #make" do | |
| 125 | + dst = @thumb.make | |
| 126 | + assert_match /100x50/, `identify "#{dst.path}"` | |
| 127 | + end | |
| 128 | + | |
| 129 | + context "redefined to have bad source_file_options setting" do | |
| 130 | + setup do | |
| 131 | + @thumb = Paperclip::Thumbnail.new(@file, | |
| 132 | + :geometry => "100x50#", | |
| 133 | + :source_file_options => "-this-aint-no-option") | |
| 134 | + end | |
| 135 | + | |
| 136 | + should "error when trying to create the thumbnail" do | |
| 137 | + assert_raises(Paperclip::PaperclipError) do | |
| 138 | + @thumb.make | |
| 139 | + end | |
| 140 | + end | |
| 141 | + end | |
| 142 | + end | |
| 143 | + | |
| 144 | + context "being thumbnailed with convert options set" do | |
| 145 | + setup do | |
| 146 | + @thumb = Paperclip::Thumbnail.new(@file, | |
| 147 | + :geometry => "100x50#", | |
| 148 | + :convert_options => "-strip -depth 8") | |
| 149 | + end | |
| 150 | + | |
| 151 | + should "have convert_options value set" do | |
| 152 | + assert_equal "-strip -depth 8", @thumb.convert_options | |
| 153 | + end | |
| 154 | + | |
| 155 | + should "send the right command to convert when sent #make" do | |
| 156 | + Paperclip.expects(:"`").with do |arg| | |
| 157 | + arg.match %r{convert\s+"#{File.expand_path(@thumb.file.path)}\[0\]"\s+-resize\s+"x50"\s+-crop\s+"100x50\+114\+0"\s+\+repage\s+-strip\s+-depth\s+8\s+".*?"} | |
| 158 | + end | |
| 159 | + @thumb.make | |
| 160 | + end | |
| 161 | + | |
| 162 | + should "create the thumbnail when sent #make" do | |
| 163 | + dst = @thumb.make | |
| 164 | + assert_match /100x50/, `identify "#{dst.path}"` | |
| 165 | + end | |
| 166 | + | |
| 167 | + context "redefined to have bad convert_options setting" do | |
| 168 | + setup do | |
| 169 | + @thumb = Paperclip::Thumbnail.new(@file, | |
| 170 | + :geometry => "100x50#", | |
| 171 | + :convert_options => "-this-aint-no-option") | |
| 172 | + end | |
| 173 | + | |
| 174 | + should "error when trying to create the thumbnail" do | |
| 175 | + assert_raises(Paperclip::PaperclipError) do | |
| 176 | + @thumb.make | |
| 177 | + end | |
| 178 | + end | |
| 179 | + end | |
| 180 | + end | |
| 181 | + | |
| 182 | + context "being thumbnailed with a blank geometry string" do | |
| 183 | + setup do | |
| 184 | + @thumb = Paperclip::Thumbnail.new(@file, | |
| 185 | + :geometry => "", | |
| 186 | + :convert_options => "-gravity center -crop \"300x300+0-0\"") | |
| 187 | + end | |
| 188 | + | |
| 189 | + should "not get resized by default" do | |
| 190 | + assert_no_match(/-resize/, @thumb.transformation_command) | |
| 191 | + end | |
| 192 | + end | |
| 193 | + end | |
| 194 | + | |
| 195 | + context "A multipage PDF" do | |
| 196 | + setup do | |
| 197 | + @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "twopage.pdf"), 'rb') | |
| 198 | + end | |
| 199 | + | |
| 200 | + teardown { @file.close } | |
| 201 | + | |
| 202 | + should "start with two pages with dimensions 612x792" do | |
| 203 | + cmd = %Q[identify -format "%wx%h" "#{@file.path}"] | |
| 204 | + assert_equal "612x792"*2, `#{cmd}`.chomp | |
| 205 | + end | |
| 206 | + | |
| 207 | + context "being thumbnailed at 100x100 with cropping" do | |
| 208 | + setup do | |
| 209 | + @thumb = Paperclip::Thumbnail.new(@file, :geometry => "100x100#", :format => :png) | |
| 210 | + end | |
| 211 | + | |
| 212 | + should "report its correct current and target geometries" do | |
| 213 | + assert_equal "100x100#", @thumb.target_geometry.to_s | |
| 214 | + assert_equal "612x792", @thumb.current_geometry.to_s | |
| 215 | + end | |
| 216 | + | |
| 217 | + should "report its correct format" do | |
| 218 | + assert_equal :png, @thumb.format | |
| 219 | + end | |
| 220 | + | |
| 221 | + should "create the thumbnail when sent #make" do | |
| 222 | + dst = @thumb.make | |
| 223 | + assert_match /100x100/, `identify "#{dst.path}"` | |
| 224 | + end | |
| 225 | + end | |
| 226 | + end | |
| 227 | +end | ... | ... |