pax_global_header 0000666 0000000 0000000 00000000064 12140026204 0014501 g ustar 00root root 0000000 0000000 52 comment=def85e0f4feaf1cc75c08cfc94c0fb83bf5997a0
ruby-carrierwave-0.8.0/ 0000775 0000000 0000000 00000000000 12140026204 0014777 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/.gitignore 0000664 0000000 0000000 00000000267 12140026204 0016774 0 ustar 00root root 0000000 0000000 doc
.yardoc
.DS_Store
spec/public
pkg
doc
more/activerecord/spec/db
more/activerecord/spec/public
more/datamapper/spec/public
*.project
spec/test.log
*.swp
.rvmrc
.bundle
Gemfile.lock ruby-carrierwave-0.8.0/.travis.yml 0000664 0000000 0000000 00000000772 12140026204 0017116 0 ustar 00root root 0000000 0000000 before_install:
- gem install bundler --pre
notifications:
email: false
rvm:
- 1.8.7
- 1.9.2
- 1.9.3
- 2.0.0
- ree
gemfile:
- gemfiles/rails3_2.gemfile
- gemfiles/rails_master.gemfile
matrix:
allow_failures:
- rvm: 2.0.0
exclude:
- rvm: 1.8.7
gemfile: gemfiles/rails_master.gemfile
- rvm: 1.9.2
gemfile: gemfiles/rails_master.gemfile
- rvm: ree
gemfile: gemfiles/rails_master.gemfile
before_script:
- "mysql -e 'create database carrierwave_test;'"
ruby-carrierwave-0.8.0/CONTRIBUTING.md 0000664 0000000 0000000 00000002150 12140026204 0017226 0 ustar 00root root 0000000 0000000 # Contributing to CarrierWave
CarrierWave thrives on a large number of [contributors](https://github.com/jnicklas/carrierwave/contributors),
and pull requests are very welcome. Before submitting a pull request, please make sure that your changes are well tested.
First, make sure you have `imagemagick` and `ghostscript` installed.
Then, you'll need to install bundler and the gem dependencies:
gem install bundler
bundle install
You should now be able to run the local tests:
bundle exec rake
You can also run the remote specs by creating a ~/.fog file:
```yaml
:carrierwave:
:aws_access_key_id: xxx
:aws_secret_access_key: yyy
:rackspace_username: xxx
:rackspace_api_key: yyy
:google_storage_access_key_id: xxx
:google_storage_secret_access_key: yyy
```
You should now be able to run the remote tests:
REMOTE=true bundle exec rake
Please test with the latest Ruby 1.8.x and 1.9.x versions using RVM if possible.
## Running active record tests
Make sure you have a local MySQL database named `carrierwave_test` with the username
`root` and empty password.
ruby-carrierwave-0.8.0/Gemfile 0000664 0000000 0000000 00000000047 12140026204 0016273 0 ustar 00root root 0000000 0000000 source "https://rubygems.org"
gemspec
ruby-carrierwave-0.8.0/History.txt 0000664 0000000 0000000 00000043726 12140026204 0017215 0 ustar 00root root 0000000 0000000 === Version 0.8.0 2013-01-08
* [BREAKING CHANGE] Remove 'fog_endpoint' in favor of 'host' and/or 'endpoint' in fog_credentials [bensie]
* [changed] Remove autoload in favor of standard 'require' to help with thread safety [bensie]
* [added] Allow recreating only specified versions instead of all versions [div]
* [added] Add support for S3-compliant storage APIs that are not actually S3 [neuhausler]
* [added] Add #extension CarrierWave::Storage::Fog::File for fetching a file extension [sweatypitts]
* [fixed] Marshaling uploader objects no longer raises a TypeError on anonymous classes [bensie]
=== Version 0.7.1 2012-11-08
* [added] add a override to allow fog configuration per uploader [dei79]
* [fixed] Fix a regression when removing uploads [mattolson]
=== Version 0.7.0 2012-10-19
* [BREAKING CHANGE] Rename 'fog_host' config option to 'asset_host' and add support for file storage [DouweM]
* [changed] Changed after_destroy with after_commit ... :on => :destroy [Cristian Sorinel]
* [changed] Do not handle any special cases for URL handling, keep the existing escape/unescape functionality and allow overriding [bensie]
* [changed] Activerecord-deprecated_finders gem was renamed [bensie]
* [changed] Removed unnecessary present? method from ActiveSupport [Yauheni Kryudziuk]
* [changed] Use AWS S3 subdomain URL when directory name contains a period. [DouweM]
* [added] Added resize_to_geometry_string RMagick method that will scale image [wprater]
* [added] Made feature to blacklist certain extensions [thiagofm]
* [added] Parse and pass fog_host option to ::Fog::Storage [Yauheni Kryudziuk]
* [added] Add serialization spec for multiple uploaders. [malclocke]
* [added] Add :read option to manipulate! [xtreme-tanzeeb-khalili]
* [added] Add binary/octet-stream as generic mime type. [phiggins]
* [added] Add 'fog_endpoint' config option to set an alternate Fog host. [DouweM]
* [fixed] Fixed can't convert File into String [jnimety]
* [fixed] Fixed an issue when parsing URL w/o schema. [Yauheni Kryudziuk]
* [fixed] Fix reference to column in serializable_hash [malclocke]
* [fixed] Fix inconsistence in file API [oelmekki]
=== Version 0.6.2 2012-04-12
* [fixed] Don't double-generate cache_id [skyeagle]
* [added] Escape plus signs (+) in remote URLs [adrianpike]
* [added] Enhance multi-page PDF support in RMagick [xtreme-tanzeeb-khalili]
=== Version 0.6.1 2012-04-02
* [fixed] Calling #serializable_hash with no options [matthewrudy]
=== Version 0.6.0 2012-03-27
* [BREAKING CHANGE] Require Rails 3.2 or Rails master (4.0) - depends on activesupport/activemodel [bensie]
* [BREAKING CHANGE] Remove :S3 storage option in favor of Fog [bensie]
* [BREAKING CHANGE] Remove :CloudFiles storage option in favor of Fog [bensie]
* [changed] JSON / XML serialization hashes are consistent and work as expected with ActiveRecord's serializable_hash [bensie]
* [added] fog_host now accepts a proc (useful for dynamic asset servers) [jtrim]
* [added] Add ability to process a version from an existing version so you aren't always crunching the original, large file [ferblape]
* [added] Allow brackets in remote URLs [ngauthier]
* [added] CarrierWave::Storage::Fog::File#exists? to check the existence of the file without needing to fetch it [bensie]
* [added] Gravity option on resize_to_fill (minimagick) [TheOddLinguist]
* [added] Add query options for s3 to support response headers overwriting [meceo]
* [added] Make storages File#url methods to work without any params [meceo]
* [added] Set the CarrierWave.root correctly if Padrino is defined [futurechimp]
* [added] Cache fog connections for improved performance [labocho]
* [fixed] Fix slow fetching of content-length on remote file [geemus]
* [fixed] Fog remote specs now passing and depend on Fog >= 1.3.1 [geemus]
* [fixed] Fix an issue where multi-page PDFs can't be converted with RMagick [chanind]
* [fixed] MiniMagick expects string args to mogrify commands [bensie]
* [fixed] With Active Record ORM, setting remote_url marks mounted column as dirty [trevorturk]
* [fixed] Fix possible race condition with CarrierWave.root [bensie]
* [fixed] ActiveSupport::Memoizable deprecation warning [slbug]
=== Version 0.5.8 2011-11-10
* [added] Allow custom error messages [bartt]
* [added] Add config.base_path to use as a prefix for uploader URLs [die-antwort]
* [added] Support fog streaming uploads [chrisdurtschi]
* [added] Support `move_to` in addition to the default `copy_to` when using the cache [jasonydes]
* [fixed] Support for Sinatra 1.3 (with backward compatibility) [bensie]
* [fixed] Fog get_object_url deprecated, use get_object_https_url or get_object_http_url [scottmessinger]
=== Version 0.5.7 2011-08-12
* [BREAKING CHANGE] Extracted Mongoid support into a separate gem (carrierwave-mongoid) [jnicklas]
* [BREAKING CHANGE] Remove ImageScience support due to lack maintenance and 1.9.2 compatibility [jnicklas]
* [BREAKING CHANGE] Combine delete_tmp_file_after_storage and delete_cache_id_after_storage options [bensie]
* [changed] Cached and then remote-uploaded file will no longer have a content_type, please use CarrierWave::MimeTypes processor instead [trevorturk]
* [changed] Allow writing over a previously assigned file when retrieving a remote file [Florent2]
* [fixed] Fixed exception when nested or double-embedded Mongoid documents are saved [potatosalad]
* [fixed] Fixed that store! can call process! twice [gzigzigzeo]
* [fixed] Performance enhancements by reducing use of rescue [jamescook]
=== Version 0.5.6 2011-07-12
* [fixed] Remove cache file and directories after storing [scottwb]
* [fixed] Add missing active_support/deprecation require [trevorturk]
* [fixed] Remove redundant requires of sequel and datamapper [solnic]
* [fixed] Running tests with REMOTE=true [geemus]
=== Version 0.5.5 2011-07-09
* [BREAKING CHANGE] Extracted DataMapper support into a separate gem (carrierwave-datamapper) [jnicklas]
* [BREAKING CHANGE] Extracted Sequel support into a separate gem (carrierwave-sequel) [jnicklas]
* [changed] Don't downcase filenames by default [bensie]
* [changed] Orm mount modules default uploader to nil [jnicklas]
* [changed] Remove alias_method :blank? from SanitizedFile to for performance re: issue #298 [trevorturk]
* [added] Conditional processing of versions [gucki]
* [added] Remove Remove previously stored files after Active Record mounted uploader update re: issue #75 [trevorturk]
* [added] Remove Remove previously stored files after Mongoid mounted uploader update re: issue #75 [did]
* [added] Added _identifier to retrieve identifier/filename [jnicklas]
* [added] clean_cached_files! clears all files older than 24 hours by default, but time frame can now be customized [cover]
* [added] Versions now implement an enable_processing method which uses the parent when no value is set [mariovisic]
* [added] Delete cache_id garbage dirs, closes GH issue #338 [clyfe]
* [added] Added CarrierWave::MimeTypes processor for more advanced content-type guessing [JangoSteve]
* [fixed] Active Record's will_change! method works when mount_on option is used [indrekj]
* [fixed] Fixed problem with accepting URL uploads when the URL was already escaped [cover]
* [fixed] Fixed ability to override sanitize_regexp [trevorturk]
* [fixed] Fix that cached and then remote-uploaded file should have content_type [trevorturk]
* [fixed] Fix validates_size/length_of in Rails 3.0.6 and above, closes #342 [bensie]
* [fixed] Various Active Support compatibility updates [slbug, bensie, et al]
=== Version 0.5.4 2011-05-18
* [changed] Fog: Performance enhancements for AWS and Google [geemus]
* [changed] Fog: Try to use subdomain public url on s3 [geemus]
* [changed] Memoize CarrierWave::Mounter#option for increased performance [ingemar]
* [changed] Relax development gem dependency versions where possible and fix tests [trevorturk]
* [changed] Upgrade to RSpec 2 [jnicklas]
=== Version 0.5.3 2011-03-22
* [changed] Cloud Files storage so delete and url return nil if object not found instead of exception [minter]
* [added] New fog storage provider that supports Amazon S3, Rackspace Cloud Files, and Google Storare for Developers [geemus]
* [added] cloud_files_auth_url and cloud_files_snet config options for Cloud Files [minter]
* [added] process_uri method that can be overridden in your uploader to support downloads from non-standard urls [trevorturk]
* [added] version urls to json output [karb]
* [added] Active Record marks uploader column as changed when changed [josevalim]
* [fixed] Cloud Files storage tests to use the new url format [minter]
* [fixed] Moved raising of FormNotMultipart farther down to avoid errors with nested attribute forms [trevorturk]
* [fixed] original_filename of remote uploads should be calculated from final (possibly redirected) URL [brady8]
* [fixed] Fix calling :process! on files stored in remote solutions [alexcrichton]
* [fixed] Fix paperclip compatibility mappings [valakirka]
* [fixed] Ensure temporary files can be deleted on Windows [Eleo]
=== Version 0.5.2 2011-02-18
* [changed] Require active_support/core_ext/string/multibyte to fix downcasing unicode filenames during sanitizing [nashbridges]
* [changed] Use fog ~> 0.4, Fog::AWS::Storage.new -> Fog::Storage.new(:provider => 'AWS') [trevorturk]
* [changed] Use class_attribute (inheritable attributes are deprecated) [stephencelis]
* [changed] extension_white_list no longer supports a single string, only an array of strings and/or Regexps [trevorturk]
* [changed] Rackspace Cloud Files: only create container if container does not exist [edmundsalvacion]
* [changed] GridFS: the path returned is no longer always nil, it is now the path in GridFS [alexcrichton]
* [added] Ability to specify a Regexp in the extension_white_list [lwe]
* [added] CarrierWave::SanitizedFile#sanitize_regexp public method to allow customizing [trevorturk]
* [added] sanitize_regexp documentation to the README [nashbridges]
* [added] Ability to use https for Amazon S3 URLs if config.s3_use_ssl is true [recruitmilitary]
* [added] The s3_region configuration documentation to the README [mrsimo]
* [fixed] Reprocessing remotely stored files [alexcrichton]
* [fixed] Nested versioning processing [alexcrichton]
* [fixed] An intermittent bug with ImageScience resize_to_fill method [LupineDev]
* [fixed] DataMapper#save should remove the avatar if remove_avatar? returns true [wprater]
=== Version 0.5.1 2010-12-01
* [changed] s3_access renamed to s3_access_policy [Jonas Nicklas]
* [changed] Depend on activesupport ~> 3.0 for Rails 3.1 compatibility [Trevor Turk]
* [changed] Use fog >= 0.3.0, fix deprecation warnings [Paul Elliott]
* [changed] Use mini_magick ~> 2.3, MiniMagick::Image.from_file becomes MiniMagick::Image.open [Fredrik Björk]
* [changed] Convert generic MiniMagick::Invalid into ProcessingError [Alex Crichton]
* [changed] Remove cached tmp file after storing for file store [Damien Mathieu]
* [added] s3_region config option to set AWS S3 region [Roger Campos]
* [added] Option to retain cached tmp file after storage (delete_tmp_file_after_storage) [Damien Mathieu]
* [added] Transparent support for authenticated_read on S3 [Jonas Nicklas]
* [fixed] Clean up internal require statements [Josh Kalderimis]
* [fixed] Header support for S3 [Alex Crichton]
* [fixed] Stack level too deep errors when using to_json [Trevor Turk]
* [fixed] Documentation for mount_uploader [Nathan Kleyn]
=== Version 0.5 2010-09-23
* [changed] Use ActiveModel instead of ActiveRecord validations to support Mongoid validations as well [Jeroen van Dijk, saberma]
* [changed] Support S3 file storage with the fog gem, instead of the aws gem (Trevor Turk)
* [changed] Move translations to a YAML file (Josh Kalderimis)
* [changed] Depend on activesupport ~> 3.0.0 instead of >= 3.0.0.rc (Trevor Turk)
* [changed] Remove old Merb and Rails generators, support Rails 3 generators (Jonas Nicklas, Trevor Turk)
* [changed] Replace Net::HTTP with open-url for remote file downloads (icebreaker)
* [changed] Move translations to a YAML file (Josh Kalderimis)
* [changed] Use gemspec to generate Gemfile contents (Jonas Nicklas)
* [added] Add file size support for S3 storage (Pavel Chipiga)
* [added] Add option for disabling multipart form check (Dennis Blöte)
* [fixed] Correct naming of validators (Josh Kalderimis)
* [fixed] Fix remote file downloader (Jonas Nicklas)
* [fixed] Escape URLs passed to remote file downloader so URLs with spaces work (Mauricio Zaffari)
* [fixed] Correct filename used in generators (Fred Wu)
=== Version 0.4.6 2010-07-20
* [removed] Support for MongoMapper, see: http://groups.google.com/group/carrierwave/browse_thread/thread/56df146b83878c22
* [changed] AWS support now uses the aws gem, instead of using aws-s3 or right-aws as previously
* [added] cloud_files_cdn_host for Cloudfiles for performance gain
* [added] #recreate_versions! to recreate versions from base file
* [added] Support for MiniMagick in RSpec matchers
* [added] RMagick's #resize_to_fill now takes an optional Gravity
* [fixed] Pass through options to to_json
* [fixed] Support new GridFS syntax for lates mongo gem
* [fixed] Validation errors are internationalized when the error is thrown, not on load
* [fixed] Rescue correct MiniMagick error
* [fixed] Support DataMapper 1.0
* [fixed] SanitizedFile#copy_to preserves content_type. Should fix GridFS content type not being set.
=== Version 0.4.5 2010-02-20
* [added] Support for Rackspace Cloudfiles
* [added] GridFS now accepts a port
* [fixed] s3_headers is now properly initialized
* [fixed] work around DataMapper's patching of core method
=== Version 0.4.4 2010-01-31
* [added] Support for downloading remote files
* [added] CarrierWave.clean_cached_files! to remove old cached files
* [added] Option to set headers for S3
* [added] GridStore now has authentication
* [fixed] Rmagick convert method now does what it says
* [fixed] Content type is stored on GridStore and Amazon S3
* [fixed] Metadata is no longer broken for S3
=== Version 0.4.3 2009-12-19
* [fixed] cnamed URLs on S3 no longer have a third slash after http
* [fixed] fixed deprecation warnings on Rails 2.3.5
=== Version 0.4.2 2009-11-26
* [added] RightAWS as an alternative S3 implementation
* [added] An option to enable/disable processing for tests
* [added] Mongoid ORM support
* [fixed] DataMapper now works both with and without dm-validations
=== Version 0.4.1 2009-10-26
* [changed] Major changes to the ImageScience module, it actually works now!
* [fixed] Bug in configuration where it complais that it can't dup Symbol
* [removed] Support for Sequel < 2.12
* [removed] `crop_resized` and `resize` aliases in RMagick, use `resize_to_fill` and `resize_to_fit` respectively
=== Version 0.4.0 2009-10-12
* [changed] the `public` option has been renamed `root` and the old `root` option was removed. No more ambiguity.
* [changed] Major *breaking* changes to the configuration syntax.
* [removed] support for `default_path`
* [removed] the `cache_to_cache_dir` option
* [removed] storage no longer calls `setup!` on storage engines
* [added] Support for MongoDB's GridFS store
=== Version 0.3.4 2009-09-01
* [added] `default_url` as a replacement for `default_path`
* [deprecated] `default_path` is deprecated
=== Version 0.3.4 2009-08-31
* [fixed] Deleting no longer causes TypeError in MongoMapper
=== Version 0.3.3 2009-08-29
* [added] Support for MongoMapper
* [added] Support for CNamed Bucket URLs for Amazon S3
=== Version 0.3.2 2009-07-18
Incremental upgrade
* [added] Ruby 1.9 compatibility
* [changed] Added Object#blank? implementation into CarrierWave, which removes any dpendencies on external libraries (extlib/activesupport)
* [fixed] Performance issues with S3 support
* [fixed] Sequel support for newer verions of Sequel (thanks Pavel!)
=== Version 0.3.1 2009-07-01
A bugfix release. Drop in compatible with 0.3.0.
* [fixed] Saving a record with a mounted Uploader no longer removes uploaded file
* [fixed] The file returned by S3 storage now has the path set to the full store path
* [added] File returned by S3 storage now responds to S3 specific methods
=== 0.3 2009-06-20
This is a stabilization release. Most features are now working as expected and
most bugs should be fixed.
* [changed] Reworked how storage engines work, some internal API changes
* [added] Macro-like methods for RMagick, no need to call #process any more!
* [added] Ability to super to any Mount method
* [fixed] Sequel support should now work as expected
* [fixed] ActiveRecord no longer saves the record twice
* [added] Added convenient macro style class methods to rmagick processing
=== 0.2.4 2009-06-11
* [added] `resize_to_limit` method for rmagick
* [added] Now deletes files from Amazon S3 when record is destroyed
=== 0.2.3 2009-05-13
* [changed] Mount now no longer returns nil if there is no stored file, it returns a blank uploader instead
* [added] Possibility to specify a default path
* [added] Paperclip compatibility module
=== 0.2.1 2009-05-01
* [changed] Url method now optionally takes versions as parameters (like Paperclip)
* [added] A field which allows files to be removed with a checkbox in mount
* [added] Mount_on option for Mount, to be able to override the serialization column
* [added] Added demeter friendly column_url method to Mount
* [added] Option to not copy files to cache dir, to prevent writes on read only fs systems (this is a workaround and needs a better solution)
=== 0.2 2009-04-15
* [changed] The version is no longer stored in the store dir. This will break the paths for files uploaded with 0.1
* [changed] CarrierWave::Uploader is now a module, not a class, so you need to include it, not inherit from it.
* [added] integrity checking in uploaders via a white list of extensions
* [added] Validations for integrity and processing in ActiveRecord, activated by default
* [added] Support for nested versions
* [added] Permissions option to set the permissions of the uploaded files
* [added] Support for Sequel
* [added] CarrierWave::Uploader#read to read the contents of the uploaded files
=== 0.1 2009-03-12
This is a very experimental release that has not been well tested. All of the major features are in place though. Please note that there currently is a bug with load paths in Merb, which means you need to manually require uploaders.
ruby-carrierwave-0.8.0/README.md 0000664 0000000 0000000 00000054224 12140026204 0016265 0 ustar 00root root 0000000 0000000 # CarrierWave
This gem provides a simple and extremely flexible way to upload files from Ruby applications.
It works well with Rack based web applications, such as Ruby on Rails.
[](http://travis-ci.org/jnicklas/carrierwave)
[](https://codeclimate.com/github/jnicklas/carrierwave)
## Information
* RDoc documentation [available on RubyDoc.info](http://rubydoc.info/gems/carrierwave/frames)
* Source code [available on GitHub](http://github.com/jnicklas/carrierwave)
* More information, known limitations, and how-tos [available on the wiki](https://github.com/jnicklas/carrierwave/wiki)
## Getting Help
* Please ask the [Google Group](http://groups.google.com/group/carrierwave) for help if you have any questions.
* Please report bugs on the [issue tracker](http://github.com/jnicklas/carrierwave/issues) but read the "getting help" section in the wiki first.
## Installation
Install the latest stable release:
[sudo] gem install carrierwave
In Rails, add it to your Gemfile:
```ruby
gem 'carrierwave'
```
Finally, restart the server to apply the changes.
Note that CarrierWave is not compatible with Rails 2 as of version 0.5. If you want to use
Rails 2, please use the 0.4-stable branch on GitHub.
## Getting Started
Start off by generating an uploader:
rails generate uploader Avatar
this should give you a file in:
app/uploaders/avatar_uploader.rb
Check out this file for some hints on how you can customize your uploader. It
should look something like this:
```ruby
class AvatarUploader < CarrierWave::Uploader::Base
storage :file
end
```
You can use your uploader class to store and retrieve files like this:
```ruby
uploader = AvatarUploader.new
uploader.store!(my_file)
uploader.retrieve_from_store!('my_file.png')
```
CarrierWave gives you a `store` for permanent storage, and a `cache` for
temporary storage. You can use different stores, including filesystem
and cloud storage.
Most of the time you are going to want to use CarrierWave together with an ORM.
It is quite simple to mount uploaders on columns in your model, so you can
simply assign files and get going:
### ActiveRecord
Make sure you are loading CarrierWave after loading your ORM, otherwise you'll
need to require the relevant extension manually, e.g.:
```ruby
require 'carrierwave/orm/activerecord'
```
Add a string column to the model you want to mount the uploader on:
```ruby
add_column :users, :avatar, :string
```
Open your model file and mount the uploader:
```ruby
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
end
```
Now you can cache files by assigning them to the attribute, they will
automatically be stored when the record is saved.
```ruby
u = User.new
u.avatar = params[:file]
u.avatar = File.open('somewhere')
u.save!
u.avatar.url # => '/url/to/file.png'
u.avatar.current_path # => 'path/to/file.png'
u.avatar.identifier # => 'file.png'
```
### DataMapper, Mongoid, Sequel
Other ORM support has been extracted into separate gems:
* [carrierwave-datamapper](https://github.com/jnicklas/carrierwave-datamapper)
* [carrierwave-mongoid](https://github.com/jnicklas/carrierwave-mongoid)
* [carrierwave-sequel](https://github.com/jnicklas/carrierwave-sequel)
There are more extensions listed in [the wiki](https://github.com/jnicklas/carrierwave/wiki)
## Changing the storage directory
In order to change where uploaded files are put, just override the `store_dir`
method:
```ruby
class MyUploader < CarrierWave::Uploader::Base
def store_dir
'public/my/upload/directory'
end
end
```
This works for the file storage as well as Amazon S3 and Rackspace Cloud Files.
Define `store_dir` as `nil` if you'd like to store files at the root level.
## Securing uploads
Certain file might be dangerous if uploaded to the wrong location, such as php
files or other script files. CarrierWave allows you to specify a white-list of
allowed extensions.
If you're mounting the uploader, uploading a file with the wrong extension will
make the record invalid instead. Otherwise, an error is raised.
```ruby
class MyUploader < CarrierWave::Uploader::Base
def extension_white_list
%w(jpg jpeg gif png)
end
end
```
### Filenames and unicode chars
Another security issue you should care for is the file names (see
[Ruby On Rails Security Guide](http://guides.rubyonrails.org/security.html#file-uploads)).
By default, CarrierWave provides only English letters, arabic numerals and '-+_.' symbols as
white-listed characters in the file name. If you want to support local scripts (Cyrillic letters, letters with diacritics and so on), you
have to override `sanitize_regexp` method. It should return regular expression which would match
all *non*-allowed symbols.
With Ruby 1.9 and higher you can simply write (as it has [Oniguruma](http://oniguruma.rubyforge.org/oniguruma/)
built-in):
```ruby
CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/
```
With Ruby 1.8 you have to manually specify all character ranges. For example, for files which may
contain Russian letters:
```ruby
CarrierWave::SanitizedFile.sanitize_regexp = /[^a-zA-Zа-яА-ЯёЁ0-9\.\-\+_]/u
```
Also make sure that allowing non-latin characters won't cause a compatibility issue with a third-party
plugins or client-side software.
## Setting the content type
If you care about the content type of your files and notice that it's not being set
as expected, you can configure your uploaders to use `CarrierWave::MimeTypes`.
This adds a dependency on the [mime-types](http://rubygems.org/gems/mime-types) gem,
but is recommended when using fog, and fog already has a dependency on mime-types.
```ruby
require 'carrierwave/processing/mime_types'
class MyUploader < CarrierWave::Uploader::Base
include CarrierWave::MimeTypes
process :set_content_type
end
```
## Adding versions
Often you'll want to add different versions of the same file. The classic
example is image thumbnails. There is built in support for this:
```ruby
class MyUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
process :resize_to_fit => [800, 800]
version :thumb do
process :resize_to_fill => [200,200]
end
end
```
When this uploader is used, an uploaded image would be scaled to be no larger
than 800 by 800 pixels. A version called thumb is then created, which is scaled
and cropped to exactly 200 by 200 pixels. The uploader could be used like this:
```ruby
uploader = AvatarUploader.new
uploader.store!(my_file) # size: 1024x768
uploader.url # => '/url/to/my_file.png' # size: 800x800
uploader.thumb.url # => '/url/to/thumb_my_file.png' # size: 200x200
```
One important thing to remember is that process is called *before* versions are
created. This can cut down on processing cost.
It is possible to nest versions within versions:
```ruby
class MyUploader < CarrierWave::Uploader::Base
version :animal do
version :human
version :monkey
version :llama
end
end
```
### Conditional versions
Occasionally you want to restrict the creation of versions on certain
properties within the model or based on the picture itself.
```ruby
class MyUploader < CarrierWave::Uploader::Base
version :human, :if => :is_human?
version :monkey, :if => :is_monkey?
version :banner, :if => :is_landscape?
protected
def is_human? picture
model.can_program?(:ruby)
end
def is_monkey? picture
model.favorite_food == 'banana'
end
def is_landscape? picture
image = MiniMagick::Image.open(picture.path)
image[:width] > image[:height]
end
end
```
The `model` variable points to the instance object the uploader is attached to.
### Create versions from existing versions
For performance reasons, it is often useful to create versions from existing ones
instead of using the original file. If your uploader generates several versions
where the next is smaller than the last, it will take less time to generate from
a smaller, already processed image.
```ruby
class MyUploader < CarrierWave::Uploader::Base
version :thumb do
process resize_to_fill: [280, 280]
end
version :small_thumb, :from_version => :thumb do
process resize_to_fill: [20, 20]
end
end
```
The option `:from_version` uses the file cached in the `:thumb` version instead
of the original version, potentially resulting in faster processing.
## Making uploads work across form redisplays
Often you'll notice that uploaded files disappear when a validation fails.
CarrierWave has a feature that makes it easy to remember the uploaded file even
in that case. Suppose your `user` model has an uploader mounted on `avatar`
file, just add a hidden field called `avatar_cache` (don't forget to add it to
the attr_accessible list as necessary). In Rails, this would look like this:
```erb
<%= form_for @user, :html => {:multipart => true} do |f| %>
<% end %>
````
It might be a good idea to show the user that a file has been uploaded, in the
case of images, a small thumbnail would be a good indicator:
```erb
<%= form_for @user, :html => {:multipart => true} do |f| %>
<% end %>
```
## Removing uploaded files
If you want to remove a previously uploaded file on a mounted uploader, you can
easily add a checkbox to the form which will remove the file when checked.
```erb
<%= form_for @user, :html => {:multipart => true} do |f| %>
<%= image_tag(@user.avatar_url) if @user.avatar? %>
<%= f.file_field :avatar %>
<% end %>
```
If you want to remove the file manually, you can call remove_avatar!.
## Uploading files from a remote location
Your users may find it convenient to upload a file from a location on the Internet
via a URL. CarrierWave makes this simple, just add the appropriate attribute to your
form and you're good to go:
```erb
<%= form_for @user, :html => {:multipart => true} do |f| %>
<%= image_tag(@user.avatar_url) if @user.avatar? %>
<%= f.text_field :remote_avatar_url %>
<% end %>
```
## Providing a default URL
In many cases, especially when working with images, it might be a good idea to
provide a default url, a fallback in case no file has been uploaded. You can do
this easily by overriding the `default_url` method in your uploader:
```ruby
class MyUploader < CarrierWave::Uploader::Base
def default_url
"/images/fallback/" + [version_name, "default.png"].compact.join('_')
end
end
```
## Recreating versions
You might come to a situation where you want to retroactively change a version
or add a new one. You can use the recreate_versions! method to recreate the
versions from the base file. This uses a naive approach which will re-upload and
process the specified version or all versions, if none is passed as an argument.
```ruby
instance = MyUploader.new
instance.recreate_versions!(:thumb, :large)
```
Or on a mounted uploader:
```ruby
User.all.each do |user|
user.avatar.recreate_versions!
end
```
## Configuring CarrierWave
CarrierWave has a broad range of configuration options, which you can configure,
both globally and on a per-uploader basis:
```ruby
CarrierWave.configure do |config|
config.permissions = 0666
config.directory_permissions = 0777
config.storage = :file
end
```
Or alternatively:
```ruby
class AvatarUploader < CarrierWave::Uploader::Base
permissions 0777
end
```
If you're using Rails, create an initializer for this:
```ruby
config/initializers/carrierwave.rb
```
## Testing with CarrierWave
It's a good idea to test your uploaders in isolation. In order to speed up your
tests, it's recommended to switch off processing in your tests, and to use the
file storage. In Rails you could do that by adding an initializer with:
```ruby
if Rails.env.test? or Rails.env.cucumber?
CarrierWave.configure do |config|
config.storage = :file
config.enable_processing = false
end
end
```
If you need to test your processing, you should test it in isolation, and enable
processing only for those tests that need it.
CarrierWave comes with some RSpec matchers which you may find useful:
```ruby
require 'carrierwave/test/matchers'
describe MyUploader do
include CarrierWave::Test::Matchers
before do
MyUploader.enable_processing = true
@uploader = MyUploader.new(@user, :avatar)
@uploader.store!(File.open(path_to_file))
end
after do
MyUploader.enable_processing = false
@uploader.remove!
end
context 'the thumb version' do
it "should scale down a landscape image to be exactly 64 by 64 pixels" do
@uploader.thumb.should have_dimensions(64, 64)
end
end
context 'the small version' do
it "should scale down a landscape image to fit within 200 by 200 pixels" do
@uploader.small.should be_no_larger_than(200, 200)
end
end
it "should make the image readable only to the owner and not executable" do
@uploader.should have_permissions(0600)
end
end
```
Setting the enable_processing flag on an uploader will prevent any of the versions from processing as well.
Processing can be enabled for a single version by setting the processing flag on the version like so:
```ruby
@uploader.thumb.enable_processing = true
```
## Using Amazon S3
[Fog](http://github.com/fog/fog) is used to support Amazon S3. Ensure you have it in your Gemfile:
```ruby
gem "fog", "~> 1.3.1"
```
You'll need to provide your fog_credentials and a fog_directory (also known as a bucket) in an initializer.
For the sake of performance it is assumed that the directory already exists, so please create it if need be.
You can also pass in additional options, as documented fully in lib/carrierwave/storage/fog.rb. Here's a full example:
```ruby
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'AWS', # required
:aws_access_key_id => 'xxx', # required
:aws_secret_access_key => 'yyy', # required
:region => 'eu-west-1', # optional, defaults to 'us-east-1'
:hosts => 's3.example.com', # optional, defaults to nil
:endpoint => 'https://s3.example.com:8080' # optional, defaults to nil
}
config.fog_directory = 'name_of_directory' # required
config.fog_public = false # optional, defaults to true
config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {}
end
```
In your uploader, set the storage to :fog
```ruby
class AvatarUploader < CarrierWave::Uploader::Base
storage :fog
end
```
That's it! You can still use the `CarrierWave::Uploader#url` method to return the url to the file on Amazon S3.
## Using Rackspace Cloud Files
[Fog](http://github.com/fog/fog) is used to support Rackspace Cloud Files. Ensure you have it in your Gemfile:
```ruby
gem "fog", "~> 1.3.1"
```
You'll need to configure a directory (also known as a container), username and API key in the initializer.
For the sake of performance it is assumed that the directory already exists, so please create it if need be.
```ruby
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'Rackspace',
:rackspace_username => 'xxxxxx',
:rackspace_api_key => 'yyyyyy'
}
config.fog_directory = 'name_of_directory'
end
```
You can optionally include your CDN host name in the configuration.
This is *highly* recommended, as without it every request requires a lookup
of this information.
```ruby
config.asset_host = "http://c000000.cdn.rackspacecloud.com"
```
In your uploader, set the storage to :fog
```ruby
class AvatarUploader < CarrierWave::Uploader::Base
storage :fog
end
```
That's it! You can still use the `CarrierWave::Uploader#url` method to return
the url to the file on Rackspace Cloud Files.
## Using Google Storage for Developers
[Fog](http://github.com/fog/fog) is used to support Google Storage for Developers. Ensure you have it in your Gemfile:
```ruby
gem "fog", "~> 1.3.1"
```
You'll need to configure a directory (also known as a bucket), access key id and secret access key in the initializer.
For the sake of performance it is assumed that the directory already exists, so please create it if need be.
Sign up [here](http://gs-signup-redirect.appspot.com/) and get your credentials [here](https://storage.cloud.google.com/m)
under the section “Interoperable Access”.
```ruby
CarrierWave.configure do |config|
config.fog_credentials = {
:provider => 'Google',
:google_storage_access_key_id => 'xxxxxx',
:google_storage_secret_access_key => 'yyyyyy'
}
config.fog_directory = 'name_of_directory'
end
```
In your uploader, set the storage to :fog
```ruby
class AvatarUploader < CarrierWave::Uploader::Base
storage :fog
end
```
That's it! You can still use the `CarrierWave::Uploader#url` method to return
the url to the file on Google.
## Dynamic Asset Host
The `asset_host` config property can be assigned a proc (or anything that responds to `call`) for generating the host dynamically. The proc-compliant object gets an instance of the current `CarrierWave::Storage::Fog::File` or `CarrierWave::SanitizedFile` as its only argument.
```ruby
CarrierWave.configure do |config|
config.asset_host = proc do |file|
identifier = # some logic
"http://#{identifier}.cdn.rackspacecloud.com"
end
end
```
## Using RMagick
If you're uploading images, you'll probably want to manipulate them in some way,
you might want to create thumbnail images for example. CarrierWave comes with a
small library to make manipulating images with RMagick easier, you'll need to
include it in your Uploader:
```ruby
class AvatarUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
end
```
The RMagick module gives you a few methods, like
`CarrierWave::RMagick#resize_to_fill` which manipulate the image file in some
way. You can set a `process` callback, which will call that method any time a
file is uploaded.
There is a demonstration of convert here.
Convert will only work if the file has the same file extension, thus the use of the filename method.
```ruby
class AvatarUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
process :resize_to_fill => [200, 200]
process :convert => 'png'
def filename
super.chomp(File.extname(super)) + '.png'
end
end
```
Check out the manipulate! method, which makes it easy for you to write your own
manipulation methods.
## Using MiniMagick
MiniMagick is similar to RMagick but performs all the operations using the 'mogrify'
command which is part of the standard ImageMagick kit. This allows you to have the power
of ImageMagick without having to worry about installing all the RMagick libraries.
See the MiniMagick site for more details:
https://github.com/minimagick/minimagick
And the ImageMagick command line options for more for whats on offer:
http://www.imagemagick.org/script/command-line-options.php
Currently, the MiniMagick carrierwave processor provides exactly the same methods as
for the RMagick processor.
```ruby
class AvatarUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
process :resize_to_fill => [200, 200]
end
```
## Migrating from Paperclip
If you are using Paperclip, you can use the provided compatibility module:
```ruby
class AvatarUploader < CarrierWave::Uploader::Base
include CarrierWave::Compatibility::Paperclip
end
```
See the documentation for `CarrierWave::Compatibility::Paperclip` for more
details.
Be sure to use mount_on to specify the correct column:
```ruby
mount_uploader :avatar, AvatarUploader, :mount_on => :avatar_file_name
```
Unfortunately attachment_fu differs too much in philosophy for there to be a
sensible compatibility mode. Patches for migrating from other solutions will be
happily accepted.
## i18n
The Active Record validations use the Rails i18n framework. Add these keys to
your translations file:
```yaml
errors:
messages:
carrierwave_processing_error: "Cannot resize image."
carrierwave_integrity_error: "Not an image."
carrierwave_download_error: "Couldn't download image."
```
## Large files
By default, CarrierWave copies an uploaded file twice, first copying the file into the cache, then
copying the file into the store. For large files, this can be prohibitively time consuming.
You may change this behavior by overriding either or both of the `move_to_cache` and
`move_to_store` methods:
```ruby
class MyUploader < CarrierWave::Uploader::Base
def move_to_cache
true
end
def move_to_store
true
end
end
```
When the `move_to_cache` and/or `move_to_store` methods return true, files will be moved (instead of copied) to the cache and store respectively.
This has only been tested with the local filesystem store.
## Contributing to CarrierWave
See [CONTRIBUTING.md](https://github.com/jnicklas/carrierwave/blob/master/CONTRIBUTING.md)
## License
Copyright (c) 2008-2013 Jonas Nicklas
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ruby-carrierwave-0.8.0/Rakefile 0000664 0000000 0000000 00000001134 12140026204 0016443 0 ustar 00root root 0000000 0000000 # encoding: UTF-8
require 'rubygems'
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
require 'bundler'
Bundler::GemHelper.install_tasks
require 'rake'
require 'rspec/core/rake_task'
require 'cucumber'
require 'cucumber/rake/task'
desc "Run all examples"
RSpec::Core::RakeTask.new(:spec) do |t|
t.rspec_opts = %w[--color]
end
desc "Run cucumber features"
Cucumber::Rake::Task.new(:features) do |t|
t.cucumber_opts = "features --format progress"
end
task :default => [:spec, :features]
ruby-carrierwave-0.8.0/carrierwave.gemspec 0000664 0000000 0000000 00000002512 12140026204 0020656 0 ustar 00root root 0000000 0000000 # -*- encoding: utf-8 -*-
lib = File.expand_path('../lib/', __FILE__)
$:.unshift lib unless $:.include?(lib)
require 'carrierwave/version'
Gem::Specification.new do |s|
s.name = "carrierwave"
s.version = CarrierWave::VERSION
s.authors = ["Jonas Nicklas"]
s.date = Date.today
s.description = "Upload files in your Ruby applications, map them to a range of ORMs, store them on different backends."
s.summary = "Ruby file upload library"
s.email = ["jonas.nicklas@gmail.com"]
s.extra_rdoc_files = ["README.md"]
s.files = Dir.glob("{bin,lib}/**/*") + %w(README.md)
s.homepage = %q{https://github.com/jnicklas/carrierwave}
s.rdoc_options = ["--main"]
s.require_paths = ["lib"]
s.rubyforge_project = %q{carrierwave}
s.rubygems_version = %q{1.3.5}
s.specification_version = 3
s.add_dependency "activesupport", ">= 3.2.0"
s.add_dependency "activemodel", ">= 3.2.0"
s.add_development_dependency "mysql2"
s.add_development_dependency "rails", ">= 3.2.0"
s.add_development_dependency "cucumber", "~> 1.1.4"
s.add_development_dependency "json"
s.add_development_dependency "rspec", "~> 2.12.0"
s.add_development_dependency "sham_rack"
s.add_development_dependency "timecop"
s.add_development_dependency "fog", ">= 1.3.1"
s.add_development_dependency "mini_magick"
s.add_development_dependency "rmagick"
end
ruby-carrierwave-0.8.0/cucumber.yml 0000664 0000000 0000000 00000000114 12140026204 0017323 0 ustar 00root root 0000000 0000000 default: --format pretty --no-source
html: --format html --out features.html ruby-carrierwave-0.8.0/features/ 0000775 0000000 0000000 00000000000 12140026204 0016615 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/features/caching.feature 0000664 0000000 0000000 00000003225 12140026204 0021570 0 ustar 00root root 0000000 0000000 Feature: uploader with file storage
In order to be able to temporarily store files to disk
As a developer using CarrierWave
I want to cache files
Scenario: cache a file
Given an uploader class that uses the 'file' storage
And an instance of that class
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
Scenario: cache two files in succession
Given an uploader class that uses the 'file' storage
And an instance of that class
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
When I cache the file 'fixtures/monkey.txt'
Then there should be a file called 'monkey.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'monkey.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/monkey.txt'
Scenario: retrieving a file from cache
Given an uploader class that uses the 'file' storage
And an instance of that class
And the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
Then the uploader should have 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt' as its current path ruby-carrierwave-0.8.0/features/download.feature 0000664 0000000 0000000 00000001567 12140026204 0022012 0 ustar 00root root 0000000 0000000 Feature: downloading files
In order to allow users to upload remote files
As a developer using CarrierWave
I want to download files to the filesystem via HTTP
Background:
Given an uploader class that uses the 'file' storage
And an instance of that class
Scenario: download a file
When I download the file 'http://s3.amazonaws.com/Monkey/testfile.txt'
Then there should be a file called 'testfile.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'testfile.txt' in a subdirectory of 'public/uploads/tmp' should contain 'S3 Remote File'
Scenario: downloading a file then storing
When I download the file 'http://s3.amazonaws.com/Monkey/testfile.txt'
And I store the file
Then there should be a file at 'public/uploads/testfile.txt'
And the file at 'public/uploads/testfile.txt' should contain 'S3 Remote File'
ruby-carrierwave-0.8.0/features/file_storage.feature 0000664 0000000 0000000 00000003650 12140026204 0022641 0 ustar 00root root 0000000 0000000 Feature: uploader with file storage
In order to be awesome
As a developer using CarrierWave
I want to upload files to the filesystem
Background:
Given an uploader class that uses the 'file' storage
And an instance of that class
Scenario: store a file
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
Scenario: store two files in succession
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
When I store the file 'fixtures/monkey.txt'
Then there should be a file at 'public/uploads/monkey.txt'
And the file at 'public/uploads/monkey.txt' should be identical to the file at 'fixtures/monkey.txt'
Scenario: cache a file and then store it
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
And there should not be a file at 'public/uploads/bork.txt'
When I store the file
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
Scenario: retrieving a file from cache then storing
Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
And I store the file
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
ruby-carrierwave-0.8.0/features/file_storage_overridden_filename.feature 0000664 0000000 0000000 00000004012 12140026204 0026713 0 ustar 00root root 0000000 0000000 Feature: uploader with file storage and overriden filename
In order to be awesome
As a developer using CarrierWave
I want to upload files to the filesystem with an overriden filename
Background:
Given an uploader class that uses the 'file' storage
And that the uploader reverses the filename
And an instance of that class
Scenario: store a file
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/txt.krob'
And the file at 'public/uploads/txt.krob' should be identical to the file at 'fixtures/bork.txt'
Scenario: store two files in succession
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/txt.krob'
And the file at 'public/uploads/txt.krob' should be identical to the file at 'fixtures/bork.txt'
When I store the file 'fixtures/monkey.txt'
Then there should be a file at 'public/uploads/txt.yeknom'
And the file at 'public/uploads/txt.yeknom' should be identical to the file at 'fixtures/monkey.txt'
Scenario: cache a file and then store it
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
And there should not be a file at 'public/uploads/txt.krob'
When I store the file
Then there should be a file at 'public/uploads/txt.krob'
And the file at 'public/uploads/txt.krob' should be identical to the file at 'fixtures/bork.txt'
Scenario: retrieving a file from cache then storing
Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
And I store the file
Then there should be a file at 'public/uploads/txt.krob'
And the file at 'public/uploads/txt.krob' should be identical to the file at 'fixtures/bork.txt'
ruby-carrierwave-0.8.0/features/file_storage_overridden_store_dir.feature 0000664 0000000 0000000 00000004110 12140026204 0027124 0 ustar 00root root 0000000 0000000 Feature: uploader with file storage and overridden store dir
In order to be awesome
As a developer using CarrierWave
I want to upload files to the filesystem
Background:
Given an uploader class that uses the 'file' storage
And that the uploader has the store_dir overridden to 'public/monkey/llama'
And an instance of that class
Scenario: store a file
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/monkey/llama/bork.txt'
And the file at 'public/monkey/llama/bork.txt' should be identical to the file at 'fixtures/bork.txt'
Scenario: store two files in succession
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/monkey/llama/bork.txt'
And the file at 'public/monkey/llama/bork.txt' should be identical to the file at 'fixtures/bork.txt'
When I store the file 'fixtures/monkey.txt'
Then there should be a file at 'public/monkey/llama/monkey.txt'
And the file at 'public/monkey/llama/monkey.txt' should be identical to the file at 'fixtures/monkey.txt'
Scenario: cache a file and then store it
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
And there should not be a file at 'public/monkey/llama/bork.txt'
When I store the file
Then there should be a file at 'public/monkey/llama/bork.txt'
And the file at 'public/monkey/llama/bork.txt' should be identical to the file at 'fixtures/bork.txt'
Scenario: retrieving a file from cache then storing
Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
And I store the file
Then there should be a file at 'public/monkey/llama/bork.txt'
And the file at 'public/monkey/llama/bork.txt' should be identical to the file at 'fixtures/bork.txt'
ruby-carrierwave-0.8.0/features/file_storage_reversing_processor.feature 0000664 0000000 0000000 00000005001 12140026204 0027014 0 ustar 00root root 0000000 0000000 Feature: uploader with file storage and a processor that reverses the file
In order to be awesome
As a developer using CarrierWave
I want to upload files to the filesystem
Background:
Given an uploader class that uses the 'file' storage
And an instance of that class
And the class has a method called 'reverse' that reverses the contents of a file
And the class will process 'reverse'
Scenario: store a file
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should not be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/bork.txt' should be the reverse of the file at 'fixtures/bork.txt'
Scenario: store two files in succession
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should not be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/bork.txt' should be the reverse of the file at 'fixtures/bork.txt'
When I store the file 'fixtures/monkey.txt'
Then there should be a file at 'public/uploads/monkey.txt'
And the file at 'public/uploads/monkey.txt' should not be identical to the file at 'fixtures/monkey.txt'
And the file at 'public/uploads/monkey.txt' should be the reverse of the file at 'fixtures/monkey.txt'
Scenario: cache a file and then store it
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should not be identical to the file at 'fixtures/bork.txt'
And there should not be a file at 'public/uploads/bork.txt'
When I store the file
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should not be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/bork.txt' should be the reverse of the file at 'fixtures/bork.txt'
Scenario: retrieving a file from cache then storing
Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
And I store the file
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
ruby-carrierwave-0.8.0/features/fixtures/ 0000775 0000000 0000000 00000000000 12140026204 0020466 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/features/fixtures/bork.txt 0000664 0000000 0000000 00000000016 12140026204 0022161 0 ustar 00root root 0000000 0000000 this is a file ruby-carrierwave-0.8.0/features/fixtures/monkey.txt 0000664 0000000 0000000 00000000024 12140026204 0022525 0 ustar 00root root 0000000 0000000 this is another file ruby-carrierwave-0.8.0/features/fixtures/upcased_bork.txt 0000664 0000000 0000000 00000000016 12140026204 0023665 0 ustar 00root root 0000000 0000000 THIS IS A FILE ruby-carrierwave-0.8.0/features/mount_activerecord.feature 0000664 0000000 0000000 00000004530 12140026204 0024070 0 ustar 00root root 0000000 0000000 Feature: Mount an Uploader on ActiveRecord class
In order to easily attach files to a form
As a web developer using CarrierWave
I want to mount an uploader on an ActiveRecord class
Background:
Given an uploader class that uses the 'file' storage
And an activerecord class that uses the 'users' table
And the uploader class is mounted on the 'avatar' column
And an instance of the activerecord class
Scenario: assign a file
When I assign the file 'fixtures/bork.txt' to the 'avatar' column
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
Scenario: assign a file and save the record
When I assign the file 'fixtures/bork.txt' to the 'avatar' column
And I save the active record
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the url for the column 'avatar' should be '/uploads/bork.txt'
Scenario: assign a file and retrieve it from cache
When I assign the file 'fixtures/bork.txt' to the 'avatar' column
And I retrieve the file later from the cache name for the column 'avatar'
And I save the active record
Then there should be a file at 'public/uploads/bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the url for the column 'avatar' should be '/uploads/bork.txt'
Scenario: store a file and retrieve it later
When I assign the file 'fixtures/bork.txt' to the 'avatar' column
And I retrieve the file later from the cache name for the column 'avatar'
And I save the active record
Then there should be a file at 'public/uploads/bork.txt'
When I reload the active record
Then the url for the column 'avatar' should be '/uploads/bork.txt'
Scenario: store a file and delete the record
When I assign the file 'fixtures/bork.txt' to the 'avatar' column
And I retrieve the file later from the cache name for the column 'avatar'
And I save the active record
Then there should be a file at 'public/uploads/bork.txt'
When I delete the active record
Then there should not be a file at 'public/uploads/bork.txt'
ruby-carrierwave-0.8.0/features/step_definitions/ 0000775 0000000 0000000 00000000000 12140026204 0022163 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/features/step_definitions/activerecord_steps.rb 0000664 0000000 0000000 00000000745 12140026204 0026406 0 ustar 00root root 0000000 0000000 # encoding: utf-8
Given /^an activerecord class that uses the '([^\']*)' table$/ do |name|
@mountee_klass = Class.new(ActiveRecord::Base)
@mountee_klass.table_name = name
end
Given /^an instance of the activerecord class$/ do
@instance = @mountee_klass.new
end
When /^I save the active record$/ do
@instance.save!
end
When /^I reload the active record$/ do
@instance = @instance.class.find(@instance.id)
end
When /^I delete the active record$/ do
@instance.destroy
end ruby-carrierwave-0.8.0/features/step_definitions/caching_steps.rb 0000664 0000000 0000000 00000000625 12140026204 0025325 0 ustar 00root root 0000000 0000000 # encoding: utf-8
Given /^the file '(.*?)' is cached file at '(.*?)'$/ do |file, cached|
FileUtils.mkdir_p(File.dirname(file_path(cached)))
FileUtils.cp(file_path(file), file_path(cached))
end
When /^I cache the file '(.*?)'$/ do |file|
@uploader.cache!(File.open(file_path(file)))
end
When /^I retrieve the cache name '(.*?)' from the cache$/ do |name|
@uploader.retrieve_from_cache!(name)
end ruby-carrierwave-0.8.0/features/step_definitions/datamapper_steps.rb 0000664 0000000 0000000 00000001176 12140026204 0026051 0 ustar 00root root 0000000 0000000 # encoding: utf-8
Given /^a datamapper class that has a '([^\']*)' column$/ do |column|
@mountee_klass = Class.new do
include DataMapper::Resource
storage_names[:default] = 'users'
property :id, DataMapper::Types::Serial
property column.to_sym, String
end
@mountee_klass.auto_migrate!
end
Given /^an instance of the datamapper class$/ do
@instance = @mountee_klass.new
end
When /^I save the datamapper record$/ do
@instance.save
end
When /^I reload the datamapper record$/ do
@instance = @instance.class.first(:id => @instance.key)
end
When /^I delete the datamapper record$/ do
@instance.destroy
end
ruby-carrierwave-0.8.0/features/step_definitions/download_steps.rb 0000664 0000000 0000000 00000000514 12140026204 0025535 0 ustar 00root root 0000000 0000000 When /^I download the file '([^']+)'/ do |url|
unless ENV['REMOTE'] == 'true'
sham_rack_app = ShamRack.at('s3.amazonaws.com').stub
sham_rack_app.register_resource('/Monkey/testfile.txt', 'S3 Remote File', 'text/plain')
end
@uploader.download!(url)
unless ENV['REMOTE'] == 'true'
ShamRack.unmount_all
end
end
ruby-carrierwave-0.8.0/features/step_definitions/file_steps.rb 0000664 0000000 0000000 00000003446 12140026204 0024654 0 ustar 00root root 0000000 0000000 # encoding: utf-8
###
# EXISTENCE
Then /^there should be a file at '(.*?)'$/ do |file|
File.exist?(file_path(file)).should be_true
end
Then /^there should not be a file at '(.*?)'$/ do |file|
File.exist?(file_path(file)).should be_false
end
Then /^there should be a file called '(.*?)' somewhere in a subdirectory of '(.*?)'$/ do |file, directory|
Dir.glob(File.join(file_path(directory), '**', file)).any?.should be_true
end
###
# IDENTICAL
Then /^the file at '(.*?)' should be identical to the file at '(.*?)'$/ do |one, two|
File.read(file_path(one)).should == File.read(file_path(two))
end
Then /^the file at '(.*?)' should not be identical to the file at '(.*?)'$/ do |one, two|
File.read(file_path(one)).should_not == File.read(file_path(two))
end
Then /^the file called '(.*?)' in a subdirectory of '(.*?)' should be identical to the file at '(.*?)'$/ do |file, directory, other|
File.read(Dir.glob(File.join(file_path(directory), '**', file)).first).should == File.read(file_path(other))
end
Then /^the file called '(.*?)' in a subdirectory of '(.*?)' should not be identical to the file at '(.*?)'$/ do |file, directory, other|
File.read(Dir.glob(File.join(file_path(directory), '**', file)).first).should_not == File.read(file_path(other))
end
###
# CONTENT
Then /^the file called '([^']+)' in a subdirectory of '([^']+)' should contain '([^']+)'$/ do |file, directory, content|
File.read(Dir.glob(File.join(file_path(directory), '**', file)).first).should include(content)
end
Then /^the file at '([^']+)' should contain '([^']+)'$/ do |path, content|
File.read(file_path(path)).should include(content)
end
###
# REVERSING
Then /^the file at '(.*?)' should be the reverse of the file at '(.*?)'$/ do |one, two|
File.read(file_path(one)).should == File.read(file_path(two)).reverse
end
ruby-carrierwave-0.8.0/features/step_definitions/general_steps.rb 0000664 0000000 0000000 00000005470 12140026204 0025351 0 ustar 00root root 0000000 0000000 # encoding: utf-8
Given /^an uploader class that uses the '(.*?)' storage$/ do |kind|
@klass = Class.new(CarrierWave::Uploader::Base)
@klass.storage = kind.to_sym
end
Given /^an instance of that class$/ do
@uploader = @klass.new
end
Given /^a processor method named :upcase$/ do
@klass.class_eval do
define_method(:upcase) do
content = File.read(current_path)
File.open(current_path, 'w') { |f| f.write content.upcase }
end
end
end
Then /^the contents of the file should be '(.*?)'$/ do |contents|
@uploader.read.chomp.should == contents
end
Given /^that the uploader reverses the filename$/ do
@klass.class_eval do
def filename
super.reverse unless super.blank?
end
end
end
Given /^that the uploader has the filename overridden to '(.*?)'$/ do |filename|
@klass.class_eval do
define_method(:filename) do
filename
end
end
end
Given /^that the uploader has the store_dir overridden to '(.*?)'$/ do |store_dir|
@klass.class_eval do
define_method(:store_dir) do
file_path(store_dir)
end
end
end
Given /^that the version '(.*?)' has the store_dir overridden to '(.*?)'$/ do |version, store_dir|
@klass.versions[version.to_sym][:uploader].class_eval do
define_method(:store_dir) do
file_path(store_dir)
end
end
end
Given /^that the uploader class has a version named '([^\']+)'$/ do |name|
@klass.version(name)
end
Given /^that the uploader class has a version named '([^\']+)' which process '([a-zA-Z0-9\_\?!]*)'$/ do |name, processor_name|
@klass.version(name) do
process processor_name.to_sym
end
end
Given /^that the uploader class has a version named '([^\']+)' which is based on version '(.*?)'$/ do |name, based_version_name|
@klass.version(name, {:from_version => based_version_name.to_sym})
end
Given /^yo dawg, I put a version called '(.*?)' in your version called '(.*?)'$/ do |v2, v1|
@klass.version(v1) do
version(v2)
end
end
Given /^the class has a method called 'reverse' that reverses the contents of a file$/ do
@klass.class_eval do
def reverse
text = File.read(current_path)
File.open(current_path, 'w') { |f| f.write(text.reverse) }
end
end
end
Given /^the class will process '([a-zA-Z0-9\_\?!]*)'$/ do |name|
@klass.process name.to_sym
end
Then /^the uploader should have '(.*?)' as its current path$/ do |path|
@uploader.current_path.should == file_path(path)
end
Then /^the uploader should have the url '(.*?)'$/ do |url|
@uploader.url.should == url
end
Then /^the uploader's version '(.*?)' should have the url '(.*?)'$/ do |version, url|
@uploader.versions[version.to_sym].url.should == url
end
Then /^the uploader's nested version '(.*?)' nested in '(.*?)' should have the url '(.*?)'$/ do |v2, v1, url|
@uploader.versions[v1.to_sym].versions[v2.to_sym].url.should == url
end
ruby-carrierwave-0.8.0/features/step_definitions/mount_steps.rb 0000664 0000000 0000000 00000001236 12140026204 0025072 0 ustar 00root root 0000000 0000000 # encoding: utf-8
When /^I assign the file '([^\']*)' to the '([^\']*)' column$/ do |path, column|
@instance.send("#{column}=", File.open(file_path(path)))
end
Given /^the uploader class is mounted on the '([^\']*)' column$/ do |column|
@mountee_klass.mount_uploader column.to_sym, @klass
end
When /^I retrieve the file later from the cache name for the column '([^\']*)'$/ do |column|
new_instance = @instance.class.new
new_instance.send("#{column}_cache=", @instance.send("#{column}_cache"))
@instance = new_instance
end
Then /^the url for the column '([^\']*)' should be '([^\']*)'$/ do |column, url|
@instance.send("#{column}_url").should == url
end
ruby-carrierwave-0.8.0/features/step_definitions/store_steps.rb 0000664 0000000 0000000 00000000714 12140026204 0025064 0 ustar 00root root 0000000 0000000 # encoding: utf-8
Given /^the file '(.*?)' is stored at '(.*?)'$/ do |file, stored|
FileUtils.mkdir_p(File.dirname(file_path(stored)))
FileUtils.cp(file_path(file), file_path(stored))
end
When /^I store the file$/ do
@uploader.store!
end
When /^I store the file '(.*?)'$/ do |file|
@uploader.store!(File.open(file_path(file)))
end
When /^I retrieve the file '(.*?)' from the store$/ do |identifier|
@uploader.retrieve_from_store!(identifier)
end
ruby-carrierwave-0.8.0/features/support/ 0000775 0000000 0000000 00000000000 12140026204 0020331 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/features/support/activerecord.rb 0000664 0000000 0000000 00000001147 12140026204 0023333 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'mysql2'
require 'active_record'
require 'carrierwave/mount'
require 'carrierwave/orm/activerecord'
# Change this if MySQL is unavailable
dbconfig = {
:adapter => 'mysql2',
:database => 'carrierwave_test',
:username => 'root',
:encoding => 'utf8'
}
ActiveRecord::Base.establish_connection(dbconfig)
ActiveRecord::Migration.verbose = false
class TestMigration < ActiveRecord::Migration
def self.up
create_table :users, :force => true do |t|
t.column :avatar, :string
end
end
def self.down
drop_table :users
end
end
Before do
TestMigration.up
end
ruby-carrierwave-0.8.0/features/support/env.rb 0000664 0000000 0000000 00000000661 12140026204 0021451 0 ustar 00root root 0000000 0000000 # encoding: utf-8
$:.unshift File.expand_path(File.join('..', '..', 'lib'), File.dirname(__FILE__))
require File.join(File.dirname(__FILE__), 'activerecord')
require 'rspec'
require 'carrierwave'
require 'sham_rack'
alias :running :lambda
def file_path( *paths )
File.expand_path(File.join('..', *paths), File.dirname(__FILE__))
end
CarrierWave.root = file_path('public')
After do
FileUtils.rm_rf(file_path("public"))
end
ruby-carrierwave-0.8.0/features/versions_basics.feature 0000664 0000000 0000000 00000006016 12140026204 0023371 0 ustar 00root root 0000000 0000000 Feature: uploader with file storage and versions
In order to be awesome
As a developer using CarrierWave
I want to upload files to the filesystem
Background:
Given an uploader class that uses the 'file' storage
And that the uploader class has a version named 'thumb'
And an instance of that class
Scenario: store a file
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/bork.txt'
Then there should be a file at 'public/uploads/thumb_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the uploader should have the url '/uploads/bork.txt'
And the uploader's version 'thumb' should have the url '/uploads/thumb_bork.txt'
Scenario: cache a file and then store it
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
Then there should be a file called 'thumb_bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
And there should not be a file at 'public/uploads/bork.txt'
And there should not be a file at 'public/uploads/thumb_bork.txt'
When I store the file
Then there should be a file at 'public/uploads/bork.txt'
And there should be a file at 'public/uploads/thumb_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the uploader should have the url '/uploads/bork.txt'
And the uploader's version 'thumb' should have the url '/uploads/thumb_bork.txt'
Scenario: retrieving a file from cache then storing
Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
Given the file 'fixtures/monkey.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/thumb_bork.txt'
When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
And I store the file
Then there should be a file at 'public/uploads/bork.txt'
Then there should be a file at 'public/uploads/thumb_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_bork.txt' should be identical to the file at 'fixtures/monkey.txt'
Scenario: retrieving a file from store
Given the file 'fixtures/bork.txt' is stored at 'public/uploads/bork.txt'
Given the file 'fixtures/monkey.txt' is stored at 'public/uploads/thumb_bork.txt'
When I retrieve the file 'bork.txt' from the store
Then the uploader should have the url '/uploads/bork.txt'
And the uploader's version 'thumb' should have the url '/uploads/thumb_bork.txt'
ruby-carrierwave-0.8.0/features/versions_caching_from_versions.feature 0000664 0000000 0000000 00000004435 12140026204 0026477 0 ustar 00root root 0000000 0000000 Feature: uploader with file storage and versions with overridden store dir
In order to be awesome
As a developer using CarrierWave
I want to upload files to the filesystem
Background:
Given an uploader class that uses the 'file' storage
Given a processor method named :upcase
And that the uploader class has a version named 'thumb' which process 'upcase'
And that the version 'thumb' has the store_dir overridden to 'public/monkey/llama'
And that the uploader class has a version named 'small_thumb' which is based on version 'thumb'
And that the version 'small_thumb' has the store_dir overridden to 'public/monkey/toro'
And an instance of that class
Scenario: cache a file and then store it
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
Then there should be a file called 'thumb_bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
Then there should be a file called 'small_thumb_bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
And the file called 'thumb_bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/upcased_bork.txt'
And the file called 'small_thumb_bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/upcased_bork.txt'
And there should not be a file at 'public/uploads/bork.txt'
And there should not be a file at 'public/monkey/llama/thumb_bork.txt'
And there should not be a file at 'public/monkey/toro/small_thumb_bork.txt'
When I store the file
Then there should be a file at 'public/uploads/bork.txt'
Then there should be a file at 'public/monkey/llama/thumb_bork.txt'
Then there should be a file at 'public/monkey/toro/small_thumb_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/monkey/llama/thumb_bork.txt' should be identical to the file at 'fixtures/upcased_bork.txt'
And the file at 'public/monkey/toro/small_thumb_bork.txt' should be identical to the file at 'fixtures/upcased_bork.txt' ruby-carrierwave-0.8.0/features/versions_nested_versions.feature 0000664 0000000 0000000 00000011765 12140026204 0025346 0 ustar 00root root 0000000 0000000 Feature: uploader with nested versions
In order to optimize performance for processing
As a developer using CarrierWave
I want to set nested versions
Background:
Given an uploader class that uses the 'file' storage
And that the uploader class has a version named 'thumb'
And yo dawg, I put a version called 'mini' in your version called 'thumb'
And yo dawg, I put a version called 'micro' in your version called 'thumb'
And an instance of that class
Scenario: store a file
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/bork.txt'
Then there should be a file at 'public/uploads/thumb_bork.txt'
Then there should be a file at 'public/uploads/thumb_mini_bork.txt'
Then there should be a file at 'public/uploads/thumb_micro_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_mini_bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_micro_bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the uploader should have the url '/uploads/bork.txt'
And the uploader's version 'thumb' should have the url '/uploads/thumb_bork.txt'
And the uploader's nested version 'mini' nested in 'thumb' should have the url '/uploads/thumb_mini_bork.txt'
And the uploader's nested version 'micro' nested in 'thumb' should have the url '/uploads/thumb_micro_bork.txt'
Scenario: cache a file and then store it
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
Then there should be a file called 'thumb_bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
And there should not be a file at 'public/uploads/bork.txt'
And there should not be a file at 'public/uploads/thumb_bork.txt'
When I store the file
Then there should be a file at 'public/uploads/bork.txt'
And there should be a file at 'public/uploads/thumb_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the uploader should have the url '/uploads/bork.txt'
And the uploader's version 'thumb' should have the url '/uploads/thumb_bork.txt'
And the uploader's nested version 'mini' nested in 'thumb' should have the url '/uploads/thumb_mini_bork.txt'
And the uploader's nested version 'micro' nested in 'thumb' should have the url '/uploads/thumb_micro_bork.txt'
Scenario: retrieving a file from cache then storing
Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
Given the file 'fixtures/monkey.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/thumb_bork.txt'
Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/thumb_mini_bork.txt'
Given the file 'fixtures/monkey.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/thumb_micro_bork.txt'
When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
And I store the file
Then there should be a file at 'public/uploads/bork.txt'
Then there should be a file at 'public/uploads/thumb_bork.txt'
Then there should be a file at 'public/uploads/thumb_mini_bork.txt'
Then there should be a file at 'public/uploads/thumb_micro_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_bork.txt' should be identical to the file at 'fixtures/monkey.txt'
And the file at 'public/uploads/thumb_mini_bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_micro_bork.txt' should be identical to the file at 'fixtures/monkey.txt'
Scenario: retrieving a file from store
Given the file 'fixtures/bork.txt' is stored at 'public/uploads/bork.txt'
Given the file 'fixtures/monkey.txt' is stored at 'public/uploads/thumb_bork.txt'
Given the file 'fixtures/monkey.txt' is stored at 'public/uploads/thumb_mini_bork.txt'
Given the file 'fixtures/monkey.txt' is stored at 'public/uploads/thumb_micro_bork.txt'
When I retrieve the file 'bork.txt' from the store
Then the uploader should have the url '/uploads/bork.txt'
And the uploader's version 'thumb' should have the url '/uploads/thumb_bork.txt'
And the uploader's nested version 'mini' nested in 'thumb' should have the url '/uploads/thumb_mini_bork.txt'
And the uploader's nested version 'micro' nested in 'thumb' should have the url '/uploads/thumb_micro_bork.txt'
ruby-carrierwave-0.8.0/features/versions_overridden_filename.feature 0000664 0000000 0000000 00000006410 12140026204 0026124 0 ustar 00root root 0000000 0000000 Feature: uploader with file storage and overriden filename
In order to customize the filaname of uploaded files
As a developer using CarrierWave
I want to upload files to the filesystem with an overriden filename and different verions
Background:
Given an uploader class that uses the 'file' storage
And that the uploader class has a version named 'thumb'
And that the uploader has the filename overridden to 'grark.png'
And an instance of that class
Scenario: store a file
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/grark.png'
Then there should be a file at 'public/uploads/thumb_grark.png'
And the file at 'public/uploads/grark.png' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_grark.png' should be identical to the file at 'fixtures/bork.txt'
And the uploader should have the url '/uploads/grark.png'
And the uploader's version 'thumb' should have the url '/uploads/thumb_grark.png'
Scenario: cache a file and then store it
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
Then there should be a file called 'thumb_bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
And there should not be a file at 'public/uploads/grark.png'
And there should not be a file at 'public/uploads/thumb_grark.png'
When I store the file
Then there should be a file at 'public/uploads/grark.png'
And there should be a file at 'public/uploads/thumb_grark.png'
And the file at 'public/uploads/grark.png' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_grark.png' should be identical to the file at 'fixtures/bork.txt'
And the uploader should have the url '/uploads/grark.png'
And the uploader's version 'thumb' should have the url '/uploads/thumb_grark.png'
Scenario: retrieving a file from cache then storing
Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
Given the file 'fixtures/monkey.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/thumb_bork.txt'
When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
And I store the file
Then there should be a file at 'public/uploads/grark.png'
Then there should be a file at 'public/uploads/thumb_grark.png'
And the file at 'public/uploads/grark.png' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/uploads/thumb_grark.png' should be identical to the file at 'fixtures/monkey.txt'
Scenario: retrieving a file from store
Given the file 'fixtures/bork.txt' is stored at 'public/uploads/bork.txt'
Given the file 'fixtures/monkey.txt' is stored at 'public/uploads/thumb_bork.txt'
When I retrieve the file 'bork.txt' from the store
Then the uploader should have the url '/uploads/bork.txt'
And the uploader's version 'thumb' should have the url '/uploads/thumb_bork.txt'
ruby-carrierwave-0.8.0/features/versions_overriden_store_dir.feature 0000664 0000000 0000000 00000005161 12140026204 0026174 0 ustar 00root root 0000000 0000000 Feature: uploader with file storage and versions with overridden store dir
In order to be awesome
As a developer using CarrierWave
I want to upload files to the filesystem
Background:
Given an uploader class that uses the 'file' storage
And that the uploader class has a version named 'thumb'
And that the version 'thumb' has the store_dir overridden to 'public/monkey/llama'
And an instance of that class
Scenario: store a file
When I store the file 'fixtures/bork.txt'
Then there should be a file at 'public/uploads/bork.txt'
Then there should be a file at 'public/monkey/llama/thumb_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/monkey/llama/thumb_bork.txt' should be identical to the file at 'fixtures/bork.txt'
Scenario: cache a file and then store it
When I cache the file 'fixtures/bork.txt'
Then there should be a file called 'bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
Then there should be a file called 'thumb_bork.txt' somewhere in a subdirectory of 'public/uploads/tmp'
And the file called 'bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
And the file called 'thumb_bork.txt' in a subdirectory of 'public/uploads/tmp' should be identical to the file at 'fixtures/bork.txt'
And there should not be a file at 'public/uploads/bork.txt'
And there should not be a file at 'public/monkey/llama/thumb_bork.txt'
When I store the file
Then there should be a file at 'public/uploads/bork.txt'
Then there should be a file at 'public/monkey/llama/thumb_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/monkey/llama/thumb_bork.txt' should be identical to the file at 'fixtures/bork.txt'
Scenario: retrieving a file from cache then storing
Given the file 'fixtures/bork.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/bork.txt'
Given the file 'fixtures/monkey.txt' is cached file at 'public/uploads/tmp/20090212-2343-8336-0348/thumb_bork.txt'
When I retrieve the cache name '20090212-2343-8336-0348/bork.txt' from the cache
And I store the file
Then there should be a file at 'public/uploads/bork.txt'
Then there should be a file at 'public/monkey/llama/thumb_bork.txt'
And the file at 'public/uploads/bork.txt' should be identical to the file at 'fixtures/bork.txt'
And the file at 'public/monkey/llama/thumb_bork.txt' should be identical to the file at 'fixtures/monkey.txt'
ruby-carrierwave-0.8.0/gemfiles/ 0000775 0000000 0000000 00000000000 12140026204 0016572 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/gemfiles/rails3_2.gemfile 0000664 0000000 0000000 00000000254 12140026204 0021543 0 ustar 00root root 0000000 0000000 source "https://rubygems.org"
gem "rails", :git => "https://github.com/rails/rails.git", :branch => "3-2-stable"
gem "carrierwave", :path => "../"
gemspec :path => "../"
ruby-carrierwave-0.8.0/gemfiles/rails_master.gemfile 0000664 0000000 0000000 00000000430 12140026204 0022606 0 ustar 00root root 0000000 0000000 source "https://rubygems.org"
gem "rails", :github => "rails/rails", :branch => "master"
gem "activerecord-deprecated_finders", :github => "rails/activerecord-deprecated_finders"
gem "journey", :github => "rails/journey"
gem "carrierwave", :path => "../"
gemspec :path => "../"
ruby-carrierwave-0.8.0/lib/ 0000775 0000000 0000000 00000000000 12140026204 0015545 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave.rb 0000664 0000000 0000000 00000003556 12140026204 0020415 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'fileutils'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/class/attribute'
require 'active_support/concern'
module CarrierWave
class << self
attr_accessor :root, :base_path
def configure(&block)
CarrierWave::Uploader::Base.configure(&block)
end
def clean_cached_files!(seconds=60*60*24)
CarrierWave::Uploader::Base.clean_cached_files!(seconds)
end
end
end
if defined?(Merb)
CarrierWave.root = Merb.dir_for(:public)
Merb::BootLoader.before_app_loads do
# Setup path for uploaders and load all of them before classes are loaded
Merb.push_path(:uploaders, Merb.root / 'app' / 'uploaders', '*.rb')
Dir.glob(File.join(Merb.load_paths[:uploaders])).each {|f| require f }
end
elsif defined?(Rails)
module CarrierWave
class Railtie < Rails::Railtie
initializer "carrierwave.setup_paths" do
CarrierWave.root = Rails.root.join(Rails.public_path).to_s
CarrierWave.base_path = ENV['RAILS_RELATIVE_URL_ROOT']
end
initializer "carrierwave.active_record" do
ActiveSupport.on_load :active_record do
require 'carrierwave/orm/activerecord'
end
end
end
end
elsif defined?(Sinatra)
if defined?(Padrino) && defined?(PADRINO_ROOT)
CarrierWave.root = File.join(PADRINO_ROOT, "public")
else
CarrierWave.root = if Sinatra::Application.respond_to?(:public_folder)
# Sinatra >= 1.3
Sinatra::Application.public_folder
else
# Sinatra < 1.3
Sinatra::Application.public
end
end
end
require "carrierwave/error"
require "carrierwave/sanitized_file"
require "carrierwave/mount"
require "carrierwave/processing"
require "carrierwave/version"
require "carrierwave/storage"
require "carrierwave/uploader"
require "carrierwave/compatibility/paperclip"
require "carrierwave/test/matchers"
ruby-carrierwave-0.8.0/lib/carrierwave/ 0000775 0000000 0000000 00000000000 12140026204 0020057 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave/compatibility/ 0000775 0000000 0000000 00000000000 12140026204 0022730 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave/compatibility/paperclip.rb 0000664 0000000 0000000 00000006524 12140026204 0025243 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Compatibility
##
# Mix this module into an Uploader to make it mimic Paperclip's storage paths
# This will make your Uploader use the same default storage path as paperclip
# does. If you need to override it, you can override the +paperclip_path+ method
# and provide a Paperclip style path:
#
# class MyUploader < CarrierWave::Uploader::Base
# include CarrierWave::Compatibility::Paperclip
#
# def paperclip_path
# ":rails_root/public/uploads/:id/:attachment/:style_:basename.:extension"
# end
# end
#
# ---
#
# This file contains code taken from Paperclip
#
# LICENSE
#
# The MIT License
#
# Copyright (c) 2008 Jon Yurek and thoughtbot, inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
module Paperclip
def store_path(for_file=filename)
path = paperclip_path
path ||= File.join(*[store_dir, paperclip_style.to_s, for_file].compact)
interpolate_paperclip_path(path, for_file)
end
def store_dir
":rails_root/public/system/:attachment/:id"
end
def paperclip_default_style
:original
end
def paperclip_path
end
def paperclip_style
version_name || paperclip_default_style
end
private
def interpolate_paperclip_path(path, filename)
mappings.inject(path) do |agg, pair|
agg.gsub(":#{pair[0]}") { pair[1].call(self, filename).to_s }
end
end
def mappings
[
[:rails_root , lambda{|u, f| Rails.root }],
[:rails_env , lambda{|u, f| Rails.env }],
[:class , lambda{|u, f| u.model.class.name.underscore.pluralize}],
[:id_partition , lambda{|u, f| ("%09d" % u.model.id).scan(/\d{3}/).join("/")}],
[:id , lambda{|u, f| u.model.id }],
[:attachment , lambda{|u, f| u.mounted_as.to_s.downcase.pluralize }],
[:style , lambda{|u, f| u.paperclip_style }],
[:basename , lambda{|u, f| f.gsub(/#{File.extname(f)}$/, "") }],
[:extension , lambda{|u, f| File.extname(f).gsub(/^\.+/, "")}]
]
end
end # Paperclip
end # Compatibility
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/error.rb 0000664 0000000 0000000 00000000352 12140026204 0021535 0 ustar 00root root 0000000 0000000 module CarrierWave
class UploadError < StandardError; end
class IntegrityError < UploadError; end
class InvalidParameter < UploadError; end
class ProcessingError < UploadError; end
class DownloadError < UploadError; end
end
ruby-carrierwave-0.8.0/lib/carrierwave/locale/ 0000775 0000000 0000000 00000000000 12140026204 0021316 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave/locale/en.yml 0000664 0000000 0000000 00000001465 12140026204 0022451 0 ustar 00root root 0000000 0000000 en:
errors:
messages:
carrierwave_processing_error: failed to be processed
carrierwave_integrity_error: is not of an allowed file type
carrierwave_download_error: could not be downloaded
extension_white_list_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
extension_black_list_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"
rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image? Original Error: %{e}"
mime_types_processing_error: "Failed to process file with MIME::Types, maybe not valid content-type? Original Error: %{e}"
mini_magick_processing_error: "Failed to manipulate with MiniMagick, maybe it is not an image? Original Error: %{e}"
ruby-carrierwave-0.8.0/lib/carrierwave/mount.rb 0000664 0000000 0000000 00000030414 12140026204 0021550 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
##
# If a Class is extended with this module, it gains the mount_uploader
# method, which is used for mapping attributes to uploaders and allowing
# easy assignment.
#
# You can use mount_uploader with pretty much any class, however it is
# intended to be used with some kind of persistent storage, like an ORM.
# If you want to persist the uploaded files in a particular Class, it
# needs to implement a `read_uploader` and a `write_uploader` method.
#
module Mount
##
# === Returns
#
# [Hash{Symbol => CarrierWave}] what uploaders are mounted on which columns
#
def uploaders
@uploaders ||= {}
@uploaders = superclass.uploaders.merge(@uploaders) if superclass.respond_to?(:uploaders)
@uploaders
end
def uploader_options
@uploader_options ||= {}
@uploader_options = superclass.uploader_options.merge(@uploader_options) if superclass.respond_to?(:uploader_options)
@uploader_options
end
##
# Return a particular option for a particular uploader
#
# === Parameters
#
# [column (Symbol)] The column the uploader is mounted at
# [option (Symbol)] The option, e.g. validate_integrity
#
# === Returns
#
# [Object] The option value
#
def uploader_option(column, option)
if uploader_options[column].has_key?(option)
uploader_options[column][option]
else
uploaders[column].send(option)
end
end
##
# Mounts the given uploader on the given column. This means that assigning
# and reading from the column will upload and retrieve files. Supposing
# that a User class has an uploader mounted on image, you can assign and
# retrieve files like this:
#
# @user.image # =>
# @user.image.store!(some_file_object)
#
# @user.image.url # => '/some_url.png'
#
# It is also possible (but not recommended) to ommit the uploader, which
# will create an anonymous uploader class.
#
# Passing a block makes it possible to customize the uploader. This can be
# convenient for brevity, but if there is any significatnt logic in the
# uploader, you should do the right thing and have it in its own file.
#
# === Added instance methods
#
# Supposing a class has used +mount_uploader+ to mount an uploader on a column
# named +image+, in that case the following methods will be added to the class:
#
# [image] Returns an instance of the uploader only if anything has been uploaded
# [image=] Caches the given file
#
# [image_url] Returns the url to the uploaded file
#
# [image_cache] Returns a string that identifies the cache location of the file
# [image_cache=] Retrieves the file from the cache based on the given cache name
#
# [remote_image_url] Returns previously cached remote url
# [remote_image_url=] Retrieve the file from the remote url
#
# [remove_image] An attribute reader that can be used with a checkbox to mark a file for removal
# [remove_image=] An attribute writer that can be used with a checkbox to mark a file for removal
# [remove_image?] Whether the file should be removed when store_image! is called.
#
# [store_image!] Stores a file that has been assigned with +image=+
# [remove_image!] Removes the uploaded file from the filesystem.
#
# [image_integrity_error] Returns an error object if the last file to be assigned caused an integrity error
# [image_processing_error] Returns an error object if the last file to be assigned caused a processing error
# [image_download_error] Returns an error object if the last file to be remotely assigned caused a download error
#
# [write_image_identifier] Uses the write_uploader method to set the identifier.
# [image_identifier] Reads out the identifier of the file
#
# === Parameters
#
# [column (Symbol)] the attribute to mount this uploader on
# [uploader (CarrierWave::Uploader)] the uploader class to mount
# [options (Hash{Symbol => Object})] a set of options
# [&block (Proc)] customize anonymous uploaders
#
# === Options
#
# [:mount_on => Symbol] if the name of the column to be serialized to differs you can override it using this option
# [:ignore_integrity_errors => Boolean] if set to true, integrity errors will result in caching failing silently
# [:ignore_processing_errors => Boolean] if set to true, processing errors will result in caching failing silently
#
# === Examples
#
# Mounting uploaders on different columns.
#
# class Song
# mount_uploader :lyrics, LyricsUploader
# mount_uploader :alternative_lyrics, LyricsUploader
# mount_uploader :file, SongUploader
# end
#
# This will add an anonymous uploader with only the default settings:
#
# class Data
# mount_uploader :csv
# end
#
# this will add an anonymous uploader overriding the store_dir:
#
# class Product
# mount_uploader :blueprint do
# def store_dir
# 'blueprints'
# end
# end
# end
#
def mount_uploader(column, uploader=nil, options={}, &block)
if block_given?
uploader = Class.new(uploader || CarrierWave::Uploader::Base)
const_set("Uploader#{uploader.object_id}".gsub('-', '_'), uploader)
uploader.class_eval(&block)
uploader.recursively_apply_block_to_versions(&block)
else
uploader ||= begin
u = Class.new(CarrierWave::Uploader::Base)
const_set("Uploader#{u.object_id}".gsub('-', '_'), u)
u
end
end
uploaders[column.to_sym] = uploader
uploader_options[column.to_sym] = options
include CarrierWave::Mount::Extension
# Make sure to write over accessors directly defined on the class.
# Simply super to the included module below.
class_eval <<-RUBY, __FILE__, __LINE__+1
def #{column}; super; end
def #{column}=(new_file); super; end
RUBY
# Mixing this in as a Module instead of class_evaling directly, so we
# can maintain the ability to super to any of these methods from within
# the class.
mod = Module.new
include mod
mod.class_eval <<-RUBY, __FILE__, __LINE__+1
def #{column}
_mounter(:#{column}).uploader
end
def #{column}=(new_file)
_mounter(:#{column}).cache(new_file)
end
def #{column}?
!_mounter(:#{column}).blank?
end
def #{column}_url(*args)
_mounter(:#{column}).url(*args)
end
def #{column}_cache
_mounter(:#{column}).cache_name
end
def #{column}_cache=(cache_name)
_mounter(:#{column}).cache_name = cache_name
end
def remote_#{column}_url
_mounter(:#{column}).remote_url
end
def remote_#{column}_url=(url)
_mounter(:#{column}).remote_url = url
end
def remove_#{column}
_mounter(:#{column}).remove
end
def remove_#{column}!
_mounter(:#{column}).remove!
end
def remove_#{column}=(value)
_mounter(:#{column}).remove = value
end
def remove_#{column}?
_mounter(:#{column}).remove?
end
def store_#{column}!
_mounter(:#{column}).store!
end
def #{column}_integrity_error
_mounter(:#{column}).integrity_error
end
def #{column}_processing_error
_mounter(:#{column}).processing_error
end
def #{column}_download_error
_mounter(:#{column}).download_error
end
def write_#{column}_identifier
_mounter(:#{column}).write_identifier
end
def #{column}_identifier
_mounter(:#{column}).identifier
end
def store_previous_model_for_#{column}
serialization_column = _mounter(:#{column}).serialization_column
if #{column}.remove_previously_stored_files_after_update && send(:"\#{serialization_column}_changed?")
@previous_model_for_#{column} ||= self.find_previous_model_for_#{column}
end
end
def find_previous_model_for_#{column}
self.class.find(to_key.first)
end
def remove_previously_stored_#{column}
if @previous_model_for_#{column} && @previous_model_for_#{column}.#{column}.path != #{column}.path
@previous_model_for_#{column}.#{column}.remove!
@previous_model_for_#{column} = nil
end
end
RUBY
end
module Extension
##
# overwrite this to read from a serialized attribute
#
def read_uploader(column); end
##
# overwrite this to write to a serialized attribute
#
def write_uploader(column, identifier); end
private
def _mounter(column)
# We cannot memoize in frozen objects :(
return Mounter.new(self, column) if frozen?
@_mounters ||= {}
@_mounters[column] ||= Mounter.new(self, column)
end
end # Extension
# this is an internal class, used by CarrierWave::Mount so that
# we don't pollute the model with a lot of methods.
class Mounter #:nodoc:
attr_reader :column, :record, :remote_url, :integrity_error, :processing_error, :download_error
attr_accessor :remove
def initialize(record, column, options={})
@record = record
@column = column
@options = record.class.uploader_options[column]
end
def write_identifier
return if record.frozen?
if remove?
record.write_uploader(serialization_column, '')
elsif not uploader.identifier.blank?
record.write_uploader(serialization_column, uploader.identifier)
end
end
def identifier
record.read_uploader(serialization_column)
end
def uploader
@uploader ||= record.class.uploaders[column].new(record, column)
if @uploader.blank? and not identifier.blank?
@uploader.retrieve_from_store!(identifier)
end
return @uploader
end
def cache(new_file)
uploader.cache!(new_file)
@integrity_error = nil
@processing_error = nil
rescue CarrierWave::IntegrityError => e
@integrity_error = e
raise e unless option(:ignore_integrity_errors)
rescue CarrierWave::ProcessingError => e
@processing_error = e
raise e unless option(:ignore_processing_errors)
end
def cache_name
uploader.cache_name
end
def cache_name=(cache_name)
uploader.retrieve_from_cache!(cache_name) unless uploader.cached?
rescue CarrierWave::InvalidParameter
end
def remote_url=(url)
@download_error = nil
@integrity_error = nil
@remote_url = url
uploader.download!(url)
rescue CarrierWave::DownloadError => e
@download_error = e
raise e unless option(:ignore_download_errors)
rescue CarrierWave::ProcessingError => e
@processing_error = e
raise e unless option(:ignore_processing_errors)
rescue CarrierWave::IntegrityError => e
@integrity_error = e
raise e unless option(:ignore_integrity_errors)
end
def store!
unless uploader.blank?
if remove?
uploader.remove!
else
uploader.store!
end
end
end
def url(*args)
uploader.url(*args)
end
def blank?
uploader.blank?
end
def remove?
!remove.blank? and remove !~ /\A0|false$\z/
end
def remove!
uploader.remove!
end
def serialization_column
option(:mount_on) || column
end
attr_accessor :uploader_options
private
def option(name)
self.uploader_options ||= {}
self.uploader_options[name] ||= record.class.uploader_option(column, name)
end
end # Mounter
end # Mount
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/orm/ 0000775 0000000 0000000 00000000000 12140026204 0020654 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave/orm/activerecord.rb 0000664 0000000 0000000 00000004366 12140026204 0023664 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'active_record'
require 'carrierwave/validations/active_model'
module CarrierWave
module ActiveRecord
include CarrierWave::Mount
##
# See +CarrierWave::Mount#mount_uploader+ for documentation
#
def mount_uploader(column, uploader=nil, options={}, &block)
super
alias_method :read_uploader, :read_attribute
alias_method :write_uploader, :write_attribute
public :read_uploader
public :write_uploader
include CarrierWave::Validations::ActiveModel
validates_integrity_of column if uploader_option(column.to_sym, :validate_integrity)
validates_processing_of column if uploader_option(column.to_sym, :validate_processing)
validates_download_of column if uploader_option(column.to_sym, :validate_download)
after_save :"store_#{column}!"
before_save :"write_#{column}_identifier"
after_commit :"remove_#{column}!", :on => :destroy
before_update :"store_previous_model_for_#{column}"
after_save :"remove_previously_stored_#{column}"
class_eval <<-RUBY, __FILE__, __LINE__+1
def #{column}=(new_file)
column = _mounter(:#{column}).serialization_column
send(:"\#{column}_will_change!")
super
end
def remote_#{column}_url=(url)
column = _mounter(:#{column}).serialization_column
send(:"\#{column}_will_change!")
super
end
def remove_#{column}!
super
_mounter(:#{column}).remove = true
_mounter(:#{column}).write_identifier
end
def serializable_hash(options=nil)
hash = {}
except = options && options[:except] && Array.wrap(options[:except]).map(&:to_s)
only = options && options[:only] && Array.wrap(options[:only]).map(&:to_s)
self.class.uploaders.each do |column, uploader|
if (!only && !except) || (only && only.include?(column.to_s)) || (except && !except.include?(column.to_s))
hash[column.to_s] = _mounter(column).uploader.serializable_hash
end
end
super(options).merge(hash)
end
RUBY
end
end # ActiveRecord
end # CarrierWave
ActiveRecord::Base.extend CarrierWave::ActiveRecord
ruby-carrierwave-0.8.0/lib/carrierwave/processing.rb 0000664 0000000 0000000 00000000202 12140026204 0022552 0 ustar 00root root 0000000 0000000 require "carrierwave/processing/rmagick"
require "carrierwave/processing/mini_magick"
require "carrierwave/processing/mime_types"
ruby-carrierwave-0.8.0/lib/carrierwave/processing/ 0000775 0000000 0000000 00000000000 12140026204 0022233 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave/processing/mime_types.rb 0000664 0000000 0000000 00000004056 12140026204 0024740 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
##
# This module simplifies the use of the mime-types gem to intelligently
# guess and set the content-type of a file. If you want to use this, you'll
# need to require this file:
#
# require 'carrierwave/processing/mime_types'
#
# And then include it in your uploader:
#
# class MyUploader < CarrierWave::Uploader::Base
# include CarrierWave::MimeTypes
# end
#
# You can now use the provided helper:
#
# class MyUploader < CarrierWave::Uploader::Base
# include CarrierWave::MimeTypes
#
# process :set_content_type
# end
#
module MimeTypes
extend ActiveSupport::Concern
included do
begin
require "mime/types"
rescue LoadError => e
e.message << " (You may need to install the mime-types gem)"
raise e
end
end
module ClassMethods
def set_content_type(override=false)
process :set_content_type => override
end
end
GENERIC_CONTENT_TYPES = %w[application/octet-stream binary/octet-stream]
def generic_content_type?
GENERIC_CONTENT_TYPES.include? file.content_type
end
##
# Changes the file content_type using the mime-types gem
#
# === Parameters
#
# [override (Boolean)] whether or not to override the file's content_type
# if it is already set and not a generic content-type,
# false by default
#
def set_content_type(override=false)
if override || file.content_type.blank? || generic_content_type?
new_content_type = ::MIME::Types.type_for(file.original_filename).first.to_s
if file.respond_to?(:content_type=)
file.content_type = new_content_type
else
file.instance_variable_set(:@content_type, new_content_type)
end
end
rescue ::MIME::InvalidContentType => e
raise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.mime_types_processing_error", :e => e)
end
end # MimeTypes
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/processing/mini_magick.rb 0000664 0000000 0000000 00000017741 12140026204 0025041 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
##
# This module simplifies manipulation with MiniMagick by providing a set
# of convenient helper methods. If you want to use them, you'll need to
# require this file:
#
# require 'carrierwave/processing/mini_magick'
#
# And then include it in your uploader:
#
# class MyUploader < CarrierWave::Uploader::Base
# include CarrierWave::MiniMagick
# end
#
# You can now use the provided helpers:
#
# class MyUploader < CarrierWave::Uploader::Base
# include CarrierWave::MiniMagick
#
# process :resize_to_fit => [200, 200]
# end
#
# Or create your own helpers with the powerful manipulate! method. Check
# out the ImageMagick docs at http://www.imagemagick.org/script/command-line-options.php for more
# info
#
# class MyUploader < CarrierWave::Uploader::Base
# include CarrierWave::MiniMagick
#
# process :radial_blur => 10
#
# def radial_blur(amount)
# manipulate! do |img|
# img.radial_blur(amount)
# img = yield(img) if block_given?
# img
# end
# end
#
# === Note
#
# MiniMagick is a mini replacement for RMagick that uses the command line
# tool "mogrify" for image manipulation.
#
# You can find more information here:
#
# http://mini_magick.rubyforge.org/
# and
# https://github.com/minimagic/minimagick/
#
#
module MiniMagick
extend ActiveSupport::Concern
included do
begin
require "mini_magick"
rescue LoadError => e
e.message << " (You may need to install the mini_magick gem)"
raise e
end
end
module ClassMethods
def convert(format)
process :convert => format
end
def resize_to_limit(width, height)
process :resize_to_limit => [width, height]
end
def resize_to_fit(width, height)
process :resize_to_fit => [width, height]
end
def resize_to_fill(width, height, gravity='Center')
process :resize_to_fill => [width, height, gravity]
end
def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
process :resize_and_pad => [width, height, background, gravity]
end
end
##
# Changes the image encoding format to the given format
#
# See http://www.imagemagick.org/script/command-line-options.php#format
#
# === Parameters
#
# [format (#to_s)] an abreviation of the format
#
# === Yields
#
# [MiniMagick::Image] additional manipulations to perform
#
# === Examples
#
# image.convert(:png)
#
def convert(format)
manipulate! do |img|
img.format(format.to_s.downcase)
img = yield(img) if block_given?
img
end
end
##
# Resize the image to fit within the specified dimensions while retaining
# the original aspect ratio. Will only resize the image if it is larger than the
# specified dimensions. The resulting image may be shorter or narrower than specified
# in the smaller dimension but will not be larger than the specified values.
#
# === Parameters
#
# [width (Integer)] the width to scale the image to
# [height (Integer)] the height to scale the image to
#
# === Yields
#
# [MiniMagick::Image] additional manipulations to perform
#
def resize_to_limit(width, height)
manipulate! do |img|
img.resize "#{width}x#{height}>"
img = yield(img) if block_given?
img
end
end
##
# Resize the image to fit within the specified dimensions while retaining
# the original aspect ratio. The image may be shorter or narrower than
# specified in the smaller dimension but will not be larger than the specified values.
#
# === Parameters
#
# [width (Integer)] the width to scale the image to
# [height (Integer)] the height to scale the image to
#
# === Yields
#
# [MiniMagick::Image] additional manipulations to perform
#
def resize_to_fit(width, height)
manipulate! do |img|
img.resize "#{width}x#{height}"
img = yield(img) if block_given?
img
end
end
##
# Resize the image to fit within the specified dimensions while retaining
# the aspect ratio of the original image. If necessary, crop the image in the
# larger dimension.
#
# === Parameters
#
# [width (Integer)] the width to scale the image to
# [height (Integer)] the height to scale the image to
# [gravity (String)] the current gravity suggestion (default: 'Center'; options: 'NorthWest', 'North', 'NorthEast', 'West', 'Center', 'East', 'SouthWest', 'South', 'SouthEast')
#
# === Yields
#
# [MiniMagick::Image] additional manipulations to perform
#
def resize_to_fill(width, height, gravity = 'Center')
manipulate! do |img|
cols, rows = img[:dimensions]
img.combine_options do |cmd|
if width != cols || height != rows
scale_x = width/cols.to_f
scale_y = height/rows.to_f
if scale_x >= scale_y
cols = (scale_x * (cols + 0.5)).round
rows = (scale_x * (rows + 0.5)).round
cmd.resize "#{cols}"
else
cols = (scale_y * (cols + 0.5)).round
rows = (scale_y * (rows + 0.5)).round
cmd.resize "x#{rows}"
end
end
cmd.gravity gravity
cmd.background "rgba(255,255,255,0.0)"
cmd.extent "#{width}x#{height}" if cols != width || rows != height
end
img = yield(img) if block_given?
img
end
end
##
# Resize the image to fit within the specified dimensions while retaining
# the original aspect ratio. If necessary, will pad the remaining area
# with the given color, which defaults to transparent (for gif and png,
# white for jpeg).
#
# See http://www.imagemagick.org/script/command-line-options.php#gravity
# for gravity options.
#
# === Parameters
#
# [width (Integer)] the width to scale the image to
# [height (Integer)] the height to scale the image to
# [background (String, :transparent)] the color of the background as a hexcode, like "#ff45de"
# [gravity (String)] how to position the image
#
# === Yields
#
# [MiniMagick::Image] additional manipulations to perform
#
def resize_and_pad(width, height, background=:transparent, gravity='Center')
manipulate! do |img|
img.combine_options do |cmd|
cmd.thumbnail "#{width}x#{height}>"
if background == :transparent
cmd.background "rgba(255, 255, 255, 0.0)"
else
cmd.background background
end
cmd.gravity gravity
cmd.extent "#{width}x#{height}"
end
img = yield(img) if block_given?
img
end
end
##
# Manipulate the image with MiniMagick. This method will load up an image
# and then pass each of its frames to the supplied block. It will then
# save the image to disk.
#
# === Gotcha
#
# This method assumes that the object responds to +current_path+.
# Any class that this module is mixed into must have a +current_path+ method.
# CarrierWave::Uploader does, so you won't need to worry about this in
# most cases.
#
# === Yields
#
# [MiniMagick::Image] manipulations to perform
#
# === Raises
#
# [CarrierWave::ProcessingError] if manipulation failed.
#
def manipulate!
cache_stored_file! if !cached?
image = ::MiniMagick::Image.open(current_path)
image = yield(image)
image.write(current_path)
::MiniMagick::Image.open(current_path)
rescue ::MiniMagick::Error, ::MiniMagick::Invalid => e
raise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.mini_magick_processing_error", :e => e)
end
end # MiniMagick
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/processing/rmagick.rb 0000664 0000000 0000000 00000025116 12140026204 0024202 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
##
# This module simplifies manipulation with RMagick by providing a set
# of convenient helper methods. If you want to use them, you'll need to
# require this file:
#
# require 'carrierwave/processing/rmagick'
#
# And then include it in your uploader:
#
# class MyUploader < CarrierWave::Uploader::Base
# include CarrierWave::RMagick
# end
#
# You can now use the provided helpers:
#
# class MyUploader < CarrierWave::Uploader::Base
# include CarrierWave::RMagick
#
# process :resize_to_fit => [200, 200]
# end
#
# Or create your own helpers with the powerful manipulate! method. Check
# out the RMagick docs at http://www.imagemagick.org/RMagick/doc/ for more
# info
#
# class MyUploader < CarrierWave::Uploader::Base
# include CarrierWave::RMagick
#
# process :do_stuff => 10.0
#
# def do_stuff(blur_factor)
# manipulate! do |img|
# img = img.sepiatone
# img = img.auto_orient
# img = img.radial_blur(blur_factor)
# end
# end
# end
#
# === Note
#
# You should be aware how RMagick handles memory. manipulate! takes care
# of freeing up memory for you, but for optimum memory usage you should
# use destructive operations as much as possible:
#
# DON'T DO THIS:
# img = img.resize_to_fit
#
# DO THIS INSTEAD:
# img.resize_to_fit!
#
# Read this for more information why:
#
# http://rubyforge.org/forum/forum.php?thread_id=1374&forum_id=1618
#
module RMagick
extend ActiveSupport::Concern
included do
begin
require "rmagick"
rescue LoadError
require "RMagick"
rescue LoadError => e
e.message << " (You may need to install the rmagick gem)"
raise e
end
end
module ClassMethods
def convert(format)
process :convert => format
end
def resize_to_limit(width, height)
process :resize_to_limit => [width, height]
end
def resize_to_fit(width, height)
process :resize_to_fit => [width, height]
end
def resize_to_fill(width, height, gravity=::Magick::CenterGravity)
process :resize_to_fill => [width, height, gravity]
end
def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
process :resize_and_pad => [width, height, background, gravity]
end
def resize_to_geometry_string(geometry_string)
process :resize_to_geometry_string => [geometry_string]
end
end
##
# Changes the image encoding format to the given format
#
# See even http://www.imagemagick.org/RMagick/doc/magick.html#formats
#
# === Parameters
#
# [format (#to_s)] an abreviation of the format
#
# === Yields
#
# [Magick::Image] additional manipulations to perform
#
# === Examples
#
# image.convert(:png)
#
def convert(format)
manipulate!(:format => format)
end
##
# Resize the image to fit within the specified dimensions while retaining
# the original aspect ratio. Will only resize the image if it is larger than the
# specified dimensions. The resulting image may be shorter or narrower than specified
# in the smaller dimension but will not be larger than the specified values.
#
# === Parameters
#
# [width (Integer)] the width to scale the image to
# [height (Integer)] the height to scale the image to
#
# === Yields
#
# [Magick::Image] additional manipulations to perform
#
def resize_to_limit(width, height)
manipulate! do |img|
geometry = Magick::Geometry.new(width, height, 0, 0, Magick::GreaterGeometry)
new_img = img.change_geometry(geometry) do |new_width, new_height|
img.resize(new_width, new_height)
end
destroy_image(img)
new_img = yield(new_img) if block_given?
new_img
end
end
##
# From the RMagick documentation: "Resize the image to fit within the
# specified dimensions while retaining the original aspect ratio. The
# image may be shorter or narrower than specified in the smaller dimension
# but will not be larger than the specified values."
#
# See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fit
#
# === Parameters
#
# [width (Integer)] the width to scale the image to
# [height (Integer)] the height to scale the image to
#
# === Yields
#
# [Magick::Image] additional manipulations to perform
#
def resize_to_fit(width, height)
manipulate! do |img|
img.resize_to_fit!(width, height)
img = yield(img) if block_given?
img
end
end
##
# From the RMagick documentation: "Resize the image to fit within the
# specified dimensions while retaining the aspect ratio of the original
# image. If necessary, crop the image in the larger dimension."
#
# See even http://www.imagemagick.org/RMagick/doc/image3.html#resize_to_fill
#
# === Parameters
#
# [width (Integer)] the width to scale the image to
# [height (Integer)] the height to scale the image to
#
# === Yields
#
# [Magick::Image] additional manipulations to perform
#
def resize_to_fill(width, height, gravity=::Magick::CenterGravity)
manipulate! do |img|
img.crop_resized!(width, height, gravity)
img = yield(img) if block_given?
img
end
end
##
# Resize the image to fit within the specified dimensions while retaining
# the original aspect ratio. If necessary, will pad the remaining area
# with the given color, which defaults to transparent (for gif and png,
# white for jpeg).
#
# === Parameters
#
# [width (Integer)] the width to scale the image to
# [height (Integer)] the height to scale the image to
# [background (String, :transparent)] the color of the background as a hexcode, like "#ff45de"
# [gravity (Magick::GravityType)] how to position the image
#
# === Yields
#
# [Magick::Image] additional manipulations to perform
#
def resize_and_pad(width, height, background=:transparent, gravity=::Magick::CenterGravity)
manipulate! do |img|
img.resize_to_fit!(width, height)
new_img = ::Magick::Image.new(width, height)
if background == :transparent
filled = new_img.matte_floodfill(1, 1)
else
filled = new_img.color_floodfill(1, 1, ::Magick::Pixel.from_color(background))
end
destroy_image(new_img)
filled.composite!(img, gravity, ::Magick::OverCompositeOp)
destroy_image(img)
filled = yield(filled) if block_given?
filled
end
end
##
# Resize the image per the provided geometry string.
#
# === Parameters
#
# [geometry_string (String)] the proportions in which to scale image
#
# === Yields
#
# [Magick::Image] additional manipulations to perform
#
def resize_to_geometry_string(geometry_string)
manipulate! do |img|
new_img = img.change_geometry(geometry_string) do |new_width, new_height|
img.resize(new_width, new_height)
end
destroy_image(img)
new_img = yield(new_img) if block_given?
new_img
end
end
##
# Manipulate the image with RMagick. This method will load up an image
# and then pass each of its frames to the supplied block. It will then
# save the image to disk.
#
# === Gotcha
#
# This method assumes that the object responds to +current_path+.
# Any class that this module is mixed into must have a +current_path+ method.
# CarrierWave::Uploader does, so you won't need to worry about this in
# most cases.
#
# === Yields
#
# [Magick::Image] manipulations to perform
# [Integer] Frame index if the image contains multiple frames
# [Hash] options, see below
#
# === Options
#
# The options argument to this method is also yielded as the third
# block argument.
#
# Currently, the following options are defined:
#
# ==== :write
# A hash of assignments to be evaluated in the block given to the RMagick write call.
#
# An example:
#
# manipulate! do |img, index, options|
# options[:write] = {
# :quality => 50,
# :depth => 8
# }
# img
# end
#
# This will translate to the following RMagick::Image#write call:
#
# image.write do |img|
# self.quality = 50
# self.depth = 8
# end
#
# ==== :read
# A hash of assignments to be given to the RMagick read call.
#
# The options available are identical to those for write, but are passed in directly, like this:
#
# manipulate! :read => { :density => 300 }
#
# ==== :format
# Specify the output format. If unset, the filename extension is used to determine the format.
#
# === Raises
#
# [CarrierWave::ProcessingError] if manipulation failed.
#
def manipulate!(options={}, &block)
cache_stored_file! if !cached?
read_block = create_info_block(options[:read])
image = ::Magick::Image.read(current_path, &read_block)
frames = if image.size > 1
list = ::Magick::ImageList.new
image.each_with_index do |frame, index|
processed_frame = if block_given?
yield *[frame, index, options].take(block.arity)
else
frame
end
list << processed_frame if processed_frame
end
block_given? ? list : list.append(true)
else
frame = image.first
frame = yield( *[frame, 0, options].take(block.arity) ) if block_given?
frame
end
write_block = create_info_block(options[:write])
if options[:format]
frames.write("#{options[:format]}:#{current_path}", &write_block)
else
frames.write(current_path, &write_block)
end
destroy_image(frames)
rescue ::Magick::ImageMagickError => e
raise CarrierWave::ProcessingError, I18n.translate(:"errors.messages.rmagick_processing_error", :e => e)
end
private
def create_info_block(options)
return nil unless options
assignments = options.map { |k, v| "self.#{k} = #{v}" }
code = "lambda { |img| " + assignments.join(";") + "}"
eval code
end
def destroy_image(image)
image.destroy! if image.respond_to?(:destroy!)
end
end # RMagick
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/sanitized_file.rb 0000664 0000000 0000000 00000017223 12140026204 0023402 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'pathname'
require 'active_support/core_ext/string/multibyte'
module CarrierWave
##
# SanitizedFile is a base class which provides a common API around all
# the different quirky Ruby File libraries. It has support for Tempfile,
# File, StringIO, Merb-style upload Hashes, as well as paths given as
# Strings and Pathnames.
#
# It's probably needlessly comprehensive and complex. Help is appreciated.
#
class SanitizedFile
attr_accessor :file
class << self
attr_writer :sanitize_regexp
def sanitize_regexp
@sanitize_regexp ||= /[^a-zA-Z0-9\.\-\+_]/
end
end
def initialize(file)
self.file = file
end
##
# Returns the filename as is, without sanizting it.
#
# === Returns
#
# [String] the unsanitized filename
#
def original_filename
return @original_filename if @original_filename
if @file and @file.respond_to?(:original_filename)
@file.original_filename
elsif path
File.basename(path)
end
end
##
# Returns the filename, sanitized to strip out any evil characters.
#
# === Returns
#
# [String] the sanitized filename
#
def filename
sanitize(original_filename) if original_filename
end
alias_method :identifier, :filename
##
# Returns the part of the filename before the extension. So if a file is called 'test.jpeg'
# this would return 'test'
#
# === Returns
#
# [String] the first part of the filename
#
def basename
split_extension(filename)[0] if filename
end
##
# Returns the file extension
#
# === Returns
#
# [String] the extension
#
def extension
split_extension(filename)[1] if filename
end
##
# Returns the file's size.
#
# === Returns
#
# [Integer] the file's size in bytes.
#
def size
if is_path?
exists? ? File.size(path) : 0
elsif @file.respond_to?(:size)
@file.size
elsif path
exists? ? File.size(path) : 0
else
0
end
end
##
# Returns the full path to the file. If the file has no path, it will return nil.
#
# === Returns
#
# [String, nil] the path where the file is located.
#
def path
unless @file.blank?
if is_path?
File.expand_path(@file)
elsif @file.respond_to?(:path) and not @file.path.blank?
File.expand_path(@file.path)
end
end
end
##
# === Returns
#
# [Boolean] whether the file is supplied as a pathname or string.
#
def is_path?
!!((@file.is_a?(String) || @file.is_a?(Pathname)) && !@file.blank?)
end
##
# === Returns
#
# [Boolean] whether the file is valid and has a non-zero size
#
def empty?
@file.nil? || self.size.nil? || (self.size.zero? && ! self.exists?)
end
##
# === Returns
#
# [Boolean] Whether the file exists
#
def exists?
return File.exists?(self.path) if self.path
return false
end
##
# Returns the contents of the file.
#
# === Returns
#
# [String] contents of the file
#
def read
if is_path?
File.open(@file, "rb") {|file| file.read}
else
@file.rewind if @file.respond_to?(:rewind)
@file.read
end
end
##
# Moves the file to the given path
#
# === Parameters
#
# [new_path (String)] The path where the file should be moved.
# [permissions (Integer)] permissions to set on the file in its new location.
# [directory_permissions (Integer)] permissions to set on created directories.
#
def move_to(new_path, permissions=nil, directory_permissions=nil)
return if self.empty?
new_path = File.expand_path(new_path)
mkdir!(new_path, directory_permissions)
if exists?
FileUtils.mv(path, new_path) unless new_path == path
else
File.open(new_path, "wb") { |f| f.write(read) }
end
chmod!(new_path, permissions)
self.file = new_path
self
end
##
# Creates a copy of this file and moves it to the given path. Returns the copy.
#
# === Parameters
#
# [new_path (String)] The path where the file should be copied to.
# [permissions (Integer)] permissions to set on the copy
# [directory_permissions (Integer)] permissions to set on created directories.
#
# === Returns
#
# @return [CarrierWave::SanitizedFile] the location where the file will be stored.
#
def copy_to(new_path, permissions=nil, directory_permissions=nil)
return if self.empty?
new_path = File.expand_path(new_path)
mkdir!(new_path, directory_permissions)
if exists?
FileUtils.cp(path, new_path) unless new_path == path
else
File.open(new_path, "wb") { |f| f.write(read) }
end
chmod!(new_path, permissions)
self.class.new({:tempfile => new_path, :content_type => content_type})
end
##
# Removes the file from the filesystem.
#
def delete
FileUtils.rm(self.path) if exists?
end
##
# Returns a File object, or nil if it does not exist.
#
# === Returns
#
# [File] a File object representing the SanitizedFile
#
def to_file
return @file if @file.is_a?(File)
File.open(path, "rb") if exists?
end
##
# Returns the content type of the file.
#
# === Returns
#
# [String] the content type of the file
#
def content_type
return @content_type if @content_type
@file.content_type.to_s.chomp if @file.respond_to?(:content_type) and @file.content_type
end
##
# Sets the content type of the file.
#
# === Returns
#
# [String] the content type of the file
#
def content_type=(type)
@content_type = type
end
##
# Used to sanitize the file name. Public to allow overriding for non-latin characters.
#
# === Returns
#
# [Regexp] the regexp for sanitizing the file name
#
def sanitize_regexp
CarrierWave::SanitizedFile.sanitize_regexp
end
private
def file=(file)
if file.is_a?(Hash)
@file = file["tempfile"] || file[:tempfile]
@original_filename = file["filename"] || file[:filename]
@content_type = file["content_type"] || file[:content_type]
else
@file = file
@original_filename = nil
@content_type = nil
end
end
# create the directory if it doesn't exist
def mkdir!(path, directory_permissions)
options = {}
options[:mode] = directory_permissions if directory_permissions
FileUtils.mkdir_p(File.dirname(path), options) unless File.exists?(File.dirname(path))
end
def chmod!(path, permissions)
File.chmod(permissions, path) if permissions
end
# Sanitize the filename, to prevent hacking
def sanitize(name)
name = name.gsub("\\", "/") # work-around for IE
name = File.basename(name)
name = name.gsub(sanitize_regexp,"_")
name = "_#{name}" if name =~ /\A\.+\z/
name = "unnamed" if name.size == 0
return name.mb_chars.to_s
end
def split_extension(filename)
# regular expressions to try for identifying extensions
extension_matchers = [
/\A(.+)\.(tar\.([glx]?z|bz2))\z/, # matches "something.tar.gz"
/\A(.+)\.([^\.]+)\z/ # matches "something.jpg"
]
extension_matchers.each do |regexp|
if filename =~ regexp
return $1, $2
end
end
return filename, "" # In case we weren't able to split the extension
end
end # SanitizedFile
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/storage.rb 0000664 0000000 0000000 00000000252 12140026204 0022047 0 ustar 00root root 0000000 0000000 require "carrierwave/storage/abstract"
require "carrierwave/storage/file"
begin
require "fog"
rescue LoadError
end
require "carrierwave/storage/fog" if defined?(Fog)
ruby-carrierwave-0.8.0/lib/carrierwave/storage/ 0000775 0000000 0000000 00000000000 12140026204 0021523 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave/storage/abstract.rb 0000664 0000000 0000000 00000001024 12140026204 0023650 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Storage
##
# This file serves mostly as a specification for Storage engines. There is no requirement
# that storage engines must be a subclass of this class.
#
class Abstract
attr_reader :uploader
def initialize(uploader)
@uploader = uploader
end
def identifier
uploader.filename
end
def store!(file)
end
def retrieve!(identifier)
end
end # Abstract
end # Storage
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/storage/file.rb 0000664 0000000 0000000 00000003230 12140026204 0022765 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Storage
##
# File storage stores file to the Filesystem (surprising, no?). There's really not much
# to it, it uses the store_dir defined on the uploader as the storage location. That's
# pretty much it.
#
class File < Abstract
##
# Move the file to the uploader's store path.
#
# By default, store!() uses copy_to(), which operates by copying the file
# from the cache to the store, then deleting the file from the cache.
# If move_to_store() is overriden to return true, then store!() uses move_to(),
# which simply moves the file from cache to store. Useful for large files.
#
# === Parameters
#
# [file (CarrierWave::SanitizedFile)] the file to store
#
# === Returns
#
# [CarrierWave::SanitizedFile] a sanitized file
#
def store!(file)
path = ::File.expand_path(uploader.store_path, uploader.root)
if uploader.move_to_store
file.move_to(path, uploader.permissions, uploader.directory_permissions)
else
file.copy_to(path, uploader.permissions, uploader.directory_permissions)
end
end
##
# Retrieve the file from its store path
#
# === Parameters
#
# [identifier (String)] the filename of the file
#
# === Returns
#
# [CarrierWave::SanitizedFile] a sanitized file
#
def retrieve!(identifier)
path = ::File.expand_path(uploader.store_path(identifier), uploader.root)
CarrierWave::SanitizedFile.new(path)
end
end # File
end # Storage
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/storage/fog.rb 0000664 0000000 0000000 00000024632 12140026204 0022632 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require "fog"
module CarrierWave
module Storage
##
# Stores things using the "fog" gem.
#
# fog supports storing files with AWS, Google, Local and Rackspace
#
# You need to setup some options to configure your usage:
#
# [:fog_credentials] host info and credentials for service
# [:fog_directory] specifies name of directory to store data in, assumed to already exist
#
# [:fog_attributes] (optional) additional attributes to set on files
# [:fog_public] (optional) public readability, defaults to true
# [:fog_authenticated_url_expiration] (optional) time (in seconds) that authenticated urls
# will be valid, when fog_public is false and provider is AWS or Google, defaults to 600
#
#
# AWS credentials contain the following keys:
#
# [:aws_access_key_id]
# [:aws_secret_access_key]
# [:region] (optional) defaults to 'us-east-1'
# :region should be one of ['eu-west-1', 'us-east-1', 'ap-southeast-1', 'us-west-1', 'ap-northeast-1']
#
#
# Google credentials contain the following keys:
# [:google_storage_access_key_id]
# [:google_storage_secrete_access_key]
#
#
# Local credentials contain the following keys:
#
# [:local_root] local path to files
#
#
# Rackspace credentials contain the following keys:
#
# [:rackspace_username]
# [:rackspace_api_key]
#
#
# A full example with AWS credentials:
# CarrierWave.configure do |config|
# config.fog_credentials = {
# :aws_access_key_id => 'xxxxxx',
# :aws_secret_access_key => 'yyyyyy',
# :provider => 'AWS'
# }
# config.fog_directory = 'directoryname'
# config.fog_public = true
# end
#
class Fog < Abstract
class << self
def connection_cache
@connection_cache ||= {}
end
end
##
# Store a file
#
# === Parameters
#
# [file (CarrierWave::SanitizedFile)] the file to store
#
# === Returns
#
# [CarrierWave::Storage::Fog::File] the stored file
#
def store!(file)
f = CarrierWave::Storage::Fog::File.new(uploader, self, uploader.store_path)
f.store(file)
f
end
##
# Retrieve a file
#
# === Parameters
#
# [identifier (String)] unique identifier for file
#
# === Returns
#
# [CarrierWave::Storage::Fog::File] the stored file
#
def retrieve!(identifier)
CarrierWave::Storage::Fog::File.new(uploader, self, uploader.store_path(identifier))
end
def connection
@connection ||= begin
options = credentials = uploader.fog_credentials
self.class.connection_cache[credentials] ||= ::Fog::Storage.new(options)
end
end
class File
##
# Current local path to file
#
# === Returns
#
# [String] a path to file
#
attr_reader :path
##
# Return all attributes from file
#
# === Returns
#
# [Hash] attributes from file
#
def attributes
file.attributes
end
##
# Return a temporary authenticated url to a private file, if available
# Only supported for AWS, Rackspace and Google providers
#
# === Returns
#
# [String] temporary authenticated url
# or
# [NilClass] no authenticated url available
#
def authenticated_url(options = {})
if ['AWS', 'Google', 'Rackspace'].include?(@uploader.fog_credentials[:provider])
# avoid a get by using local references
local_directory = connection.directories.new(:key => @uploader.fog_directory)
local_file = local_directory.files.new(:key => path)
if @uploader.fog_credentials[:provider] == "AWS"
local_file.url(::Fog::Time.now + @uploader.fog_authenticated_url_expiration, options)
elsif @uploader.fog_credentials[:provider] == "Rackspace"
connection.get_object_https_url(@uploader.fog_directory, path, ::Fog::Time.now + @uploader.fog_authenticated_url_expiration)
else
local_file.url(::Fog::Time.now + @uploader.fog_authenticated_url_expiration)
end
else
nil
end
end
##
# Lookup value for file content-type header
#
# === Returns
#
# [String] value of content-type
#
def content_type
@content_type || file.content_type
end
##
# Set non-default content-type header (default is file.content_type)
#
# === Returns
#
# [String] returns new content type value
#
def content_type=(new_content_type)
@content_type = new_content_type
end
##
# Remove the file from service
#
# === Returns
#
# [Boolean] true for success or raises error
#
def delete
# avoid a get by just using local reference
directory.files.new(:key => path).destroy
end
##
# Return extension of file
#
# === Returns
#
# [String] extension of file
#
def extension
path.split('.').last
end
##
# deprecated: All attributes from file (includes headers)
#
# === Returns
#
# [Hash] attributes from file
#
def headers
location = caller.first
warning = "[yellow][WARN] headers is deprecated, use attributes instead[/]"
warning << " [light_black](#{location})[/]"
Formatador.display_line(warning)
attributes
end
def initialize(uploader, base, path)
@uploader, @base, @path = uploader, base, path
end
##
# Read content of file from service
#
# === Returns
#
# [String] contents of file
def read
file.body
end
##
# Return size of file body
#
# === Returns
#
# [Integer] size of file body
#
def size
file.content_length
end
##
# Check if the file exists on the remote service
#
# === Returns
#
# [Boolean] true if file exists or false
def exists?
!!directory.files.head(path)
end
##
# Write file to service
#
# === Returns
#
# [Boolean] true on success or raises error
def store(new_file)
fog_file = new_file.to_file
@content_type ||= new_file.content_type
@file = directory.files.create({
:body => fog_file ? fog_file : new_file.read,
:content_type => @content_type,
:key => path,
:public => @uploader.fog_public
}.merge(@uploader.fog_attributes))
fog_file.close if fog_file && !fog_file.closed?
true
end
##
# Return a url to a public file, if available
#
# === Returns
#
# [String] public url
# or
# [NilClass] no public url available
#
def public_url
if host = @uploader.asset_host
if host.respond_to? :call
"#{host.call(self)}/#{path}"
else
"#{host}/#{path}"
end
else
# AWS/Google optimized for speed over correctness
case @uploader.fog_credentials[:provider]
when 'AWS'
# check if some endpoint is set in fog_credentials
if @uploader.fog_credentials.has_key?(:endpoint)
"#{@uploader.fog_credentials[:endpoint]}/#{@uploader.fog_directory}/#{path}"
else
# if directory is a valid subdomain, use that style for access
if @uploader.fog_directory.to_s =~ /^(?:[a-z]|\d(?!\d{0,2}(?:\d{1,3}){3}$))(?:[a-z0-9\.]|(?![\-])|\-(?![\.])){1,61}[a-z0-9]$/
"https://#{@uploader.fog_directory}.s3.amazonaws.com/#{path}"
else
# directory is not a valid subdomain, so use path style for access
"https://s3.amazonaws.com/#{@uploader.fog_directory}/#{path}"
end
end
when 'Google'
"https://commondatastorage.googleapis.com/#{@uploader.fog_directory}/#{path}"
else
# avoid a get by just using local reference
directory.files.new(:key => path).public_url
end
end
end
##
# Return url to file, if avaliable
#
# === Returns
#
# [String] url
# or
# [NilClass] no url available
#
def url(options = {})
if !@uploader.fog_public
authenticated_url(options)
else
public_url
end
end
##
# Return file name, if available
#
# === Returns
#
# [String] file name
# or
# [NilClass] no file name available
#
def filename(options = {})
if file_url = url(options)
file_url.gsub(/.*\/(.*?$)/, '\1')
end
end
private
##
# connection to service
#
# === Returns
#
# [Fog::#{provider}::Storage] connection to service
#
def connection
@base.connection
end
##
# local reference to directory containing file
#
# === Returns
#
# [Fog::#{provider}::Directory] containing directory
#
def directory
@directory ||= begin
connection.directories.new(
:key => @uploader.fog_directory,
:public => @uploader.fog_public
)
end
end
##
# lookup file
#
# === Returns
#
# [Fog::#{provider}::File] file data from remote service
#
def file
@file ||= directory.files.head(path)
end
end
end # Fog
end # Storage
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/test/ 0000775 0000000 0000000 00000000000 12140026204 0021036 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave/test/matchers.rb 0000664 0000000 0000000 00000022353 12140026204 0023176 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Test
##
# These are some matchers that can be used in RSpec specs, to simplify the testing
# of uploaders.
#
module Matchers
class BeIdenticalTo # :nodoc:
def initialize(expected)
@expected = expected
end
def matches?(actual)
@actual = actual
FileUtils.identical?(@actual, @expected)
end
def failure_message
"expected #{@actual.inspect} to be identical to #{@expected.inspect}"
end
def negative_failure_message
"expected #{@actual.inspect} to not be identical to #{@expected.inspect}"
end
def description
"be identical to #{@expected.inspect}"
end
end
def be_identical_to(expected)
BeIdenticalTo.new(expected)
end
class HavePermissions # :nodoc:
def initialize(expected)
@expected = expected
end
def matches?(actual)
@actual = actual
# Satisfy expectation here. Return false or raise an error if it's not met.
(File.stat(@actual.path).mode & 0777) == @expected
end
def failure_message
"expected #{@actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0777).to_s(8)}"
end
def negative_failure_message
"expected #{@actual.current_path.inspect} not to have permissions #{@expected.to_s(8)}, but it did"
end
def description
"have permissions #{@expected.to_s(8)}"
end
end
def have_permissions(expected)
HavePermissions.new(expected)
end
class HaveDirectoryPermissions # :nodoc:
def initialize(expected)
@expected = expected
end
def matches?(actual)
@actual = actual
# Satisfy expectation here. Return false or raise an error if it's not met.
(File.stat(File.dirname @actual.path).mode & 0777) == @expected
end
def failure_message
"expected #{File.dirname @actual.current_path.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0777).to_s(8)}"
end
def negative_failure_message
"expected #{File.dirname @actual.current_path.inspect} not to have permissions #{@expected.to_s(8)}, but it did"
end
def description
"have permissions #{@expected.to_s(8)}"
end
end
def have_directory_permissions(expected)
HaveDirectoryPermissions.new(expected)
end
class BeNoLargerThan # :nodoc:
def initialize(width, height)
@width, @height = width, height
end
def matches?(actual)
@actual = actual
# Satisfy expectation here. Return false or raise an error if it's not met.
image = ImageLoader.load_image(@actual.current_path)
@actual_width = image.width
@actual_height = image.height
@actual_width <= @width && @actual_height <= @height
end
def failure_message
"expected #{@actual.current_path.inspect} to be no larger than #{@width} by #{@height}, but it was #{@actual_width} by #{@actual_height}."
end
def negative_failure_message
"expected #{@actual.current_path.inspect} to be larger than #{@width} by #{@height}, but it wasn't."
end
def description
"be no larger than #{@width} by #{@height}"
end
end
def be_no_larger_than(width, height)
BeNoLargerThan.new(width, height)
end
class HaveDimensions # :nodoc:
def initialize(width, height)
@width, @height = width, height
end
def matches?(actual)
@actual = actual
# Satisfy expectation here. Return false or raise an error if it's not met.
image = ImageLoader.load_image(@actual.current_path)
@actual_width = image.width
@actual_height = image.height
@actual_width == @width && @actual_height == @height
end
def failure_message
"expected #{@actual.current_path.inspect} to have an exact size of #{@width} by #{@height}, but it was #{@actual_width} by #{@actual_height}."
end
def negative_failure_message
"expected #{@actual.current_path.inspect} not to have an exact size of #{@width} by #{@height}, but it did."
end
def description
"have an exact size of #{@width} by #{@height}"
end
end
def have_dimensions(width, height)
HaveDimensions.new(width, height)
end
class HaveHeight # :nodoc:
def initialize(height)
@height = height
end
def matches?(actual)
@actual = actual
# Satisfy expectation here. Return false or raise an error if it's not met.
image = ImageLoader.load_image(@actual.current_path)
@actual_height = image.height
@actual_height == @height
end
def failure_message
"expected #{@actual.current_path.inspect} to have an exact size of #{@height}, but it was #{@actual_height}."
end
def negative_failure_message
"expected #{@actual.current_path.inspect} not to have an exact size of #{@height}, but it did."
end
def description
"have an exact height of #{@height}"
end
end
def have_height(height)
HaveHeight.new(height)
end
class HaveWidth # :nodoc:
def initialize(width)
@width = width
end
def matches?(actual)
@actual = actual
# Satisfy expectation here. Return false or raise an error if it's not met.
image = ImageLoader.load_image(@actual.current_path)
@actual_width = image.width
@actual_width == @width
end
def failure_message
"expected #{@actual.current_path.inspect} to have an exact size of #{@width}, but it was #{@actual_width}."
end
def negative_failure_message
"expected #{@actual.current_path.inspect} not to have an exact size of #{@width}, but it did."
end
def description
"have an exact width of #{@width}"
end
end
def have_width(width)
HaveWidth.new(width)
end
class BeNoWiderThan # :nodoc:
def initialize(width)
@width = width
end
def matches?(actual)
@actual = actual
# Satisfy expectation here. Return false or raise an error if it's not met.
image = ImageLoader.load_image(@actual.current_path)
@actual_width = image.width
@actual_width <= @width
end
def failure_message
"expected #{@actual.current_path.inspect} to be no wider than #{@width}, but it was #{@actual_width}."
end
def negative_failure_message
"expected #{@actual.current_path.inspect} not to be wider than #{@width}, but it is."
end
def description
"have a width less than or equal to #{@width}"
end
end
def be_no_wider_than(width)
BeNoWiderThan.new(width)
end
class BeNoTallerThan # :nodoc:
def initialize(height)
@height = height
end
def matches?(actual)
@actual = actual
# Satisfy expectation here. Return false or raise an error if it's not met.
image = ImageLoader.load_image(@actual.current_path)
@actual_height = image.height
@actual_height <= @height
end
def failure_message
"expected #{@actual.current_path.inspect} to be no taller than #{@height}, but it was #{@actual_height}."
end
def negative_failure_message
"expected #{@actual.current_path.inspect} not to be taller than #{@height}, but it is."
end
def description
"have a height less than or equal to #{@height}"
end
end
def be_no_taller_than(height)
BeNoTallerThan.new(height)
end
class ImageLoader # :nodoc:
def self.load_image(filename)
if defined? ::MiniMagick
MiniMagickWrapper.new(filename)
else
unless defined? ::Magick
begin
require 'rmagick'
rescue LoadError
require 'RMagick'
rescue LoadError
puts "WARNING: Failed to require rmagick, image processing may fail!"
end
end
MagickWrapper.new(filename)
end
end
end
class MagickWrapper # :nodoc:
attr_reader :image
def width
image.columns
end
def height
image.rows
end
def initialize(filename)
@image = ::Magick::Image.read(filename).first
end
end
class MiniMagickWrapper # :nodoc:
attr_reader :image
def width
image[:width]
end
def height
image[:height]
end
def initialize(filename)
@image = ::MiniMagick::Image.open(filename)
end
end
end # Matchers
end # Test
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader.rb 0000664 0000000 0000000 00000004262 12140026204 0022223 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require "carrierwave/uploader/configuration"
require "carrierwave/uploader/callbacks"
require "carrierwave/uploader/proxy"
require "carrierwave/uploader/url"
require "carrierwave/uploader/mountable"
require "carrierwave/uploader/cache"
require "carrierwave/uploader/store"
require "carrierwave/uploader/download"
require "carrierwave/uploader/remove"
require "carrierwave/uploader/extension_whitelist"
require "carrierwave/uploader/extension_blacklist"
require "carrierwave/uploader/processing"
require "carrierwave/uploader/versions"
require "carrierwave/uploader/default_url"
require "carrierwave/uploader/serialization"
module CarrierWave
##
# See CarrierWave::Uploader::Base
#
module Uploader
##
# An uploader is a class that allows you to easily handle the caching and storage of
# uploaded files. Please refer to the README for configuration options.
#
# Once you have an uploader you can use it in isolation:
#
# my_uploader = MyUploader.new
# my_uploader.cache!(File.open(path_to_file))
# my_uploader.retrieve_from_store!('monkey.png')
#
# Alternatively, you can mount it on an ORM or other persistence layer, with
# +CarrierWave::Mount#mount_uploader+. There are extensions for activerecord and datamapper
# these are *very* simple (they are only a dozen lines of code), so adding your own should
# be trivial.
#
class Base
attr_reader :file
include CarrierWave::Uploader::Configuration
include CarrierWave::Uploader::Callbacks
include CarrierWave::Uploader::Proxy
include CarrierWave::Uploader::Url
include CarrierWave::Uploader::Mountable
include CarrierWave::Uploader::Cache
include CarrierWave::Uploader::Store
include CarrierWave::Uploader::Download
include CarrierWave::Uploader::Remove
include CarrierWave::Uploader::ExtensionWhitelist
include CarrierWave::Uploader::ExtensionBlacklist
include CarrierWave::Uploader::Processing
include CarrierWave::Uploader::Versions
include CarrierWave::Uploader::DefaultUrl
include CarrierWave::Uploader::Serialization
end # Base
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/ 0000775 0000000 0000000 00000000000 12140026204 0021672 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave/uploader/cache.rb 0000664 0000000 0000000 00000013075 12140026204 0023270 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
class FormNotMultipart < UploadError
def message
"You tried to assign a String or a Pathname to an uploader, for security reasons, this is not allowed.\n\n If this is a file upload, please check that your upload form is multipart encoded."
end
end
##
# Generates a unique cache id for use in the caching system
#
# === Returns
#
# [String] a cache id in the format YYYYMMDD-HHMM-PID-RND
#
def self.generate_cache_id
Time.now.strftime('%Y%m%d-%H%M') + '-' + Process.pid.to_s + '-' + ("%04d" % rand(9999))
end
module Uploader
module Cache
extend ActiveSupport::Concern
include CarrierWave::Uploader::Callbacks
include CarrierWave::Uploader::Configuration
module ClassMethods
##
# Removes cached files which are older than one day. You could call this method
# from a rake task to clean out old cached files.
#
# You can call this method directly on the module like this:
#
# CarrierWave.clean_cached_files!
#
# === Note
#
# This only works as long as you haven't done anything funky with your cache_dir.
# It's recommended that you keep cache files in one place only.
#
def clean_cached_files!(seconds=60*60*24)
Dir.glob(File.expand_path(File.join(cache_dir, '*'), CarrierWave.root)).each do |dir|
time = dir.scan(/(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})/).first.map { |t| t.to_i }
time = Time.utc(*time)
if time < (Time.now.utc - seconds)
FileUtils.rm_rf(dir)
end
end
end
end
##
# Returns true if the uploader has been cached
#
# === Returns
#
# [Bool] whether the current file is cached
#
def cached?
@cache_id
end
##
# Caches the remotely stored file
#
# This is useful when about to process images. Most processing solutions
# require the file to be stored on the local filesystem.
#
def cache_stored_file!
cache!
end
def sanitized_file
_content = file.read
if _content.is_a?(File) # could be if storage is Fog
sanitized = CarrierWave::Storage::Fog.new(self).retrieve!(File.basename(_content.path))
sanitized.read if sanitized.exists?
else
sanitized = SanitizedFile.new :tempfile => StringIO.new(file.read),
:filename => File.basename(path), :content_type => file.content_type
end
sanitized
end
##
# Returns a String which uniquely identifies the currently cached file for later retrieval
#
# === Returns
#
# [String] a cache name, in the format YYYYMMDD-HHMM-PID-RND/filename.txt
#
def cache_name
File.join(cache_id, full_original_filename) if cache_id and original_filename
end
##
# Caches the given file. Calls process! to trigger any process callbacks.
#
# By default, cache!() uses copy_to(), which operates by copying the file
# to the cache, then deleting the original file. If move_to_cache() is
# overriden to return true, then cache!() uses move_to(), which simply
# moves the file to the cache. Useful for large files.
#
# === Parameters
#
# [new_file (File, IOString, Tempfile)] any kind of file object
#
# === Raises
#
# [CarrierWave::FormNotMultipart] if the assigned parameter is a string
#
def cache!(new_file = sanitized_file)
new_file = CarrierWave::SanitizedFile.new(new_file)
unless new_file.empty?
raise CarrierWave::FormNotMultipart if new_file.is_path? && ensure_multipart_form
with_callbacks(:cache, new_file) do
self.cache_id = CarrierWave.generate_cache_id unless cache_id
@filename = new_file.filename
self.original_filename = new_file.filename
if move_to_cache
@file = new_file.move_to(cache_path, permissions, directory_permissions)
else
@file = new_file.copy_to(cache_path, permissions, directory_permissions)
end
end
end
end
##
# Retrieves the file with the given cache_name from the cache.
#
# === Parameters
#
# [cache_name (String)] uniquely identifies a cache file
#
# === Raises
#
# [CarrierWave::InvalidParameter] if the cache_name is incorrectly formatted.
#
def retrieve_from_cache!(cache_name)
with_callbacks(:retrieve_from_cache, cache_name) do
self.cache_id, self.original_filename = cache_name.to_s.split('/', 2)
@filename = original_filename
@file = CarrierWave::SanitizedFile.new(cache_path)
end
end
private
def cache_path
File.expand_path(File.join(cache_dir, cache_name), root)
end
attr_reader :cache_id, :original_filename
# We can override the full_original_filename method in other modules
alias_method :full_original_filename, :original_filename
def cache_id=(cache_id)
raise CarrierWave::InvalidParameter, "invalid cache id" unless cache_id =~ /\A[\d]{8}\-[\d]{4}\-[\d]+\-[\d]{4}\z/
@cache_id = cache_id
end
def original_filename=(filename)
raise CarrierWave::InvalidParameter, "invalid filename" if filename =~ CarrierWave::SanitizedFile.sanitize_regexp
@original_filename = filename
end
end # Cache
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/callbacks.rb 0000664 0000000 0000000 00000001717 12140026204 0024144 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module Callbacks
extend ActiveSupport::Concern
included do
class_attribute :_before_callbacks, :_after_callbacks,
:instance_writer => false
self._before_callbacks = Hash.new []
self._after_callbacks = Hash.new []
end
def with_callbacks(kind, *args)
self.class._before_callbacks[kind].each { |c| send c, *args }
yield
self.class._after_callbacks[kind].each { |c| send c, *args }
end
module ClassMethods
def before(kind, callback)
self._before_callbacks = self._before_callbacks.
merge kind => _before_callbacks[kind] + [callback]
end
def after(kind, callback)
self._after_callbacks = self._after_callbacks.
merge kind => _after_callbacks[kind] + [callback]
end
end # ClassMethods
end # Callbacks
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/configuration.rb 0000664 0000000 0000000 00000011523 12140026204 0025070 0 ustar 00root root 0000000 0000000 module CarrierWave
module Uploader
module Configuration
extend ActiveSupport::Concern
included do
class_attribute :_storage, :instance_writer => false
add_config :root
add_config :base_path
add_config :asset_host
add_config :permissions
add_config :directory_permissions
add_config :storage_engines
add_config :store_dir
add_config :cache_dir
add_config :enable_processing
add_config :ensure_multipart_form
add_config :delete_tmp_file_after_storage
add_config :move_to_cache
add_config :move_to_store
add_config :remove_previously_stored_files_after_update
# fog
add_config :fog_attributes
add_config :fog_credentials
add_config :fog_directory
add_config :fog_public
add_config :fog_authenticated_url_expiration
# Mounting
add_config :ignore_integrity_errors
add_config :ignore_processing_errors
add_config :ignore_download_errors
add_config :validate_integrity
add_config :validate_processing
add_config :validate_download
add_config :mount_on
# set default values
reset_config
end
module ClassMethods
##
# Sets the storage engine to be used when storing files with this uploader.
# Can be any class that implements a #store!(CarrierWave::SanitizedFile) and a #retrieve!
# method. See lib/carrierwave/storage/file.rb for an example. Storage engines should
# be added to CarrierWave::Uploader::Base.storage_engines so they can be referred
# to by a symbol, which should be more convenient
#
# If no argument is given, it will simply return the currently used storage engine.
#
# === Parameters
#
# [storage (Symbol, Class)] The storage engine to use for this uploader
#
# === Returns
#
# [Class] the storage engine to be used with this uploader
#
# === Examples
#
# storage :file
# storage CarrierWave::Storage::File
# storage MyCustomStorageEngine
#
def storage(storage = nil)
if storage
self._storage = storage.is_a?(Symbol) ? eval(storage_engines[storage]) : storage
end
_storage
end
alias_method :storage=, :storage
def add_config(name)
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def self.#{name}(value=nil)
@#{name} = value if value
return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
name = superclass.#{name}
return nil if name.nil? && !instance_variable_defined?("@#{name}")
@#{name} = name && !name.is_a?(Module) && !name.is_a?(Symbol) && !name.is_a?(Numeric) && !name.is_a?(TrueClass) && !name.is_a?(FalseClass) ? name.dup : name
end
def self.#{name}=(value)
@#{name} = value
end
def #{name}=(value)
@#{name} = value
end
def #{name}
value = @#{name} if instance_variable_defined?(:@#{name})
value = self.class.#{name} unless instance_variable_defined?(:@#{name})
value.instance_of?(Proc) ? value.call : value
end
RUBY
end
def configure
yield self
end
##
# sets configuration back to default
#
def reset_config
configure do |config|
config.permissions = 0644
config.directory_permissions = 0755
config.storage_engines = {
:file => "CarrierWave::Storage::File",
:fog => "CarrierWave::Storage::Fog"
}
config.storage = :file
config.fog_attributes = {}
config.fog_credentials = {}
config.fog_public = true
config.fog_authenticated_url_expiration = 600
config.store_dir = 'uploads'
config.cache_dir = 'uploads/tmp'
config.delete_tmp_file_after_storage = true
config.move_to_cache = false
config.move_to_store = false
config.remove_previously_stored_files_after_update = true
config.ignore_integrity_errors = true
config.ignore_processing_errors = true
config.ignore_download_errors = true
config.validate_integrity = true
config.validate_processing = true
config.validate_download = true
config.root = lambda { CarrierWave.root }
config.base_path = CarrierWave.base_path
config.enable_processing = true
config.ensure_multipart_form = true
end
end
end
end
end
end
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/default_url.rb 0000664 0000000 0000000 00000000554 12140026204 0024531 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module DefaultUrl
def url(*args)
super || default_url
end
##
# Override this method in your uploader to provide a default url
# in case no file has been cached/stored yet.
#
def default_url; end
end # DefaultPath
end # Uploader
end # CarrierWave ruby-carrierwave-0.8.0/lib/carrierwave/uploader/download.rb 0000664 0000000 0000000 00000003512 12140026204 0024027 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'open-uri'
module CarrierWave
module Uploader
module Download
extend ActiveSupport::Concern
include CarrierWave::Uploader::Callbacks
include CarrierWave::Uploader::Configuration
include CarrierWave::Uploader::Cache
class RemoteFile
def initialize(uri)
@uri = uri
end
def original_filename
File.basename(file.base_uri.path)
end
def respond_to?(*args)
super or file.respond_to?(*args)
end
def http?
@uri.scheme =~ /^https?$/
end
private
def file
if @file.blank?
@file = Kernel.open(@uri.to_s)
@file = @file.is_a?(String) ? StringIO.new(@file) : @file
end
@file
rescue Exception => e
raise CarrierWave::DownloadError, "could not download file: #{e.message}"
end
def method_missing(*args, &block)
file.send(*args, &block)
end
end
##
# Caches the file by downloading it from the given URL.
#
# === Parameters
#
# [url (String)] The URL where the remote file is stored
#
def download!(uri)
unless uri.blank?
processed_uri = process_uri(uri)
file = RemoteFile.new(processed_uri)
raise CarrierWave::DownloadError, "trying to download a file which is not served over HTTP" unless file.http?
cache!(file)
end
end
##
# Processes the given URL by parsing and escaping it. Public to allow overriding.
#
# === Parameters
#
# [url (String)] The URL where the remote file is stored
#
def process_uri(uri)
URI.parse(URI.escape(URI.unescape(uri)))
end
end # Download
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/extension_blacklist.rb 0000664 0000000 0000000 00000002676 12140026204 0026276 0 ustar 00root root 0000000 0000000 module CarrierWave
module Uploader
module ExtensionBlacklist
extend ActiveSupport::Concern
included do
before :cache, :check_blacklist!
end
##
# Override this method in your uploader to provide a black list of extensions which
# are prohibited to be uploaded. Compares the file's extension case insensitive.
# Furthermore, not only strings but Regexp are allowed as well.
#
# When using a Regexp in the black list, `\A` and `\z` are automatically added to
# the Regexp expression, also case insensitive.
#
# === Returns
# [NilClass, Array[String,Regexp]] a black list of extensions which are prohibited to be uploaded
#
# === Examples
#
# def extension_black_list
# %w(swf tiff)
# end
#
# Basically the same, but using a Regexp:
#
# def extension_black_list
# [/swf/, 'tiff']
# end
#
def extension_black_list; end
private
def check_blacklist!(new_file)
extension = new_file.extension.to_s
if extension_black_list and extension_black_list.detect { |item| extension =~ /\A#{item}\z/i }
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_black_list_error", :extension => new_file.extension.inspect, :prohibited_types => extension_black_list.join(", "))
end
end
end
end
end
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/extension_whitelist.rb 0000664 0000000 0000000 00000003012 12140026204 0026323 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module ExtensionWhitelist
extend ActiveSupport::Concern
included do
before :cache, :check_whitelist!
end
##
# Override this method in your uploader to provide a white list of extensions which
# are allowed to be uploaded. Compares the file's extension case insensitive.
# Furthermore, not only strings but Regexp are allowed as well.
#
# When using a Regexp in the white list, `\A` and `\z` are automatically added to
# the Regexp expression, also case insensitive.
#
# === Returns
#
# [NilClass, Array[String,Regexp]] a white list of extensions which are allowed to be uploaded
#
# === Examples
#
# def extension_white_list
# %w(jpg jpeg gif png)
# end
#
# Basically the same, but using a Regexp:
#
# def extension_white_list
# [/jpe?g/, 'gif', 'png']
# end
#
def extension_white_list; end
private
def check_whitelist!(new_file)
extension = new_file.extension.to_s
if extension_white_list and not extension_white_list.detect { |item| extension =~ /\A#{item}\z/i }
raise CarrierWave::IntegrityError, I18n.translate(:"errors.messages.extension_white_list_error", :extension => new_file.extension.inspect, :allowed_types => extension_white_list.join(", "))
end
end
end # ExtensionWhitelist
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/mountable.rb 0000664 0000000 0000000 00000002255 12140026204 0024211 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module Mountable
attr_reader :model, :mounted_as
##
# If a model is given as the first parameter, it will be stored in the uploader, and
# available throught +#model+. Likewise, mounted_as stores the name of the column
# where this instance of the uploader is mounted. These values can then be used inside
# your uploader.
#
# If you do not wish to mount your uploaders with the ORM extensions in -more then you
# can override this method inside your uploader. Just be sure to call +super+
#
# === Parameters
#
# [model (Object)] Any kind of model object
# [mounted_as (Symbol)] The name of the column where this uploader is mounted
#
# === Examples
#
# class MyUploader < CarrierWave::Uploader::Base
#
# def store_dir
# File.join('public', 'files', mounted_as, model.permalink)
# end
# end
#
def initialize(model=nil, mounted_as=nil)
@model = model
@mounted_as = mounted_as
end
end # Mountable
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/processing.rb 0000664 0000000 0000000 00000005014 12140026204 0024373 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module Processing
extend ActiveSupport::Concern
include CarrierWave::Uploader::Callbacks
included do
class_attribute :processors, :instance_writer => false
self.processors = []
after :cache, :process!
end
module ClassMethods
##
# Adds a processor callback which applies operations as a file is uploaded.
# The argument may be the name of any method of the uploader, expressed as a symbol,
# or a list of such methods, or a hash where the key is a method and the value is
# an array of arguments to call the method with
#
# === Parameters
#
# args (*Symbol, Hash{Symbol => Array[]})
#
# === Examples
#
# class MyUploader < CarrierWave::Uploader::Base
#
# process :sepiatone, :vignette
# process :scale => [200, 200]
# process :scale => [200, 200], :if => :image?
# process :sepiatone, :if => :image?
#
# def sepiatone
# ...
# end
#
# def vignette
# ...
# end
#
# def scale(height, width)
# ...
# end
#
# def image?
# ...
# end
#
# end
#
def process(*args)
if !args.first.is_a?(Hash) && args.last.is_a?(Hash)
conditions = args.pop
args.map!{ |arg| {arg => []}.merge(conditions) }
end
args.each do |arg|
if arg.is_a?(Hash)
condition = arg.delete(:if)
arg.each do |method, args|
self.processors += [[method, args, condition]]
end
else
self.processors += [[arg, [], nil]]
end
end
end
end # ClassMethods
##
# Apply all process callbacks added through CarrierWave.process
#
def process!(new_file=nil)
if enable_processing
self.class.processors.each do |method, args, condition|
if(condition)
next if !(condition.respond_to?(:call) ? condition.call(self, :args => args, :method => method, :file => new_file) : self.send(condition, new_file))
end
self.send(method, *args)
end
end
end
end # Processing
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/proxy.rb 0000664 0000000 0000000 00000002745 12140026204 0023410 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module Proxy
##
# === Returns
#
# [Boolean] Whether the uploaded file is blank
#
def blank?
file.blank?
end
##
# === Returns
#
# [String] the path where the file is currently located.
#
def current_path
file.path if file.respond_to?(:path)
end
alias_method :path, :current_path
##
# Returns a string that uniquely identifies the last stored file
#
# === Returns
#
# [String] uniquely identifies a file
#
def identifier
storage.identifier if storage.respond_to?(:identifier)
end
##
# Read the contents of the file
#
# === Returns
#
# [String] contents of the file
#
def read
file.read if file.respond_to?(:read)
end
##
# Fetches the size of the currently stored/cached file
#
# === Returns
#
# [Integer] size of the file
#
def size
file.respond_to?(:size) ? file.size : 0
end
##
# Return the size of the file when asked for its length
#
# === Returns
#
# [Integer] size of the file
#
# === Note
#
# This was added because of the way Rails handles length/size validations in 3.0.6 and above.
#
def length
size
end
end # Proxy
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/remove.rb 0000664 0000000 0000000 00000000646 12140026204 0023522 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module Remove
extend ActiveSupport::Concern
include CarrierWave::Uploader::Callbacks
##
# Removes the file and reset it
#
def remove!
with_callbacks(:remove) do
@file.delete if @file
@file = nil
@cache_id = nil
end
end
end # Remove
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/serialization.rb 0000664 0000000 0000000 00000001277 12140026204 0025103 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require "active_support/json"
require "active_support/core_ext/hash"
module CarrierWave
module Uploader
module Serialization
extend ActiveSupport::Concern
def serializable_hash
{"url" => url}.merge Hash[versions.map { |name, version| [name, { "url" => version.url }] }]
end
def as_json(options=nil)
Hash[mounted_as || "uploader", serializable_hash]
end
def to_json
ActiveSupport::JSON.encode(as_json)
end
def to_xml(options={})
merged_options = options.merge(:root => mounted_as || "uploader", :type => 'uploader')
serializable_hash.to_xml(merged_options)
end
end
end
end
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/store.rb 0000664 0000000 0000000 00000005763 12140026204 0023366 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module Store
extend ActiveSupport::Concern
include CarrierWave::Uploader::Callbacks
include CarrierWave::Uploader::Configuration
include CarrierWave::Uploader::Cache
##
# Override this in your Uploader to change the filename.
#
# Be careful using record ids as filenames. If the filename is stored in the database
# the record id will be nil when the filename is set. Don't use record ids unless you
# understand this limitation.
#
# Do not use the version_name in the filename, as it will prevent versions from being
# loaded correctly.
#
# === Returns
#
# [String] a filename
#
def filename
@filename
end
##
# Calculates the path where the file should be stored. If +for_file+ is given, it will be
# used as the filename, otherwise +CarrierWave::Uploader#filename+ is assumed.
#
# === Parameters
#
# [for_file (String)] name of the file
#
# === Returns
#
# [String] the store path
#
def store_path(for_file=filename)
File.join([store_dir, full_filename(for_file)].compact)
end
##
# Stores the file by passing it to this Uploader's storage engine.
#
# If new_file is omitted, a previously cached file will be stored.
#
# === Parameters
#
# [new_file (File, IOString, Tempfile)] any kind of file object
#
def store!(new_file=nil)
cache!(new_file) if new_file && ((@cache_id != parent_cache_id) || @cache_id.nil?)
if @file and @cache_id
with_callbacks(:store, new_file) do
new_file = storage.store!(@file)
@file.delete if (delete_tmp_file_after_storage && ! move_to_store)
delete_cache_id
@file = new_file
@cache_id = nil
end
end
end
##
# Deletes a cache id (tmp dir in cache)
#
def delete_cache_id
if @cache_id
path = File.expand_path(File.join(cache_dir, @cache_id), CarrierWave.root)
begin
Dir.rmdir(path)
rescue Errno::ENOENT
# Ignore: path does not exist
rescue Errno::ENOTDIR
# Ignore: path is not a dir
rescue Errno::ENOTEMPTY, Errno::EEXIST
# Ignore: dir is not empty
end
end
end
##
# Retrieves the file from the storage.
#
# === Parameters
#
# [identifier (String)] uniquely identifies the file to retrieve
#
def retrieve_from_store!(identifier)
with_callbacks(:retrieve_from_store, identifier) do
@file = storage.retrieve!(identifier)
end
end
private
def full_filename(for_file)
for_file
end
def storage
@storage ||= self.class.storage.new(self)
end
end # Store
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/url.rb 0000664 0000000 0000000 00000001722 12140026204 0023023 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module Url
extend ActiveSupport::Concern
include CarrierWave::Uploader::Configuration
##
# === Parameters
#
# [Hash] optional, the query params (only AWS)
#
# === Returns
#
# [String] the location where this file is accessible via a url
#
def url(options = {})
if file.respond_to?(:url) and not file.url.blank?
file.method(:url).arity == 0 ? file.url : file.url(options)
elsif file.respond_to?(:path)
path = file.path.gsub(File.expand_path(root), '')
if host = asset_host
if host.respond_to? :call
"#{host.call(file)}#{path}"
else
"#{host}#{path}"
end
else
(base_path || "") + path
end
end
end
def to_s
url || ''
end
end # Url
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/uploader/versions.rb 0000664 0000000 0000000 00000021140 12140026204 0024065 0 ustar 00root root 0000000 0000000 # encoding: utf-8
module CarrierWave
module Uploader
module Versions
extend ActiveSupport::Concern
include CarrierWave::Uploader::Callbacks
included do
class_attribute :versions, :version_names, :instance_reader => false, :instance_writer => false
self.versions = {}
self.version_names = []
attr_accessor :parent_cache_id
after :cache, :assign_parent_cache_id
after :cache, :cache_versions!
after :store, :store_versions!
after :remove, :remove_versions!
after :retrieve_from_cache, :retrieve_versions_from_cache!
after :retrieve_from_store, :retrieve_versions_from_store!
end
module ClassMethods
##
# Adds a new version to this uploader
#
# === Parameters
#
# [name (#to_sym)] name of the version
# [options (Hash)] optional options hash
# [&block (Proc)] a block to eval on this version of the uploader
#
# === Examples
#
# class MyUploader < CarrierWave::Uploader::Base
#
# version :thumb do
# process :scale => [200, 200]
# end
#
# version :preview, :if => :image? do
# process :scale => [200, 200]
# end
#
# end
#
def version(name, options = {}, &block)
name = name.to_sym
unless versions[name]
uploader = Class.new(self)
const_set("Uploader#{uploader.object_id}".gsub('-', '_'), uploader)
uploader.versions = {}
# Define the enable_processing method for versions so they get the
# value from the parent class unless explicitly overwritten
uploader.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def self.enable_processing(value=nil)
self.enable_processing = value if value
if !@enable_processing.nil?
@enable_processing
else
superclass.enable_processing
end
end
RUBY
# Add the current version hash to class attribute :versions
current_version = {}
current_version[name] = {
:uploader => uploader,
:options => options
}
self.versions = versions.merge(current_version)
versions[name][:uploader].version_names += [name]
class_eval <<-RUBY
def #{name}
versions[:#{name}]
end
RUBY
# as the processors get the output from the previous processors as their
# input we must not stack the processors here
versions[name][:uploader].processors = versions[name][:uploader].processors.dup
versions[name][:uploader].processors.clear
end
versions[name][:uploader].class_eval(&block) if block
versions[name]
end
def recursively_apply_block_to_versions(&block)
versions.each do |name, version|
version[:uploader].class_eval(&block)
version[:uploader].recursively_apply_block_to_versions(&block)
end
end
end # ClassMethods
##
# Returns a hash mapping the name of each version of the uploader to an instance of it
#
# === Returns
#
# [Hash{Symbol => CarrierWave::Uploader}] a list of uploader instances
#
def versions
return @versions if @versions
@versions = {}
self.class.versions.each do |name, version|
@versions[name] = version[:uploader].new(model, mounted_as)
end
@versions
end
##
# === Returns
#
# [String] the name of this version of the uploader
#
def version_name
self.class.version_names.join('_').to_sym unless self.class.version_names.blank?
end
##
# When given a version name as a parameter, will return the url for that version
# This also works with nested versions.
# When given a query hash as a parameter, will return the url with signature that contains query params
# Query hash only works with AWS (S3 storage).
#
# === Example
#
# my_uploader.url # => /path/to/my/uploader.gif
# my_uploader.url(:thumb) # => /path/to/my/thumb_uploader.gif
# my_uploader.url(:thumb, :small) # => /path/to/my/thumb_small_uploader.gif
# my_uploader.url(:query => {"response-content-disposition" => "attachment"})
# my_uploader.url(:version, :sub_version, :query => {"response-content-disposition" => "attachment"})
#
# === Parameters
#
# [*args (Symbol)] any number of versions
# OR/AND
# [Hash] query params
#
# === Returns
#
# [String] the location where this file is accessible via a url
#
def url(*args)
if (version = args.first) && version.respond_to?(:to_sym)
raise ArgumentError, "Version #{version} doesn't exist!" if versions[version.to_sym].nil?
# recursively proxy to version
versions[version.to_sym].url(*args[1..-1])
elsif args.first
super(args.first)
else
super
end
end
##
# Recreate versions and reprocess them. This can be used to recreate
# versions if their parameters somehow have changed.
#
def recreate_versions!(*versions)
# Some files could possibly not be stored on the local disk. This
# doesn't play nicely with processing. Make sure that we're only
# processing a cached file
#
# The call to store! will trigger the necessary callbacks to both
# process this version and all sub-versions
if versions.any?
file = sanitized_file if !cached?
store_versions!(file, versions)
else
cache! if !cached?
store!
end
end
private
def assign_parent_cache_id(file)
active_versions.each do |name, uploader|
uploader.parent_cache_id = @cache_id
end
end
def active_versions
versions.select do |name, uploader|
condition = self.class.versions[name][:options][:if]
if(condition)
if(condition.respond_to?(:call))
condition.call(self, :version => name, :file => file)
else
send(condition, file)
end
else
true
end
end
end
def full_filename(for_file)
[version_name, super(for_file)].compact.join('_')
end
def full_original_filename
[version_name, super].compact.join('_')
end
def cache_versions!(new_file)
# We might have processed the new_file argument after the callbacks were
# initialized, so get the actual file based off of the current state of
# our file
processed_parent = SanitizedFile.new :tempfile => self.file,
:filename => new_file.original_filename
active_versions.each do |name, v|
next if v.cached?
v.send(:cache_id=, cache_id)
# If option :from_version is present, create cache using cached file from
# version indicated
if self.class.versions[name][:options] && self.class.versions[name][:options][:from_version]
# Maybe the reference version has not been cached yet
unless versions[self.class.versions[name][:options][:from_version]].cached?
versions[self.class.versions[name][:options][:from_version]].cache!(processed_parent)
end
processed_version = SanitizedFile.new :tempfile => versions[self.class.versions[name][:options][:from_version]],
:filename => new_file.original_filename
v.cache!(processed_version)
else
v.cache!(processed_parent)
end
end
end
def store_versions!(new_file, versions=nil)
if versions
versions.each { |v| Hash[active_versions][v].store!(new_file) }
else
active_versions.each { |name, v| v.store!(new_file) }
end
end
def remove_versions!
versions.each { |name, v| v.remove! }
end
def retrieve_versions_from_cache!(cache_name)
versions.each { |name, v| v.retrieve_from_cache!(cache_name) }
end
def retrieve_versions_from_store!(identifier)
versions.each { |name, v| v.retrieve_from_store!(identifier) }
end
end # Versions
end # Uploader
end # CarrierWave
ruby-carrierwave-0.8.0/lib/carrierwave/validations/ 0000775 0000000 0000000 00000000000 12140026204 0022374 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/carrierwave/validations/active_model.rb 0000664 0000000 0000000 00000005053 12140026204 0025357 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'active_model/validator'
require 'active_support/concern'
module CarrierWave
# == Active Model Presence Validator
module Validations
module ActiveModel
extend ActiveSupport::Concern
class ProcessingValidator < ::ActiveModel::EachValidator
def validate_each(record, attribute, value)
if e = record.send("#{attribute}_processing_error")
message = (e.message == e.class.to_s) ? :carrierwave_processing_error : e.message
record.errors.add(attribute, message)
end
end
end
class IntegrityValidator < ::ActiveModel::EachValidator
def validate_each(record, attribute, value)
if e = record.send("#{attribute}_integrity_error")
message = (e.message == e.class.to_s) ? :carrierwave_integrity_error : e.message
record.errors.add(attribute, message)
end
end
end
class DownloadValidator < ::ActiveModel::EachValidator
def validate_each(record, attribute, value)
if e = record.send("#{attribute}_download_error")
message = (e.message == e.class.to_s) ? :carrierwave_download_error : e.message
record.errors.add(attribute, message)
end
end
end
module HelperMethods
##
# Makes the record invalid if the file couldn't be uploaded due to an integrity error
#
# Accepts the usual parameters for validations in Rails (:if, :unless, etc...)
#
def validates_integrity_of(*attr_names)
validates_with IntegrityValidator, _merge_attributes(attr_names)
end
##
# Makes the record invalid if the file couldn't be processed (assuming the process failed
# with a CarrierWave::ProcessingError)
#
# Accepts the usual parameters for validations in Rails (:if, :unless, etc...)
#
def validates_processing_of(*attr_names)
validates_with ProcessingValidator, _merge_attributes(attr_names)
end
#
##
# Makes the record invalid if the remote file couldn't be downloaded
#
# Accepts the usual parameters for validations in Rails (:if, :unless, etc...)
#
def validates_download_of(*attr_names)
validates_with DownloadValidator, _merge_attributes(attr_names)
end
end
included do
extend HelperMethods
include HelperMethods
end
end
end
end
I18n.load_path << File.join(File.dirname(__FILE__), "..", "locale", 'en.yml')
ruby-carrierwave-0.8.0/lib/carrierwave/version.rb 0000664 0000000 0000000 00000000053 12140026204 0022067 0 ustar 00root root 0000000 0000000 module CarrierWave
VERSION = "0.8.0"
end
ruby-carrierwave-0.8.0/lib/generators/ 0000775 0000000 0000000 00000000000 12140026204 0017716 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/generators/templates/ 0000775 0000000 0000000 00000000000 12140026204 0021714 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/lib/generators/templates/uploader.rb 0000664 0000000 0000000 00000003166 12140026204 0024062 0 ustar 00root root 0000000 0000000 # encoding: utf-8
class <%= class_name %>Uploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
# include CarrierWave::MiniMagick
# Include the Sprockets helpers for Rails 3.1+ asset pipeline compatibility:
# include Sprockets::Helpers::RailsHelper
# include Sprockets::Helpers::IsolatedHelper
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
# Provide a default URL as a default if there hasn't been a file uploaded:
# def default_url
# # For Rails 3.1+ asset pipeline compatibility:
# # asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
#
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
# end
# Process files as they are uploaded:
# process :scale => [200, 300]
#
# def scale(width, height)
# # do something
# end
# Create different versions of your uploaded files:
# version :thumb do
# process :scale => [50, 50]
# end
# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
# def extension_white_list
# %w(jpg jpeg gif png)
# end
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
end
ruby-carrierwave-0.8.0/lib/generators/uploader_generator.rb 0000664 0000000 0000000 00000000332 12140026204 0024122 0 ustar 00root root 0000000 0000000 class UploaderGenerator < Rails::Generators::NamedBase
source_root File.expand_path("../templates", __FILE__)
def create_uploader_file
template "uploader.rb", "app/uploaders/#{file_name}_uploader.rb"
end
end ruby-carrierwave-0.8.0/script/ 0000775 0000000 0000000 00000000000 12140026204 0016303 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/script/console 0000775 0000000 0000000 00000000674 12140026204 0017702 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
# File: script/console
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
libs = " -r irb/completion"
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
libs << " -r #{File.dirname(__FILE__) + '/../lib/carrierwave.rb'}"
puts "Loading carrierwave gem"
exec "#{irb} #{libs} --simple-prompt" ruby-carrierwave-0.8.0/script/destroy 0000775 0000000 0000000 00000000603 12140026204 0017721 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
begin
require 'rubigen'
rescue LoadError
require 'rubygems'
require 'rubigen'
end
require 'rubigen/scripts/destroy'
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
RubiGen::Scripts::Destroy.new.run(ARGV)
ruby-carrierwave-0.8.0/script/generate 0000775 0000000 0000000 00000000605 12140026204 0020024 0 ustar 00root root 0000000 0000000 #!/usr/bin/env ruby
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
begin
require 'rubigen'
rescue LoadError
require 'rubygems'
require 'rubigen'
end
require 'rubigen/scripts/generate'
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
RubiGen::Scripts::Generate.new.run(ARGV)
ruby-carrierwave-0.8.0/spec/ 0000775 0000000 0000000 00000000000 12140026204 0015731 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/spec/compatibility/ 0000775 0000000 0000000 00000000000 12140026204 0020602 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/spec/compatibility/paperclip_spec.rb 0000664 0000000 0000000 00000003033 12140026204 0024117 0 ustar 00root root 0000000 0000000 # encoding: utf-8
require 'spec_helper'
require 'carrierwave/orm/activerecord'
module Rails; end unless defined?(Rails)
describe CarrierWave::Compatibility::Paperclip do
before do
Rails.stub(:root).and_return('/rails/root')
Rails.stub(:env).and_return('test')
@uploader_class = Class.new(CarrierWave::Uploader::Base) do
include CarrierWave::Compatibility::Paperclip
end
@model = mock('a model')
@model.stub!(:id).and_return(23)
@uploader = @uploader_class.new(@model, :monkey)
end
after do
FileUtils.rm_rf(public_path)
end
describe '#store_path' do
it "should mimics paperclip default" do
@uploader.store_path("monkey.png").should == "/rails/root/public/system/monkeys/23/original/monkey.png"
end
it "should interpolate the root path" do
@uploader.stub!(:paperclip_path).and_return(":rails_root/foo/bar")
@uploader.store_path("monkey.png").should == Rails.root + "/foo/bar"
end
it "should interpolate the attachment" do
@uploader.stub!(:paperclip_path).and_return("/foo/:attachment/bar")
@uploader.store_path("monkey.png").should == "/foo/monkeys/bar"
end
it "should interpolate the id" do
@uploader.stub!(:paperclip_path).and_return("/foo/:id/bar")
@uploader.store_path("monkey.png").should == "/foo/23/bar"
end
it "should interpolate the id partition" do
@uploader.stub!(:paperclip_path).and_return("/foo/:id_partition/bar")
@uploader.store_path("monkey.png").should == "/foo/000/000/023/bar"
end
end
end
ruby-carrierwave-0.8.0/spec/fixtures/ 0000775 0000000 0000000 00000000000 12140026204 0017602 5 ustar 00root root 0000000 0000000 ruby-carrierwave-0.8.0/spec/fixtures/Uppercase.jpg 0000664 0000000 0000000 00000000015 12140026204 0022227 0 ustar 00root root 0000000 0000000 this is stuff ruby-carrierwave-0.8.0/spec/fixtures/bork.ttxt 0000664 0000000 0000000 00000000715 12140026204 0021467 0 ustar 00root root 0000000 0000000 bork bork bork Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ruby-carrierwave-0.8.0/spec/fixtures/bork.txt 0000664 0000000 0000000 00000000715 12140026204 0021303 0 ustar 00root root 0000000 0000000 bork bork bork Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ruby-carrierwave-0.8.0/spec/fixtures/bork.txtt 0000664 0000000 0000000 00000000715 12140026204 0021467 0 ustar 00root root 0000000 0000000 bork bork bork Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. ruby-carrierwave-0.8.0/spec/fixtures/case.JPG 0000664 0000000 0000000 00000000015 12140026204 0021053 0 ustar 00root root 0000000 0000000 this is stuff ruby-carrierwave-0.8.0/spec/fixtures/landscape.jpg 0000664 0000000 0000000 00000511326 12140026204 0022246 0 ustar 00root root 0000000 0000000 JFIF HiExif II*
( 1 2 i \ Panasonic DMC-FZ5 H H ACD Systems Digital Imaging 2005:07:18 13:17:36 # " ' P 0220
| \ 718 0100 6 T K
(
2005:07:15 11:58:30 2005:07:15 11:58:30 d
(
Panasonic ! " # $ % &