Commit 8271d89c by Tute Costa

Merge branch 'master' into v4.2

parents 67580ee3 db1ebd13
This diff is collapsed. Click to expand it.
inherit_from: .hound.yml
...@@ -4,20 +4,24 @@ rvm: ...@@ -4,20 +4,24 @@ rvm:
- rbx-2 - rbx-2
- 2.0.0 - 2.0.0
- 2.1.1 - 2.1.1
- 2.2.2
install: install:
- "travis_retry bundle install" - "travis_retry bundle install"
before_script: "sudo ntpdate -ub ntp.ubuntu.com pool.ntp.org; true"
script: "bundle exec rake clean spec cucumber" script: "bundle exec rake clean spec cucumber"
gemfile: gemfile:
- gemfiles/3.2.gemfile - gemfiles/3.2.gemfile
- gemfiles/4.0.gemfile - gemfiles/4.0.gemfile
- gemfiles/4.1.gemfile - gemfiles/4.1.gemfile
- gemfiles/4.2.gemfile
matrix: matrix:
fast_finish: true fast_finish: true
allow_failures: allow_failures:
- rvm: jruby-19mode - rvm: jruby-19mode
- rvm: rbx-2 - rvm: rbx-2
sudo: false
cache: bundler
...@@ -14,6 +14,6 @@ appraise "4.1" do ...@@ -14,6 +14,6 @@ appraise "4.1" do
end end
appraise "4.2" do appraise "4.2" do
gem "rails", "~> 4.2.0.rc2" gem "rails", "~> 4.2.0"
gem "paperclip", :path => "../" gem "paperclip", :path => "../"
end end
...@@ -6,7 +6,7 @@ We love pull requests. Here's a quick guide: ...@@ -6,7 +6,7 @@ We love pull requests. Here's a quick guide:
1. Fork the repo. 1. Fork the repo.
2. Run the tests. We only take pull requests with passing tests, and it's great 2. Run the tests. We only take pull requests with passing tests, and it's great
to know that you have a clean slate: `bundle && rake` to know that you have a clean slate: `bundle && bundle exec rake`
3. Add a test for your change. Only refactoring and documentation changes 3. Add a test for your change. Only refactoring and documentation changes
require no new tests. If you are adding functionality or fixing a bug, we need require no new tests. If you are adding functionality or fixing a bug, we need
...@@ -43,14 +43,14 @@ will be asked to rewrite them before we'll accept. ...@@ -43,14 +43,14 @@ will be asked to rewrite them before we'll accept.
### Bootstrapping your test suite: ### Bootstrapping your test suite:
bundle install bundle install
bundle exec rake appraisal:install bundle exec appraisal install
This will install all the required gems that requires to test against each This will install all the required gems that requires to test against each
version of Rails, which defined in `gemfiles/*.gemfile`. version of Rails, which defined in `gemfiles/*.gemfile`.
### To run a full test suite: ### To run a full test suite:
bundle exec rake bundle exec appraisal rake
This will run RSpec and Cucumber against all version of Rails This will run RSpec and Cucumber against all version of Rails
......
...@@ -2,7 +2,7 @@ source "https://rubygems.org" ...@@ -2,7 +2,7 @@ source "https://rubygems.org"
gemspec gemspec
gem 'sqlite3', '1.3.8', :platforms => :ruby gem 'sqlite3', '~>1.3.8', :platforms => :ruby
gem 'jruby-openssl', :platforms => :jruby gem 'jruby-openssl', :platforms => :jruby
gem 'activerecord-jdbcsqlite3-adapter', :platforms => :jruby gem 'activerecord-jdbcsqlite3-adapter', :platforms => :jruby
...@@ -17,4 +17,5 @@ gem 'pry' ...@@ -17,4 +17,5 @@ gem 'pry'
group :development, :test do group :development, :test do
gem 'mime-types', '~> 1.16' gem 'mime-types', '~> 1.16'
gem 'builder' gem 'builder'
gem 'rubocop', require: false
end end
...@@ -3,7 +3,7 @@ LICENSE ...@@ -3,7 +3,7 @@ LICENSE
The MIT License The MIT License
Copyright (c) 2008-2014 Jon Yurek and thoughtbot, inc. Copyright (c) 2008-2015 Jon Yurek and thoughtbot, inc.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
...@@ -12,7 +12,7 @@ New in 4.2.1: ...@@ -12,7 +12,7 @@ New in 4.2.1:
* Improvement: Better escaping for characters in URLs * Improvement: Better escaping for characters in URLs
* Improvement: Honor `fog_credentials[:scheme]` * Improvement: Honor `fog_credentials[:scheme]`
* Improvement: Also look for custom processors in lib/paperclip * Improvement: Also look for custom processors in lib/paperclip
* Improvement: id partitioning for string IDs works liks integer id * Improvement: id partitioning for string IDs works like integer id
* Improvement: Can pass options to DB adapters in migrations * Improvement: Can pass options to DB adapters in migrations
* Improvement: Update expiring_url creation for later versions of fog * Improvement: Update expiring_url creation for later versions of fog
* Improvement: `path` can be a Proc in S3 attachments * Improvement: `path` can be a Proc in S3 attachments
......
Releasing paperclip
1. Update `lib/paperclip/version.rb` file accordingly.
2. Update `NEWS` to reflect the changes since last release.
3. Commit changes. There shouldn’t be code changes, and thus CI doesn’t need to
run, you can then add “[ci skip]” to the commit message.
4. Tag the release: `git tag -m 'vVERSION' vVERSION`
5. Push changes: `git push --tags`
6. Build and publish the gem:
```bash
gem build paperclip.gemspec
gem push paperclip-VERSION.gem
```
7. Announce the new release, making sure to say “thank you” to the contributors
who helped shape this version.
Running Tests
=============
Please see `CONTRIBUTING.md` in "Running Tests" section for more information.
...@@ -11,7 +11,7 @@ task :all do |t| ...@@ -11,7 +11,7 @@ task :all do |t|
if ENV['BUNDLE_GEMFILE'] if ENV['BUNDLE_GEMFILE']
exec('rake spec cucumber') exec('rake spec cucumber')
else else
exec("rm gemfiles/*.lock") exec("rm -f gemfiles/*.lock")
Rake::Task["appraisal:gemfiles"].execute Rake::Task["appraisal:gemfiles"].execute
Rake::Task["appraisal:install"].execute Rake::Task["appraisal:install"].execute
exec('rake appraisal') exec('rake appraisal')
......
...@@ -12,17 +12,20 @@ Feature: Rails integration ...@@ -12,17 +12,20 @@ Feature: Rails integration
Scenario: Configure defaults for all attachments through Railtie Scenario: Configure defaults for all attachments through Railtie
Given I add this snippet to config/application.rb: Given I add this snippet to config/application.rb:
""" """
config.paperclip_defaults = {:url => "/paperclip/custom/:attachment/:style/:filename"} config.paperclip_defaults = {
:url => "/paperclip/custom/:attachment/:style/:filename",
:validate_media_type => false
}
""" """
And I attach :attachment And I attach :attachment
And I start the rails application And I start the rails application
When I go to the new user page When I go to the new user page
And I fill in "Name" with "something" And I fill in "Name" with "something"
And I attach the file "spec/support/fixtures/5k.png" to "Attachment" And I attach the file "spec/support/fixtures/animated.unknown" to "Attachment"
And I press "Submit" And I press "Submit"
Then I should see "Name: something" Then I should see "Name: something"
And I should see an image with a path of "/paperclip/custom/attachments/original/5k.png" And I should see an image with a path of "/paperclip/custom/attachments/original/animated.unknown"
And the file at "/paperclip/custom/attachments/original/5k.png" should be the same as "spec/support/fixtures/5k.png" And the file at "/paperclip/custom/attachments/original/animated.unknown" should be the same as "spec/support/fixtures/animated.unknown"
Scenario: Add custom processors Scenario: Add custom processors
Given I add a "test" processor in "lib/paperclip" Given I add a "test" processor in "lib/paperclip"
......
...@@ -49,7 +49,13 @@ end ...@@ -49,7 +49,13 @@ end
Then /^the attachment should have the same content type as the fixture "([^"]*)"$/ do |filename| Then /^the attachment should have the same content type as the fixture "([^"]*)"$/ do |filename|
in_current_dir do in_current_dir do
require 'mime/types' begin
# Use mime/types/columnar if available, for reduced memory usage
require "mime/types/columnar"
rescue LoadError
require "mime/types"
end
attachment_content_type = `bundle exec #{runner_command} "puts User.last.attachment_content_type"`.strip attachment_content_type = `bundle exec #{runner_command} "puts User.last.attachment_content_type"`.strip
attachment_content_type.should == MIME::Types.type_for(filename).first.content_type attachment_content_type.should == MIME::Types.type_for(filename).first.content_type
end end
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
source "https://rubygems.org" source "https://rubygems.org"
gem "sqlite3", "1.3.8", :platforms => :ruby gem "sqlite3", "~>1.3.8", :platforms => :ruby
gem "jruby-openssl", :platforms => :jruby gem "jruby-openssl", :platforms => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
gem "rubysl", :platforms => :rbx gem "rubysl", :platforms => :rbx
...@@ -14,6 +14,7 @@ gem "paperclip", :path => "../" ...@@ -14,6 +14,7 @@ gem "paperclip", :path => "../"
group :development, :test do group :development, :test do
gem "mime-types", "~> 1.16" gem "mime-types", "~> 1.16"
gem "builder" gem "builder"
gem "rubocop", :require => false
end end
gemspec :path => "../" gemspec :path => "../"
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
source "https://rubygems.org" source "https://rubygems.org"
gem "sqlite3", "1.3.8", :platforms => :ruby gem "sqlite3", "~>1.3.8", :platforms => :ruby
gem "jruby-openssl", :platforms => :jruby gem "jruby-openssl", :platforms => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
gem "rubysl", :platforms => :rbx gem "rubysl", :platforms => :rbx
...@@ -14,6 +14,7 @@ gem "paperclip", :path => "../" ...@@ -14,6 +14,7 @@ gem "paperclip", :path => "../"
group :development, :test do group :development, :test do
gem "mime-types", "~> 1.16" gem "mime-types", "~> 1.16"
gem "builder" gem "builder"
gem "rubocop", :require => false
end end
gemspec :path => "../" gemspec :path => "../"
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
source "https://rubygems.org" source "https://rubygems.org"
gem "sqlite3", "1.3.8", :platforms => :ruby gem "sqlite3", "~>1.3.8", :platforms => :ruby
gem "jruby-openssl", :platforms => :jruby gem "jruby-openssl", :platforms => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
gem "rubysl", :platforms => :rbx gem "rubysl", :platforms => :rbx
...@@ -14,6 +14,7 @@ gem "paperclip", :path => "../" ...@@ -14,6 +14,7 @@ gem "paperclip", :path => "../"
group :development, :test do group :development, :test do
gem "mime-types", "~> 1.16" gem "mime-types", "~> 1.16"
gem "builder" gem "builder"
gem "rubocop", :require => false
end end
gemspec :path => "../" gemspec :path => "../"
...@@ -2,18 +2,19 @@ ...@@ -2,18 +2,19 @@
source "https://rubygems.org" source "https://rubygems.org"
gem "sqlite3", "1.3.8", :platforms => :ruby gem "sqlite3", "~>1.3.8", :platforms => :ruby
gem "jruby-openssl", :platforms => :jruby gem "jruby-openssl", :platforms => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
gem "rubysl", :platforms => :rbx gem "rubysl", :platforms => :rbx
gem "racc", :platforms => :rbx gem "racc", :platforms => :rbx
gem "pry" gem "pry"
gem "rails", "~> 4.2.0.rc2" gem "rails", "~> 4.2.0"
gem "paperclip", :path => "../" gem "paperclip", :path => "../"
group :development, :test do group :development, :test do
gem "mime-types", "~> 1.16" gem "mime-types", "~> 1.16"
gem "builder" gem "builder"
gem "rubocop", :require => false
end end
gemspec :path => "../" gemspec :path => "../"
...@@ -55,7 +55,17 @@ require 'paperclip/helpers' ...@@ -55,7 +55,17 @@ require 'paperclip/helpers'
require 'paperclip/has_attached_file' require 'paperclip/has_attached_file'
require 'paperclip/attachment_registry' require 'paperclip/attachment_registry'
require 'paperclip/filename_cleaner' require 'paperclip/filename_cleaner'
require 'mime/types' require 'paperclip/rails_environment'
begin
# Use mime/types/columnar if available, for reduced memory usage
require "mime/types/columnar"
rescue LoadError
require "mime/types"
end
require 'mimemagic'
require 'mimemagic/overlay'
require 'logger' require 'logger'
require 'cocaine' require 'cocaine'
......
...@@ -137,6 +137,8 @@ module Paperclip ...@@ -137,6 +137,8 @@ module Paperclip
# +#for(style_name, options_hash)+ # +#for(style_name, options_hash)+
def url(style_name = default_style, options = {}) def url(style_name = default_style, options = {})
return nil if @instance.new_record?
if options == true || options == false # Backwards compatibility. if options == true || options == false # Backwards compatibility.
@url_generator.for(style_name, default_options.merge(:timestamp => options)) @url_generator.for(style_name, default_options.merge(:timestamp => options))
else else
...@@ -528,7 +530,7 @@ module Paperclip ...@@ -528,7 +530,7 @@ module Paperclip
@queued_for_write[name] = Paperclip.io_adapters.for(@queued_for_write[name]) @queued_for_write[name] = Paperclip.io_adapters.for(@queued_for_write[name])
unadapted_file.close if unadapted_file.respond_to?(:close) unadapted_file.close if unadapted_file.respond_to?(:close)
@queued_for_write[name] @queued_for_write[name]
rescue Paperclip::Error => e rescue Paperclip::Errors::NotIdentifiedByImageMagickError => e
log("An error was received while processing: #{e.inspect}") log("An error was received while processing: #{e.inspect}")
(@errors[:processing] ||= []) << e.message if @options[:whiny] (@errors[:processing] ||= []) << e.message if @options[:whiny]
ensure ensure
......
...@@ -52,7 +52,7 @@ module Paperclip ...@@ -52,7 +52,7 @@ module Paperclip
def definitions_for(klass) def definitions_for(klass)
klass.ancestors.each_with_object({}) do |ancestor, inherited_definitions| klass.ancestors.each_with_object({}) do |ancestor, inherited_definitions|
inherited_definitions.merge! @attachments[ancestor] inherited_definitions.deep_merge! @attachments[ancestor]
end end
end end
end end
......
...@@ -2,7 +2,7 @@ module Paperclip ...@@ -2,7 +2,7 @@ module Paperclip
class ContentTypeDetector class ContentTypeDetector
# The content-type detection strategy is as follows: # The content-type detection strategy is as follows:
# #
# 1. Blank/Empty files: If there's no filename or the file is empty, # 1. Blank/Empty files: If there's no filepath or the file is empty,
# provide a sensible default (application/octet-stream or inode/x-empty) # provide a sensible default (application/octet-stream or inode/x-empty)
# #
# 2. Calculated match: Return the first result that is found by both the # 2. Calculated match: Return the first result that is found by both the
...@@ -20,8 +20,8 @@ module Paperclip ...@@ -20,8 +20,8 @@ module Paperclip
EMPTY_TYPE = "inode/x-empty" EMPTY_TYPE = "inode/x-empty"
SENSIBLE_DEFAULT = "application/octet-stream" SENSIBLE_DEFAULT = "application/octet-stream"
def initialize(filename) def initialize(filepath)
@filename = filename @filepath = filepath
end end
# Returns a String describing the file's content type # Returns a String describing the file's content type
...@@ -33,32 +33,47 @@ module Paperclip ...@@ -33,32 +33,47 @@ module Paperclip
elsif calculated_type_matches.any? elsif calculated_type_matches.any?
calculated_type_matches.first calculated_type_matches.first
else else
type_from_file_command || SENSIBLE_DEFAULT type_from_file_contents || SENSIBLE_DEFAULT
end.to_s end.to_s
end end
private private
def blank_name?
@filepath.nil? || @filepath.empty?
end
def empty_file? def empty_file?
File.exist?(@filename) && File.size(@filename) == 0 File.exist?(@filepath) && File.size(@filepath) == 0
end end
alias :empty? :empty_file? alias :empty? :empty_file?
def blank_name? def calculated_type_matches
@filename.nil? || @filename.empty? possible_types.select do |content_type|
content_type == type_from_file_contents
end
end end
def possible_types def possible_types
MIME::Types.type_for(@filename).collect(&:content_type) MIME::Types.type_for(@filepath).collect(&:content_type)
end end
def calculated_type_matches def type_from_file_contents
possible_types.select{|content_type| content_type == type_from_file_command } type_from_mime_magic || type_from_file_command
rescue Errno::ENOENT => e
Paperclip.log("Error while determining content type: #{e}")
SENSIBLE_DEFAULT
end
def type_from_mime_magic
@type_from_mime_magic ||=
MimeMagic.by_magic(File.open(@filepath)).try(:type)
end end
def type_from_file_command def type_from_file_command
@type_from_file_command ||= FileCommandContentTypeDetector.new(@filename).detect @type_from_file_command ||=
FileCommandContentTypeDetector.new(@filepath).detect
end end
end end
end end
...@@ -13,9 +13,9 @@ module Paperclip ...@@ -13,9 +13,9 @@ module Paperclip
private private
def type_from_file_command def type_from_file_command
type = begin
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist. # On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
Paperclip.run("file", "-b --mime :file", :file => @filename) type = begin
Paperclip.run("file", "-b --mime :file", file: @filename)
rescue Cocaine::CommandLineError => e rescue Cocaine::CommandLineError => e
Paperclip.log("Error while determining content type: #{e}") Paperclip.log("Error while determining content type: #{e}")
SENSIBLE_DEFAULT SENSIBLE_DEFAULT
...@@ -26,7 +26,5 @@ module Paperclip ...@@ -26,7 +26,5 @@ module Paperclip
end end
type.split(/[:;\s]+/)[0] type.split(/[:;\s]+/)[0]
end end
end end
end end
...@@ -8,7 +8,7 @@ module Paperclip ...@@ -8,7 +8,7 @@ module Paperclip
base.extend ClassMethods base.extend ClassMethods
base.send :include, Callbacks base.send :include, Callbacks
base.send :include, Validators base.send :include, Validators
base.send :include, Schema if defined? ActiveRecord base.send :include, Schema
locale_path = Dir.glob(File.dirname(__FILE__) + "/locales/*.{rb,yml}") locale_path = Dir.glob(File.dirname(__FILE__) + "/locales/*.{rb,yml}")
I18n.load_path += locale_path unless I18n.load_path.include?(locale_path) I18n.load_path += locale_path unless I18n.load_path.include?(locale_path)
......
...@@ -79,7 +79,8 @@ module Paperclip ...@@ -79,7 +79,8 @@ module Paperclip
end end
def add_required_validations def add_required_validations
if @options[:validate_media_type] != false options = Paperclip::Attachment.default_options.deep_merge(@options)
if options[:validate_media_type] != false
name = @name name = @name
@klass.validates_media_type_spoof_detection name, @klass.validates_media_type_spoof_detection name,
:if => ->(instance){ instance.send(name).dirty? } :if => ->(instance){ instance.send(name).dirty? }
......
...@@ -172,7 +172,7 @@ module Paperclip ...@@ -172,7 +172,7 @@ module Paperclip
when Integer when Integer
("%09d" % id).scan(/\d{3}/).join("/") ("%09d" % id).scan(/\d{3}/).join("/")
when String when String
('%9.9s' % id).tr(" ", "0").scan(/.{3}/).join("/") id.scan(/.{3}/).first(3).join("/")
else else
nil nil
end end
......
...@@ -6,6 +6,7 @@ module Paperclip ...@@ -6,6 +6,7 @@ module Paperclip
attr_reader :content_type, :original_filename, :size attr_reader :content_type, :original_filename, :size
delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink, :to => :@tempfile delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink, :to => :@tempfile
alias :length :size
def fingerprint def fingerprint
@fingerprint ||= Digest::MD5.file(path).to_s @fingerprint ||= Digest::MD5.file(path).to_s
......
...@@ -42,7 +42,7 @@ module Paperclip ...@@ -42,7 +42,7 @@ module Paperclip
end end
def mapping_override_mismatch? def mapping_override_mismatch?
mapped_content_type != calculated_content_type !Array(mapped_content_type).include?(calculated_content_type)
end end
......
module Paperclip
class RailsEnvironment
def self.get
new.get
end
def get
if rails_exists? && rails_environment_exists?
Rails.env
else
nil
end
end
private
def rails_exists?
Object.const_defined?("Rails")
end
def rails_environment_exists?
Rails.respond_to?(:env)
end
end
end
...@@ -141,8 +141,9 @@ module Paperclip ...@@ -141,8 +141,9 @@ module Paperclip
def expiring_url(time = (Time.now + 3600), style_name = default_style) def expiring_url(time = (Time.now + 3600), style_name = default_style)
time = convert_time(time) time = convert_time(time)
if path(style_name) && directory.files.respond_to?(:get_http_url) http_url_method = "get_#{scheme}_url"
expiring_url = directory.files.get_http_url(path(style_name), time) if path(style_name) && directory.files.respond_to?(http_url_method)
expiring_url = directory.files.public_send(http_url_method, path(style_name), time)
if @options[:fog_host] if @options[:fog_host]
expiring_url.gsub!(/#{host_name_for_directory}/, dynamic_fog_host_for_style(style_name)) expiring_url.gsub!(/#{host_name_for_directory}/, dynamic_fog_host_for_style(style_name))
...@@ -156,8 +157,7 @@ module Paperclip ...@@ -156,8 +157,7 @@ module Paperclip
def parse_credentials(creds) def parse_credentials(creds)
creds = find_credentials(creds).stringify_keys creds = find_credentials(creds).stringify_keys
env = Object.const_defined?(:Rails) ? Rails.env : nil (creds[RailsEnvironment.get] || creds).symbolize_keys
(creds[env] || creds).symbolize_keys
end end
def copy_to_local_file(style, local_dest_path) def copy_to_local_file(style, local_dest_path)
......
...@@ -4,7 +4,7 @@ module Paperclip ...@@ -4,7 +4,7 @@ module Paperclip
# distribution. You can find out more about it at http://aws.amazon.com/s3 # distribution. You can find out more about it at http://aws.amazon.com/s3
# #
# To use Paperclip with S3, include the +aws-sdk+ gem in your Gemfile: # To use Paperclip with S3, include the +aws-sdk+ gem in your Gemfile:
# gem 'aws-sdk' # gem 'aws-sdk', '~> 1.6'
# There are a few S3-specific options for has_attached_file: # There are a few S3-specific options for has_attached_file:
# * +s3_credentials+: Takes a path, a File, a Hash or a Proc. The path (or File) must point # * +s3_credentials+: Takes a path, a File, a Hash or a Proc. The path (or File) must point
# to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon # to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon
...@@ -288,8 +288,7 @@ module Paperclip ...@@ -288,8 +288,7 @@ module Paperclip
def parse_credentials creds def parse_credentials creds
creds = creds.respond_to?('call') ? creds.call(self) : creds creds = creds.respond_to?('call') ? creds.call(self) : creds
creds = find_credentials(creds).stringify_keys creds = find_credentials(creds).stringify_keys
env = Object.const_defined?(:Rails) ? Rails.env : nil (creds[RailsEnvironment.get] || creds).symbolize_keys
(creds[env] || creds).symbolize_keys
end end
def exists?(style = default_style) def exists?(style = default_style)
......
...@@ -29,7 +29,6 @@ module Paperclip ...@@ -29,7 +29,6 @@ module Paperclip
super super
geometry = options[:geometry].to_s geometry = options[:geometry].to_s
@file = file
@crop = geometry[-1,1] == '#' @crop = geometry[-1,1] == '#'
@target_geometry = options.fetch(:string_geometry_parser, Geometry).parse(geometry) @target_geometry = options.fetch(:string_geometry_parser, Geometry).parse(geometry)
@current_geometry = options.fetch(:file_geometry_parser, Geometry).from_file(@file) @current_geometry = options.fetch(:file_geometry_parser, Geometry).from_file(@file)
...@@ -64,8 +63,8 @@ module Paperclip ...@@ -64,8 +63,8 @@ module Paperclip
# that contains the new image. # that contains the new image.
def make def make
src = @file src = @file
dst = Tempfile.new([@basename, @format ? ".#{@format}" : '']) filename = [@basename, @format ? ".#{@format}" : ""].join
dst.binmode dst = TempfileFactory.new.generate(filename)
begin begin
parameters = [] parameters = []
......
...@@ -108,4 +108,20 @@ namespace :paperclip do ...@@ -108,4 +108,20 @@ namespace :paperclip do
end end
end end
end end
desc "find missing attachments. Useful to know which attachments are broken"
task :find_broken_attachments => :environment do
klass = Paperclip::Task.obtain_class
names = Paperclip::Task.obtain_attachments(klass)
names.each do |name|
Paperclip.each_instance_with_attachment(klass, name) do |instance|
attachment = instance.send(name)
if attachment.exists?
print "."
else
Paperclip::Task.log_error("#{instance.class}##{attachment.name}, #{instance.id}, #{attachment.url}")
end
end
end
end
end end
...@@ -12,8 +12,6 @@ Gem::Specification.new do |s| ...@@ -12,8 +12,6 @@ Gem::Specification.new do |s|
s.description = "Easy upload management for ActiveRecord" s.description = "Easy upload management for ActiveRecord"
s.license = "MIT" s.license = "MIT"
s.rubyforge_project = "paperclip"
s.files = `git ls-files`.split("\n") s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {spec,features}/*`.split("\n") s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
...@@ -24,21 +22,22 @@ Gem::Specification.new do |s| ...@@ -24,21 +22,22 @@ Gem::Specification.new do |s|
s.add_dependency('activemodel', '>= 3.0.0') s.add_dependency('activemodel', '>= 3.0.0')
s.add_dependency('activesupport', '>= 3.0.0') s.add_dependency('activesupport', '>= 3.0.0')
s.add_dependency('cocaine', '~> 0.5.3') s.add_dependency('cocaine', '~> 0.5.5')
s.add_dependency('mime-types') s.add_dependency('mime-types')
s.add_dependency('mimemagic', '0.3.0')
s.add_development_dependency('activerecord', '>= 3.0.0') s.add_development_dependency('activerecord', '>= 3.0.0')
s.add_development_dependency('shoulda') s.add_development_dependency('shoulda')
s.add_development_dependency('rspec') s.add_development_dependency('rspec')
s.add_development_dependency('appraisal') s.add_development_dependency('appraisal')
s.add_development_dependency('mocha') s.add_development_dependency('mocha')
s.add_development_dependency('aws-sdk', '>= 1.5.7') s.add_development_dependency('aws-sdk', '~> 1.6')
s.add_development_dependency('bourne') s.add_development_dependency('bourne')
s.add_development_dependency('cucumber', '~> 1.3.11') s.add_development_dependency('cucumber', '~> 1.3.18')
s.add_development_dependency('aruba') s.add_development_dependency('aruba')
s.add_development_dependency('nokogiri') s.add_development_dependency('nokogiri')
# Ruby version < 1.9.3 can't install capybara > 2.0.3. # Ruby version < 1.9.3 can't install capybara > 2.0.3.
s.add_development_dependency('capybara', '= 2.0.3') s.add_development_dependency('capybara')
s.add_development_dependency('bundler') s.add_development_dependency('bundler')
s.add_development_dependency('fog', '~> 1.0') s.add_development_dependency('fog', '~> 1.0')
s.add_development_dependency('launchy') s.add_development_dependency('launchy')
......
...@@ -8,6 +8,6 @@ describe "Attachment Definitions" do ...@@ -8,6 +8,6 @@ describe "Attachment Definitions" do
Dummy.do_not_validate_attachment_file_type :avatar Dummy.do_not_validate_attachment_file_type :avatar
expected = {avatar: {path: "abc"}, other_attachment: {url: "123"}} expected = {avatar: {path: "abc"}, other_attachment: {url: "123"}}
assert_equal expected, Dummy.attachment_definitions expect(Dummy.attachment_definitions).to eq expected
end end
end end
...@@ -31,8 +31,8 @@ describe 'Attachment Registry' do ...@@ -31,8 +31,8 @@ describe 'Attachment Registry' do
it 'calls the block with the class, attachment name, and options' do it 'calls the block with the class, attachment name, and options' do
foo = Class.new foo = Class.new
expected_accumulations = [ expected_accumulations = [
[foo, :avatar, { yo: 'greeting' }], [foo, :avatar, { yo: "greeting" }],
[foo, :greeter, { ciao: 'greeting' }] [foo, :greeter, { ciao: "greeting" }]
] ]
expected_accumulations.each do |args| expected_accumulations.each do |args|
Paperclip::AttachmentRegistry.register(*args) Paperclip::AttachmentRegistry.register(*args)
...@@ -50,25 +50,64 @@ describe 'Attachment Registry' do ...@@ -50,25 +50,64 @@ describe 'Attachment Registry' do
context '.definitions_for' do context '.definitions_for' do
it 'produces the attachment name and options' do it 'produces the attachment name and options' do
expected_definitions = { expected_definitions = {
avatar: { yo: 'greeting' }, avatar: { yo: "greeting" },
greeter: { ciao: 'greeting' } greeter: { ciao: "greeting" }
} }
foo = Class.new foo = Class.new
Paperclip::AttachmentRegistry.register(foo, :avatar, { yo: 'greeting' }) Paperclip::AttachmentRegistry.register(
Paperclip::AttachmentRegistry.register(foo, :greeter, { ciao: 'greeting' }) foo,
:avatar,
yo: "greeting"
)
Paperclip::AttachmentRegistry.register(
foo,
:greeter,
ciao: "greeting"
)
definitions = Paperclip::AttachmentRegistry.definitions_for(foo) definitions = Paperclip::AttachmentRegistry.definitions_for(foo)
assert_equal expected_definitions, definitions assert_equal expected_definitions, definitions
end end
it "produces defintions for subclasses" do it 'produces defintions for subclasses' do
expected_definitions = { avatar: { yo: 'greeting' } } expected_definitions = { avatar: { yo: "greeting" } }
Foo = Class.new foo = Class.new
Bar = Class.new(Foo) bar = Class.new(foo)
Paperclip::AttachmentRegistry.register(Foo, :avatar, expected_definitions[:avatar]) Paperclip::AttachmentRegistry.register(
foo,
:avatar,
expected_definitions[:avatar]
)
definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
assert_equal expected_definitions, definitions
end
definitions = Paperclip::AttachmentRegistry.definitions_for(Bar) it 'produces defintions for subclasses but deep merging them' do
foo_definitions = { avatar: { yo: "greeting" } }
bar_definitions = { avatar: { ciao: "greeting" } }
expected_definitions = {
avatar: {
yo: "greeting",
ciao: "greeting"
}
}
foo = Class.new
bar = Class.new(foo)
Paperclip::AttachmentRegistry.register(
foo,
:avatar,
foo_definitions[:avatar]
)
Paperclip::AttachmentRegistry.register(
bar,
:avatar,
bar_definitions[:avatar]
)
definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
assert_equal expected_definitions, definitions assert_equal expected_definitions, definitions
end end
...@@ -77,7 +116,11 @@ describe 'Attachment Registry' do ...@@ -77,7 +116,11 @@ describe 'Attachment Registry' do
context '.clear' do context '.clear' do
it 'removes all of the existing attachment definitions' do it 'removes all of the existing attachment definitions' do
foo = Class.new foo = Class.new
Paperclip::AttachmentRegistry.register(foo, :greeter, { ciao: 'greeting' }) Paperclip::AttachmentRegistry.register(
foo,
:greeter,
ciao: "greeting"
)
Paperclip::AttachmentRegistry.clear Paperclip::AttachmentRegistry.clear
......
...@@ -34,9 +34,9 @@ describe Paperclip::Attachment do ...@@ -34,9 +34,9 @@ describe Paperclip::Attachment do
it "does not delete styles that don't get reprocessed" do it "does not delete styles that don't get reprocessed" do
file = File.new(fixture_file("50x50.png"), 'rb') file = File.new(fixture_file("50x50.png"), 'rb')
rebuild_class styles: { rebuild_class styles: {
small: '100x>', small: "100x>",
large: '500x>', large: "500x>",
original: '42x42#' original: "42x42#"
} }
dummy = Dummy.new dummy = Dummy.new
...@@ -75,7 +75,11 @@ describe Paperclip::Attachment do ...@@ -75,7 +75,11 @@ describe Paperclip::Attachment do
it "handles a boolean second argument to #url" do it "handles a boolean second argument to #url" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, :instance, url_generator: mock_url_generator_builder) attachment = Paperclip::Attachment.new(
:name,
FakeModel.new,
url_generator: mock_url_generator_builder
)
attachment.url(:style_name, true) attachment.url(:style_name, true)
expect(mock_url_generator_builder.has_generated_url_with_options?(timestamp: true, escape: true)).to eq true expect(mock_url_generator_builder.has_generated_url_with_options?(timestamp: true, escape: true)).to eq true
...@@ -86,7 +90,11 @@ describe Paperclip::Attachment do ...@@ -86,7 +90,11 @@ describe Paperclip::Attachment do
it "passes the style and options through to the URL generator on #url" do it "passes the style and options through to the URL generator on #url" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, :instance, url_generator: mock_url_generator_builder) attachment = Paperclip::Attachment.new(
:name,
FakeModel.new,
url_generator: mock_url_generator_builder
)
attachment.url(:style_name, options: :values) attachment.url(:style_name, options: :values)
expect(mock_url_generator_builder.has_generated_url_with_options?(options: :values)).to eq true expect(mock_url_generator_builder.has_generated_url_with_options?(options: :values)).to eq true
...@@ -95,7 +103,7 @@ describe Paperclip::Attachment do ...@@ -95,7 +103,7 @@ describe Paperclip::Attachment do
it "passes default options through when #url is given one argument" do it "passes default options through when #url is given one argument" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, attachment = Paperclip::Attachment.new(:name,
:instance, FakeModel.new,
url_generator: mock_url_generator_builder, url_generator: mock_url_generator_builder,
use_timestamp: true) use_timestamp: true)
...@@ -106,7 +114,7 @@ describe Paperclip::Attachment do ...@@ -106,7 +114,7 @@ describe Paperclip::Attachment do
it "passes default style and options through when #url is given no arguments" do it "passes default style and options through when #url is given no arguments" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, attachment = Paperclip::Attachment.new(:name,
:instance, FakeModel.new,
default_style: 'default style', default_style: 'default style',
url_generator: mock_url_generator_builder, url_generator: mock_url_generator_builder,
use_timestamp: true) use_timestamp: true)
...@@ -119,7 +127,7 @@ describe Paperclip::Attachment do ...@@ -119,7 +127,7 @@ describe Paperclip::Attachment do
it "passes the option timestamp: true if :use_timestamp is true and :timestamp is not passed" do it "passes the option timestamp: true if :use_timestamp is true and :timestamp is not passed" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, attachment = Paperclip::Attachment.new(:name,
:instance, FakeModel.new,
url_generator: mock_url_generator_builder, url_generator: mock_url_generator_builder,
use_timestamp: true) use_timestamp: true)
...@@ -130,7 +138,7 @@ describe Paperclip::Attachment do ...@@ -130,7 +138,7 @@ describe Paperclip::Attachment do
it "passes the option timestamp: false if :use_timestamp is false and :timestamp is not passed" do it "passes the option timestamp: false if :use_timestamp is false and :timestamp is not passed" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, attachment = Paperclip::Attachment.new(:name,
:instance, FakeModel.new,
url_generator: mock_url_generator_builder, url_generator: mock_url_generator_builder,
use_timestamp: false) use_timestamp: false)
...@@ -141,7 +149,7 @@ describe Paperclip::Attachment do ...@@ -141,7 +149,7 @@ describe Paperclip::Attachment do
it "does not change the :timestamp if :timestamp is passed" do it "does not change the :timestamp if :timestamp is passed" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, attachment = Paperclip::Attachment.new(:name,
:instance, FakeModel.new,
url_generator: mock_url_generator_builder, url_generator: mock_url_generator_builder,
use_timestamp: false) use_timestamp: false)
...@@ -152,7 +160,7 @@ describe Paperclip::Attachment do ...@@ -152,7 +160,7 @@ describe Paperclip::Attachment do
it "renders JSON as default style" do it "renders JSON as default style" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, attachment = Paperclip::Attachment.new(:name,
:instance, FakeModel.new,
default_style: 'default style', default_style: 'default style',
url_generator: mock_url_generator_builder) url_generator: mock_url_generator_builder)
...@@ -163,7 +171,7 @@ describe Paperclip::Attachment do ...@@ -163,7 +171,7 @@ describe Paperclip::Attachment do
it "passes the option escape: true if :escape_url is true and :escape is not passed" do it "passes the option escape: true if :escape_url is true and :escape is not passed" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, attachment = Paperclip::Attachment.new(:name,
:instance, FakeModel.new,
url_generator: mock_url_generator_builder, url_generator: mock_url_generator_builder,
escape_url: true) escape_url: true)
...@@ -174,7 +182,7 @@ describe Paperclip::Attachment do ...@@ -174,7 +182,7 @@ describe Paperclip::Attachment do
it "passes the option escape: false if :escape_url is false and :escape is not passed" do it "passes the option escape: false if :escape_url is false and :escape is not passed" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name, attachment = Paperclip::Attachment.new(:name,
:instance, FakeModel.new,
url_generator: mock_url_generator_builder, url_generator: mock_url_generator_builder,
escape_url: false) escape_url: false)
...@@ -212,6 +220,7 @@ describe Paperclip::Attachment do ...@@ -212,6 +220,7 @@ describe Paperclip::Attachment do
dummy = Dummy.new dummy = Dummy.new
dummy.id = 1234 dummy.id = 1234
dummy.avatar_file_name = "fake.jpg" dummy.avatar_file_name = "fake.jpg"
dummy.stubs(:new_record?).returns(false)
expected_string = '{"avatar":"/system/dummies/avatars/000/001/234/original/fake.jpg"}' expected_string = '{"avatar":"/system/dummies/avatars/000/001/234/original/fake.jpg"}'
if ActiveRecord::Base.include_root_in_json # This is true by default in Rails 3, and false in 4 if ActiveRecord::Base.include_root_in_json # This is true by default in Rails 3, and false in 4
expected_string = %({"dummy":#{expected_string}}) expected_string = %({"dummy":#{expected_string}})
...@@ -251,6 +260,10 @@ describe Paperclip::Attachment do ...@@ -251,6 +260,10 @@ describe Paperclip::Attachment do
it "returns false when asked exists?" do it "returns false when asked exists?" do
assert !@dummy.avatar.exists? assert !@dummy.avatar.exists?
end end
it "#url returns nil" do
assert_nil @dummy.avatar.url
end
end end
context "on an Attachment" do context "on an Attachment" do
...@@ -635,15 +648,40 @@ describe Paperclip::Attachment do ...@@ -635,15 +648,40 @@ describe Paperclip::Attachment do
before do before do
rebuild_model processor: [:thumbnail], styles: { small: '' }, whiny_thumbnails: true rebuild_model processor: [:thumbnail], styles: { small: '' }, whiny_thumbnails: true
@dummy = Dummy.new @dummy = Dummy.new
Paperclip::Thumbnail.expects(:make).raises(Paperclip::Error, "cannot be processed.")
@file = StringIO.new("...") @file = StringIO.new("...")
@file.stubs(:to_tempfile).returns(@file) @file.stubs(:to_tempfile).returns(@file)
@dummy.avatar = @file end
context "when error is meaningful for the end user" do
before do
Paperclip::Thumbnail.expects(:make).raises(
Paperclip::Errors::NotIdentifiedByImageMagickError,
"cannot be processed."
)
end end
it "correctly forwards processing error message to the instance" do it "correctly forwards processing error message to the instance" do
@dummy.avatar = @file
@dummy.valid? @dummy.valid?
assert_contains @dummy.errors.full_messages, "Avatar cannot be processed." assert_contains(
@dummy.errors.full_messages,
"Avatar cannot be processed."
)
end
end
context "when error is intended for the developer" do
before do
Paperclip::Thumbnail.expects(:make).raises(
Paperclip::Errors::CommandNotFoundError
)
end
it "propagates the error" do
assert_raises(Paperclip::Errors::CommandNotFoundError) do
@dummy.avatar = @file
end
end
end end
end end
......
require 'spec_helper' require 'spec_helper'
describe Paperclip::ContentTypeDetector do describe Paperclip::ContentTypeDetector do
it 'returns a meaningful content type for open xml spreadsheets' do
file = File.new(fixture_file("empty.xlsx"))
assert_equal "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
Paperclip::ContentTypeDetector.new(file.path).detect
end
it 'gives a sensible default when the name is empty' do it 'gives a sensible default when the name is empty' do
assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new("").detect assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new("").detect
end end
...@@ -13,7 +19,8 @@ describe Paperclip::ContentTypeDetector do ...@@ -13,7 +19,8 @@ describe Paperclip::ContentTypeDetector do
it 'returns content type of file if it is an acceptable type' do it 'returns content type of file if it is an acceptable type' do
MIME::Types.stubs(:type_for).returns([MIME::Type.new('application/mp4'), MIME::Type.new('video/mp4'), MIME::Type.new('audio/mp4')]) MIME::Types.stubs(:type_for).returns([MIME::Type.new('application/mp4'), MIME::Type.new('video/mp4'), MIME::Type.new('audio/mp4')])
Paperclip.stubs(:run).returns("video/mp4") Paperclip::ContentTypeDetector.any_instance
.stubs(:type_from_file_contents).returns("video/mp4")
@filename = "my_file.mp4" @filename = "my_file.mp4"
assert_equal "video/mp4", Paperclip::ContentTypeDetector.new(@filename).detect assert_equal "video/mp4", Paperclip::ContentTypeDetector.new(@filename).detect
end end
......
...@@ -24,4 +24,3 @@ describe Paperclip::FileCommandContentTypeDetector do ...@@ -24,4 +24,3 @@ describe Paperclip::FileCommandContentTypeDetector do
Paperclip::FileCommandContentTypeDetector.new("windows").detect Paperclip::FileCommandContentTypeDetector.new("windows").detect
end end
end end
...@@ -138,14 +138,7 @@ describe Paperclip::Interpolations do ...@@ -138,14 +138,7 @@ describe Paperclip::Interpolations do
assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style) assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style)
end end
it "returns the partitioned id of the attachment when the id is a short string" do it "returns the partitioned id of the attachment when the id is a string" do
attachment = mock
attachment.expects(:id).returns("fnj23")
attachment.expects(:instance).returns(attachment)
assert_equal "000/0fn/j23", Paperclip::Interpolations.id_partition(attachment, :style)
end
it "returns the partitioned id of the attachment when the id is a long string" do
attachment = mock attachment = mock
attachment.expects(:id).returns("32fnj23oio2f") attachment.expects(:id).returns("32fnj23oio2f")
attachment.expects(:instance).returns(attachment) attachment.expects(:instance).returns(attachment)
......
...@@ -9,11 +9,12 @@ describe Paperclip::AbstractAdapter do ...@@ -9,11 +9,12 @@ describe Paperclip::AbstractAdapter do
end end
end end
context "content type from file command" do context "content type from file contents" do
before do before do
@adapter = TestAdapter.new @adapter = TestAdapter.new
@adapter.stubs(:path).returns("image.png") @adapter.stubs(:path).returns("image.png")
Paperclip.stubs(:run).returns("image/png\n") Paperclip.stubs(:run).returns("image/png\n")
Paperclip::ContentTypeDetector.any_instance.stubs(:type_from_mime_magic).returns("image/png")
end end
it "returns the content type without newline" do it "returns the content type without newline" do
......
...@@ -73,10 +73,13 @@ describe Paperclip::FileAdapter do ...@@ -73,10 +73,13 @@ describe Paperclip::FileAdapter do
end end
end end
context "file with content type derived from file command on *nix" do context "file with content type derived from file contents on *nix" do
before do before do
MIME::Types.stubs(:type_for).returns([]) MIME::Types.stubs(:type_for).returns([])
Paperclip.stubs(:run).returns("application/vnd.ms-office\n") Paperclip.stubs(:run).returns("application/vnd.ms-office\n")
Paperclip::ContentTypeDetector.any_instance
.stubs(:type_from_mime_magic).returns("application/vnd.ms-office")
@subject = Paperclip.io_adapters.for(@file) @subject = Paperclip.io_adapters.for(@file)
end end
......
...@@ -20,6 +20,10 @@ describe Paperclip::StringioAdapter do ...@@ -20,6 +20,10 @@ describe Paperclip::StringioAdapter do
assert_equal 6, @subject.size assert_equal 6, @subject.size
end end
it "returns the length of the data" do
assert_equal 6, @subject.length
end
it "generates an MD5 hash of the contents" do it "generates an MD5 hash of the contents" do
assert_equal Digest::MD5.hexdigest(@contents), @subject.fingerprint assert_equal Digest::MD5.hexdigest(@contents), @subject.fingerprint
end end
......
...@@ -53,4 +53,18 @@ describe Paperclip::MediaTypeSpoofDetector do ...@@ -53,4 +53,18 @@ describe Paperclip::MediaTypeSpoofDetector do
file = File.open(fixture_file("empty.html")) file = File.open(fixture_file("empty.html"))
assert ! Paperclip::MediaTypeSpoofDetector.using(file, "empty.html", "").spoofed? assert ! Paperclip::MediaTypeSpoofDetector.using(file, "empty.html", "").spoofed?
end end
it 'does allow array as :content_type_mappings' do
begin
Paperclip.options[:content_type_mappings] = {
html: ['binary', 'text/html']
}
file = File.open(fixture_file('empty.html'))
spoofed = Paperclip::MediaTypeSpoofDetector
.using(file, 'empty.html').spoofed?
assert !spoofed
ensure
Paperclip.options[:content_type_mappings] = {}
end
end
end end
...@@ -20,7 +20,7 @@ describe Paperclip do ...@@ -20,7 +20,7 @@ describe Paperclip do
it "saves Cocaine::CommandLine.path that set before" do it "saves Cocaine::CommandLine.path that set before" do
Cocaine::CommandLine.path = "/opt/my_app/bin" Cocaine::CommandLine.path = "/opt/my_app/bin"
Paperclip.run("convert", "stuff") Paperclip.run("convert", "stuff")
assert_equal [Cocaine::CommandLine.path].flatten.include?("/opt/my_app/bin"), true assert_equal Cocaine::CommandLine.path.include?("/opt/my_app/bin"), true
end end
it "does not duplicate Cocaine::CommandLine.path on multiple runs" do it "does not duplicate Cocaine::CommandLine.path on multiple runs" do
......
require 'spec_helper'
describe Paperclip::RailsEnvironment do
it "returns nil when Rails isn't defined" do
resetting_rails_to(nil) do
expect(Paperclip::RailsEnvironment.get).to be_nil
end
end
it "returns nil when Rails.env isn't defined" do
resetting_rails_to({}) do
expect(Paperclip::RailsEnvironment.get).to be_nil
end
end
it "returns the value of Rails.env if it is set" do
resetting_rails_to(OpenStruct.new(env: "foo")) do
expect(Paperclip::RailsEnvironment.get).to eq "foo"
end
end
def resetting_rails_to(new_value)
begin
previous_rails = Object.send(:remove_const, "Rails")
Object.const_set("Rails", new_value) unless new_value.nil?
yield
ensure
Object.send(:remove_const, "Rails") if Object.const_defined?("Rails")
Object.const_set("Rails", previous_rails)
end
end
end
...@@ -320,6 +320,9 @@ describe Paperclip::Storage::Fog do ...@@ -320,6 +320,9 @@ describe Paperclip::Storage::Fog do
it "honors the scheme in public url" do it "honors the scheme in public url" do
assert_match(/^http:\/\//, @dummy.avatar.url) assert_match(/^http:\/\//, @dummy.avatar.url)
end end
it "honors the scheme in expiring url" do
assert_match(/^http:\/\//, @dummy.avatar.expiring_url)
end
end end
context "with scheme not set" do context "with scheme not set" do
...@@ -334,15 +337,20 @@ describe Paperclip::Storage::Fog do ...@@ -334,15 +337,20 @@ describe Paperclip::Storage::Fog do
it "provides HTTPS public url" do it "provides HTTPS public url" do
assert_match(/^https:\/\//, @dummy.avatar.url) assert_match(/^https:\/\//, @dummy.avatar.url)
end end
it "provides HTTPS expiring url" do
assert_match(/^https:\/\//, @dummy.avatar.expiring_url)
end
end end
context "with a valid bucket name for a subdomain" do context "with a valid bucket name for a subdomain" do
before { @dummy.stubs(:new_record?).returns(false) }
it "provides an url in subdomain style" do it "provides an url in subdomain style" do
assert_match(/^https:\/\/papercliptests.s3.amazonaws.com\/avatars\/5k.png/, @dummy.avatar.url) assert_match(/^https:\/\/papercliptests.s3.amazonaws.com\/avatars\/5k.png/, @dummy.avatar.url)
end end
it "provides an url that expires in subdomain style" do it "provides an url that expires in subdomain style" do
assert_match(/^http:\/\/papercliptests.s3.amazonaws.com\/avatars\/5k.png.+Expires=.+$/, @dummy.avatar.expiring_url) assert_match(/^https:\/\/papercliptests.s3.amazonaws.com\/avatars\/5k.png.+Expires=.+$/, @dummy.avatar.expiring_url)
end end
end end
...@@ -390,7 +398,7 @@ describe Paperclip::Storage::Fog do ...@@ -390,7 +398,7 @@ describe Paperclip::Storage::Fog do
end end
it "provides a url that expires in folder style" do it "provides a url that expires in folder style" do
assert_match(/^http:\/\/s3.amazonaws.com\/this_is_invalid\/avatars\/5k.png.+Expires=.+$/, @dummy.avatar.expiring_url) assert_match(/^https:\/\/s3.amazonaws.com\/this_is_invalid\/avatars\/5k.png.+Expires=.+$/, @dummy.avatar.expiring_url)
end end
end end
...@@ -492,6 +500,7 @@ describe Paperclip::Storage::Fog do ...@@ -492,6 +500,7 @@ describe Paperclip::Storage::Fog do
@file = File.new(fixture_file('5k.png'), 'rb') @file = File.new(fixture_file('5k.png'), 'rb')
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = @file @dummy.avatar = @file
@dummy.stubs(:new_record?).returns(false)
end end
after do after do
......
...@@ -105,6 +105,7 @@ describe Paperclip::Storage::S3 do ...@@ -105,6 +105,7 @@ describe Paperclip::Storage::S3 do
url: ":s3_path_url" url: ":s3_path_url"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a url based on an S3 path" do it "returns a url based on an S3 path" do
...@@ -145,6 +146,7 @@ describe Paperclip::Storage::S3 do ...@@ -145,6 +146,7 @@ describe Paperclip::Storage::S3 do
path: ":attachment/:basename:dotextension" path: ":attachment/:basename:dotextension"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a url based on an S3 path" do it "returns a url based on an S3 path" do
...@@ -161,6 +163,7 @@ describe Paperclip::Storage::S3 do ...@@ -161,6 +163,7 @@ describe Paperclip::Storage::S3 do
path: ":attachment/:basename:dotextension" path: ":attachment/:basename:dotextension"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a protocol-relative URL" do it "returns a protocol-relative URL" do
...@@ -177,6 +180,7 @@ describe Paperclip::Storage::S3 do ...@@ -177,6 +180,7 @@ describe Paperclip::Storage::S3 do
path: ":attachment/:basename:dotextension" path: ":attachment/:basename:dotextension"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a url based on an S3 path" do it "returns a url based on an S3 path" do
...@@ -193,6 +197,7 @@ describe Paperclip::Storage::S3 do ...@@ -193,6 +197,7 @@ describe Paperclip::Storage::S3 do
path: ":attachment/:basename:dotextension" path: ":attachment/:basename:dotextension"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a url based on an S3 path" do it "returns a url based on an S3 path" do
...@@ -236,6 +241,7 @@ describe Paperclip::Storage::S3 do ...@@ -236,6 +241,7 @@ describe Paperclip::Storage::S3 do
s3_host_name: "s3-ap-northeast-1.amazonaws.com" s3_host_name: "s3-ap-northeast-1.amazonaws.com"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a url based on an :s3_host_name path" do it "returns a url based on an :s3_host_name path" do
...@@ -259,6 +265,7 @@ describe Paperclip::Storage::S3 do ...@@ -259,6 +265,7 @@ describe Paperclip::Storage::S3 do
attr_accessor :value attr_accessor :value
end end
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "uses s3_host_name as a proc if available" do it "uses s3_host_name as a proc if available" do
...@@ -281,6 +288,7 @@ describe Paperclip::Storage::S3 do ...@@ -281,6 +288,7 @@ describe Paperclip::Storage::S3 do
File.open(fixture_file('5k.png'), 'rb') do |file| File.open(fixture_file('5k.png'), 'rb') do |file|
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = file @dummy.avatar = file
@dummy.stubs(:new_record?).returns(false)
end end
end end
...@@ -342,17 +350,18 @@ describe Paperclip::Storage::S3 do ...@@ -342,17 +350,18 @@ describe Paperclip::Storage::S3 do
context "An attachment that uses S3 for storage and has spaces in file name" do context "An attachment that uses S3 for storage and has spaces in file name" do
before do before do
rebuild_model styles: { large: ['500x500#', :jpg] }, rebuild_model(
styles: { large: ["500x500#", :jpg] },
storage: :s3, storage: :s3,
bucket: "bucket", bucket: "bucket",
s3_credentials: { s3_credentials: { "access_key_id" => "12345",
'access_key_id' => "12345", "secret_access_key" => "54321" }
'secret_access_key' => "54321" )
}
File.open(fixture_file('spaced file.png'), 'rb') do |file| File.open(fixture_file("spaced file.png"), "rb") do |file|
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = file @dummy.avatar = file
@dummy.stubs(:new_record?).returns(false)
end end
end end
...@@ -385,6 +394,7 @@ describe Paperclip::Storage::S3 do ...@@ -385,6 +394,7 @@ describe Paperclip::Storage::S3 do
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = file @dummy.avatar = file
@dummy.save @dummy.save
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a replaced version for path" do it "returns a replaced version for path" do
...@@ -405,6 +415,7 @@ describe Paperclip::Storage::S3 do ...@@ -405,6 +415,7 @@ describe Paperclip::Storage::S3 do
url: ":s3_domain_url" url: ":s3_domain_url"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a url based on an S3 subdomain" do it "returns a url based on an S3 subdomain" do
...@@ -414,16 +425,20 @@ describe Paperclip::Storage::S3 do ...@@ -414,16 +425,20 @@ describe Paperclip::Storage::S3 do
context "" do context "" do
before do before do
rebuild_model storage: :s3, rebuild_model(
storage: :s3,
s3_credentials: { s3_credentials: {
production: { bucket: "prod_bucket" }, production: { bucket: "prod_bucket" },
development: { bucket: "dev_bucket" } development: { bucket: "dev_bucket" }
}, },
bucket: "bucket",
s3_host_alias: "something.something.com", s3_host_alias: "something.something.com",
path: ":attachment/:basename:dotextension", path: ":attachment/:basename:dotextension",
url: ":s3_alias_url" url: ":s3_alias_url"
)
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a url based on the host_alias" do it "returns a url based on the host_alias" do
...@@ -447,6 +462,7 @@ describe Paperclip::Storage::S3 do ...@@ -447,6 +462,7 @@ describe Paperclip::Storage::S3 do
end end
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a url based on the host_alias" do it "returns a url based on the host_alias" do
...@@ -469,6 +485,7 @@ describe Paperclip::Storage::S3 do ...@@ -469,6 +485,7 @@ describe Paperclip::Storage::S3 do
url: ":asset_host" url: ":asset_host"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = stringy_file @dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end end
it "returns a relative URL for Rails to calculate assets host" do it "returns a relative URL for Rails to calculate assets host" do
...@@ -684,6 +701,7 @@ describe Paperclip::Storage::S3 do ...@@ -684,6 +701,7 @@ describe Paperclip::Storage::S3 do
@file = File.new(fixture_file('5k.png'), 'rb') @file = File.new(fixture_file('5k.png'), 'rb')
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = @file @dummy.avatar = @file
@dummy.stubs(:new_record?).returns(false)
end end
after { @file.close } after { @file.close }
......
...@@ -26,4 +26,8 @@ describe Paperclip::TempfileFactory do ...@@ -26,4 +26,8 @@ describe Paperclip::TempfileFactory do
file = subject.generate file = subject.generate
assert File.exist?(file.path) assert File.exist?(file.path)
end end
it "does not throw Errno::ENAMETOOLONG when it has a really long name" do
expect { subject.generate("o" * 255) }.to_not raise_error
end
end end
...@@ -481,4 +481,20 @@ describe Paperclip::Thumbnail do ...@@ -481,4 +481,20 @@ describe Paperclip::Thumbnail do
end end
end end
end end
context "with a really long file name" do
before do
tempfile = Tempfile.new("f")
tempfile_additional_chars = tempfile.path.split("/")[-1].length + 15
image_file = File.new(fixture_file("5k.png"), "rb")
@file = Tempfile.new("f" * (255 - tempfile_additional_chars))
@file.write(image_file.read)
@file.rewind
end
it "does not throw Errno::ENAMETOOLONG" do
thumb = Paperclip::Thumbnail.new(@file, geometry: "50x50", format: :gif)
expect { thumb.make }.to_not raise_error
end
end
end end
...@@ -43,7 +43,7 @@ describe Paperclip::UrlGenerator do ...@@ -43,7 +43,7 @@ describe Paperclip::UrlGenerator do
end end
it "executes the method named by the symbol as the default URL when no file is assigned" do it "executes the method named by the symbol as the default URL when no file is assigned" do
mock_model = MockModel.new mock_model = FakeModel.new
mock_attachment = MockAttachment.new(model: mock_model) mock_attachment = MockAttachment.new(model: mock_model)
mock_interpolator = MockInterpolator.new mock_interpolator = MockInterpolator.new
default_url = :to_s default_url = :to_s
......
...@@ -18,4 +18,8 @@ class FakeModel ...@@ -18,4 +18,8 @@ class FakeModel
def valid? def valid?
errors.empty? errors.empty?
end end
def new_record?
false
end
end end
...@@ -8,7 +8,16 @@ RSpec::Matchers.define :have_column do |column_name| ...@@ -8,7 +8,16 @@ RSpec::Matchers.define :have_column do |column_name|
column && column.default.to_s == @default.to_s column && column.default.to_s == @default.to_s
end end
failure_message_for_should do |columns| failure_message_method =
"expected to find '#{column_name}', default '#{@default}' in #{columns.map{|column| [column.name, column.default] }}" if RSpec::Version::STRING.to_i >= 3
:failure_message
else
:failure_message_for_should
end
send(failure_message_method) do |columns|
"expected to find '#{column_name}', " +
"default '#{@default}' " +
"in #{columns.map { |column| [column.name, column.default] }}"
end end
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment