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:
- rbx-2
- 2.0.0
- 2.1.1
- 2.2.2
install:
- "travis_retry bundle install"
before_script: "sudo ntpdate -ub ntp.ubuntu.com pool.ntp.org; true"
script: "bundle exec rake clean spec cucumber"
gemfile:
- gemfiles/3.2.gemfile
- gemfiles/4.0.gemfile
- gemfiles/4.1.gemfile
- gemfiles/4.2.gemfile
matrix:
fast_finish: true
allow_failures:
- rvm: jruby-19mode
- rvm: rbx-2
sudo: false
cache: bundler
......@@ -14,6 +14,6 @@ appraise "4.1" do
end
appraise "4.2" do
gem "rails", "~> 4.2.0.rc2"
gem "rails", "~> 4.2.0"
gem "paperclip", :path => "../"
end
......@@ -6,7 +6,7 @@ We love pull requests. Here's a quick guide:
1. Fork the repo.
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
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.
### Bootstrapping your test suite:
bundle install
bundle exec rake appraisal:install
bundle exec appraisal install
This will install all the required gems that requires to test against each
version of Rails, which defined in `gemfiles/*.gemfile`.
### To run a full test suite:
bundle exec rake
bundle exec appraisal rake
This will run RSpec and Cucumber against all version of Rails
......
......@@ -2,7 +2,7 @@ source "https://rubygems.org"
gemspec
gem 'sqlite3', '1.3.8', :platforms => :ruby
gem 'sqlite3', '~>1.3.8', :platforms => :ruby
gem 'jruby-openssl', :platforms => :jruby
gem 'activerecord-jdbcsqlite3-adapter', :platforms => :jruby
......@@ -17,4 +17,5 @@ gem 'pry'
group :development, :test do
gem 'mime-types', '~> 1.16'
gem 'builder'
gem 'rubocop', require: false
end
......@@ -3,7 +3,7 @@ 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
of this software and associated documentation files (the "Software"), to deal
......
......@@ -12,7 +12,7 @@ New in 4.2.1:
* Improvement: Better escaping for characters in URLs
* Improvement: Honor `fog_credentials[:scheme]`
* 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: Update expiring_url creation for later versions of fog
* 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|
if ENV['BUNDLE_GEMFILE']
exec('rake spec cucumber')
else
exec("rm gemfiles/*.lock")
exec("rm -f gemfiles/*.lock")
Rake::Task["appraisal:gemfiles"].execute
Rake::Task["appraisal:install"].execute
exec('rake appraisal')
......
......@@ -12,17 +12,20 @@ Feature: Rails integration
Scenario: Configure defaults for all attachments through Railtie
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 start the rails application
When I go to the new user page
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"
Then I should see "Name: something"
And I should see an image with a path of "/paperclip/custom/attachments/original/5k.png"
And the file at "/paperclip/custom/attachments/original/5k.png" should be the same as "spec/support/fixtures/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/animated.unknown" should be the same as "spec/support/fixtures/animated.unknown"
Scenario: Add custom processors
Given I add a "test" processor in "lib/paperclip"
......
......@@ -49,7 +49,13 @@ end
Then /^the attachment should have the same content type as the fixture "([^"]*)"$/ do |filename|
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.should == MIME::Types.type_for(filename).first.content_type
end
......
......@@ -2,7 +2,7 @@
source "https://rubygems.org"
gem "sqlite3", "1.3.8", :platforms => :ruby
gem "sqlite3", "~>1.3.8", :platforms => :ruby
gem "jruby-openssl", :platforms => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
gem "rubysl", :platforms => :rbx
......@@ -14,6 +14,7 @@ gem "paperclip", :path => "../"
group :development, :test do
gem "mime-types", "~> 1.16"
gem "builder"
gem "rubocop", :require => false
end
gemspec :path => "../"
......@@ -2,7 +2,7 @@
source "https://rubygems.org"
gem "sqlite3", "1.3.8", :platforms => :ruby
gem "sqlite3", "~>1.3.8", :platforms => :ruby
gem "jruby-openssl", :platforms => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
gem "rubysl", :platforms => :rbx
......@@ -14,6 +14,7 @@ gem "paperclip", :path => "../"
group :development, :test do
gem "mime-types", "~> 1.16"
gem "builder"
gem "rubocop", :require => false
end
gemspec :path => "../"
......@@ -2,7 +2,7 @@
source "https://rubygems.org"
gem "sqlite3", "1.3.8", :platforms => :ruby
gem "sqlite3", "~>1.3.8", :platforms => :ruby
gem "jruby-openssl", :platforms => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
gem "rubysl", :platforms => :rbx
......@@ -14,6 +14,7 @@ gem "paperclip", :path => "../"
group :development, :test do
gem "mime-types", "~> 1.16"
gem "builder"
gem "rubocop", :require => false
end
gemspec :path => "../"
......@@ -2,18 +2,19 @@
source "https://rubygems.org"
gem "sqlite3", "1.3.8", :platforms => :ruby
gem "sqlite3", "~>1.3.8", :platforms => :ruby
gem "jruby-openssl", :platforms => :jruby
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
gem "rubysl", :platforms => :rbx
gem "racc", :platforms => :rbx
gem "pry"
gem "rails", "~> 4.2.0.rc2"
gem "rails", "~> 4.2.0"
gem "paperclip", :path => "../"
group :development, :test do
gem "mime-types", "~> 1.16"
gem "builder"
gem "rubocop", :require => false
end
gemspec :path => "../"
......@@ -55,7 +55,17 @@ require 'paperclip/helpers'
require 'paperclip/has_attached_file'
require 'paperclip/attachment_registry'
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 'cocaine'
......@@ -136,7 +146,7 @@ module Paperclip
# user.avatar.url # => "/avatars/23/normal_me.png"
# * +keep_old_files+: Keep the existing attachment files (original + resized) from
# being automatically deleted when an attachment is cleared or updated. Defaults to +false+.
# * +preserve_files+: Keep the existing attachment files in all cases, even if the parent
# * +preserve_files+: Keep the existing attachment files in all cases, even if the parent
# record is destroyed. Defaults to +false+.
# * +whiny+: Will raise an error if Paperclip cannot post_process an uploaded file due
# to a command line error. This will override the global setting for this attachment.
......
......@@ -137,6 +137,8 @@ module Paperclip
# +#for(style_name, options_hash)+
def url(style_name = default_style, options = {})
return nil if @instance.new_record?
if options == true || options == false # Backwards compatibility.
@url_generator.for(style_name, default_options.merge(:timestamp => options))
else
......@@ -528,7 +530,7 @@ module Paperclip
@queued_for_write[name] = Paperclip.io_adapters.for(@queued_for_write[name])
unadapted_file.close if unadapted_file.respond_to?(:close)
@queued_for_write[name]
rescue Paperclip::Error => e
rescue Paperclip::Errors::NotIdentifiedByImageMagickError => e
log("An error was received while processing: #{e.inspect}")
(@errors[:processing] ||= []) << e.message if @options[:whiny]
ensure
......
......@@ -52,7 +52,7 @@ module Paperclip
def definitions_for(klass)
klass.ancestors.each_with_object({}) do |ancestor, inherited_definitions|
inherited_definitions.merge! @attachments[ancestor]
inherited_definitions.deep_merge! @attachments[ancestor]
end
end
end
......
......@@ -2,7 +2,7 @@ module Paperclip
class ContentTypeDetector
# 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)
#
# 2. Calculated match: Return the first result that is found by both the
......@@ -20,8 +20,8 @@ module Paperclip
EMPTY_TYPE = "inode/x-empty"
SENSIBLE_DEFAULT = "application/octet-stream"
def initialize(filename)
@filename = filename
def initialize(filepath)
@filepath = filepath
end
# Returns a String describing the file's content type
......@@ -33,32 +33,47 @@ module Paperclip
elsif calculated_type_matches.any?
calculated_type_matches.first
else
type_from_file_command || SENSIBLE_DEFAULT
type_from_file_contents || SENSIBLE_DEFAULT
end.to_s
end
private
def blank_name?
@filepath.nil? || @filepath.empty?
end
def empty_file?
File.exist?(@filename) && File.size(@filename) == 0
File.exist?(@filepath) && File.size(@filepath) == 0
end
alias :empty? :empty_file?
def blank_name?
@filename.nil? || @filename.empty?
def calculated_type_matches
possible_types.select do |content_type|
content_type == type_from_file_contents
end
end
def possible_types
MIME::Types.type_for(@filename).collect(&:content_type)
MIME::Types.type_for(@filepath).collect(&:content_type)
end
def calculated_type_matches
possible_types.select{|content_type| content_type == type_from_file_command }
def type_from_file_contents
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
def type_from_file_command
@type_from_file_command ||= FileCommandContentTypeDetector.new(@filename).detect
@type_from_file_command ||=
FileCommandContentTypeDetector.new(@filepath).detect
end
end
end
......@@ -13,20 +13,18 @@ module Paperclip
private
def type_from_file_command
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
type = begin
# 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)
rescue Cocaine::CommandLineError => e
Paperclip.log("Error while determining content type: #{e}")
SENSIBLE_DEFAULT
end
Paperclip.run("file", "-b --mime :file", file: @filename)
rescue Cocaine::CommandLineError => e
Paperclip.log("Error while determining content type: #{e}")
SENSIBLE_DEFAULT
end
if type.nil? || type.match(/\(.*?\)/)
type = SENSIBLE_DEFAULT
end
type.split(/[:;\s]+/)[0]
end
end
end
......@@ -8,7 +8,7 @@ module Paperclip
base.extend ClassMethods
base.send :include, Callbacks
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}")
I18n.load_path += locale_path unless I18n.load_path.include?(locale_path)
......
......@@ -79,7 +79,8 @@ module Paperclip
end
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
@klass.validates_media_type_spoof_detection name,
:if => ->(instance){ instance.send(name).dirty? }
......
......@@ -172,7 +172,7 @@ module Paperclip
when Integer
("%09d" % id).scan(/\d{3}/).join("/")
when String
('%9.9s' % id).tr(" ", "0").scan(/.{3}/).join("/")
id.scan(/.{3}/).first(3).join("/")
else
nil
end
......
......@@ -6,6 +6,7 @@ module Paperclip
attr_reader :content_type, :original_filename, :size
delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink, :to => :@tempfile
alias :length :size
def fingerprint
@fingerprint ||= Digest::MD5.file(path).to_s
......
......@@ -42,7 +42,7 @@ module Paperclip
end
def mapping_override_mismatch?
mapped_content_type != calculated_content_type
!Array(mapped_content_type).include?(calculated_content_type)
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
def expiring_url(time = (Time.now + 3600), style_name = default_style)
time = convert_time(time)
if path(style_name) && directory.files.respond_to?(:get_http_url)
expiring_url = directory.files.get_http_url(path(style_name), time)
http_url_method = "get_#{scheme}_url"
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]
expiring_url.gsub!(/#{host_name_for_directory}/, dynamic_fog_host_for_style(style_name))
......@@ -156,8 +157,7 @@ module Paperclip
def parse_credentials(creds)
creds = find_credentials(creds).stringify_keys
env = Object.const_defined?(:Rails) ? Rails.env : nil
(creds[env] || creds).symbolize_keys
(creds[RailsEnvironment.get] || creds).symbolize_keys
end
def copy_to_local_file(style, local_dest_path)
......
......@@ -4,7 +4,7 @@ module Paperclip
# 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:
# gem 'aws-sdk'
# gem 'aws-sdk', '~> 1.6'
# 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
# to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon
......@@ -288,8 +288,7 @@ module Paperclip
def parse_credentials creds
creds = creds.respond_to?('call') ? creds.call(self) : creds
creds = find_credentials(creds).stringify_keys
env = Object.const_defined?(:Rails) ? Rails.env : nil
(creds[env] || creds).symbolize_keys
(creds[RailsEnvironment.get] || creds).symbolize_keys
end
def exists?(style = default_style)
......
......@@ -29,7 +29,6 @@ module Paperclip
super
geometry = options[:geometry].to_s
@file = file
@crop = geometry[-1,1] == '#'
@target_geometry = options.fetch(:string_geometry_parser, Geometry).parse(geometry)
@current_geometry = options.fetch(:file_geometry_parser, Geometry).from_file(@file)
......@@ -64,8 +63,8 @@ module Paperclip
# that contains the new image.
def make
src = @file
dst = Tempfile.new([@basename, @format ? ".#{@format}" : ''])
dst.binmode
filename = [@basename, @format ? ".#{@format}" : ""].join
dst = TempfileFactory.new.generate(filename)
begin
parameters = []
......
......@@ -108,4 +108,20 @@ namespace :paperclip do
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
......@@ -12,8 +12,6 @@ Gem::Specification.new do |s|
s.description = "Easy upload management for ActiveRecord"
s.license = "MIT"
s.rubyforge_project = "paperclip"
s.files = `git ls-files`.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) }
......@@ -24,21 +22,22 @@ Gem::Specification.new do |s|
s.add_dependency('activemodel', '>= 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('mimemagic', '0.3.0')
s.add_development_dependency('activerecord', '>= 3.0.0')
s.add_development_dependency('shoulda')
s.add_development_dependency('rspec')
s.add_development_dependency('appraisal')
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('cucumber', '~> 1.3.11')
s.add_development_dependency('cucumber', '~> 1.3.18')
s.add_development_dependency('aruba')
s.add_development_dependency('nokogiri')
# 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('fog', '~> 1.0')
s.add_development_dependency('launchy')
......
......@@ -8,6 +8,6 @@ describe "Attachment Definitions" do
Dummy.do_not_validate_attachment_file_type :avatar
expected = {avatar: {path: "abc"}, other_attachment: {url: "123"}}
assert_equal expected, Dummy.attachment_definitions
expect(Dummy.attachment_definitions).to eq expected
end
end
......@@ -31,8 +31,8 @@ describe 'Attachment Registry' do
it 'calls the block with the class, attachment name, and options' do
foo = Class.new
expected_accumulations = [
[foo, :avatar, { yo: 'greeting' }],
[foo, :greeter, { ciao: 'greeting' }]
[foo, :avatar, { yo: "greeting" }],
[foo, :greeter, { ciao: "greeting" }]
]
expected_accumulations.each do |args|
Paperclip::AttachmentRegistry.register(*args)
......@@ -50,25 +50,64 @@ describe 'Attachment Registry' do
context '.definitions_for' do
it 'produces the attachment name and options' do
expected_definitions = {
avatar: { yo: 'greeting' },
greeter: { ciao: 'greeting' }
avatar: { yo: "greeting" },
greeter: { ciao: "greeting" }
}
foo = Class.new
Paperclip::AttachmentRegistry.register(foo, :avatar, { yo: 'greeting' })
Paperclip::AttachmentRegistry.register(foo, :greeter, { ciao: 'greeting' })
Paperclip::AttachmentRegistry.register(
foo,
:avatar,
yo: "greeting"
)
Paperclip::AttachmentRegistry.register(
foo,
:greeter,
ciao: "greeting"
)
definitions = Paperclip::AttachmentRegistry.definitions_for(foo)
assert_equal expected_definitions, definitions
end
it "produces defintions for subclasses" do
expected_definitions = { avatar: { yo: 'greeting' } }
Foo = Class.new
Bar = Class.new(Foo)
Paperclip::AttachmentRegistry.register(Foo, :avatar, expected_definitions[:avatar])
it 'produces defintions for subclasses' do
expected_definitions = { avatar: { yo: "greeting" } }
foo = Class.new
bar = Class.new(foo)
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
end
......@@ -77,7 +116,11 @@ describe 'Attachment Registry' do
context '.clear' do
it 'removes all of the existing attachment definitions' do
foo = Class.new
Paperclip::AttachmentRegistry.register(foo, :greeter, { ciao: 'greeting' })
Paperclip::AttachmentRegistry.register(
foo,
:greeter,
ciao: "greeting"
)
Paperclip::AttachmentRegistry.clear
......
......@@ -13,7 +13,7 @@ describe Paperclip::Attachment do
it "is present when the file is set" do
rebuild_class
dummy = Dummy.new
dummy.avatar = File.new(fixture_file("50x50.png"), "rb")
dummy.avatar = File.new(fixture_file("50x50.png"), "rb")
expect(dummy.avatar).to_not be_blank
expect(dummy.avatar).to be_present
end
......@@ -34,9 +34,9 @@ describe Paperclip::Attachment do
it "does not delete styles that don't get reprocessed" do
file = File.new(fixture_file("50x50.png"), 'rb')
rebuild_class styles: {
small: '100x>',
large: '500x>',
original: '42x42#'
small: "100x>",
large: "500x>",
original: "42x42#"
}
dummy = Dummy.new
......@@ -75,7 +75,11 @@ describe Paperclip::Attachment do
it "handles a boolean second argument to #url" do
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)
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
it "passes the style and options through to the URL generator on #url" do
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)
expect(mock_url_generator_builder.has_generated_url_with_options?(options: :values)).to eq true
......@@ -95,7 +103,7 @@ describe Paperclip::Attachment do
it "passes default options through when #url is given one argument" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name,
:instance,
FakeModel.new,
url_generator: mock_url_generator_builder,
use_timestamp: true)
......@@ -106,7 +114,7 @@ describe Paperclip::Attachment do
it "passes default style and options through when #url is given no arguments" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name,
:instance,
FakeModel.new,
default_style: 'default style',
url_generator: mock_url_generator_builder,
use_timestamp: true)
......@@ -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
mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name,
:instance,
FakeModel.new,
url_generator: mock_url_generator_builder,
use_timestamp: true)
......@@ -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
mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name,
:instance,
FakeModel.new,
url_generator: mock_url_generator_builder,
use_timestamp: false)
......@@ -141,7 +149,7 @@ describe Paperclip::Attachment do
it "does not change the :timestamp if :timestamp is passed" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name,
:instance,
FakeModel.new,
url_generator: mock_url_generator_builder,
use_timestamp: false)
......@@ -152,7 +160,7 @@ describe Paperclip::Attachment do
it "renders JSON as default style" do
mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name,
:instance,
FakeModel.new,
default_style: 'default style',
url_generator: mock_url_generator_builder)
......@@ -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
mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name,
:instance,
FakeModel.new,
url_generator: mock_url_generator_builder,
escape_url: true)
......@@ -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
mock_url_generator_builder = MockUrlGeneratorBuilder.new
attachment = Paperclip::Attachment.new(:name,
:instance,
FakeModel.new,
url_generator: mock_url_generator_builder,
escape_url: false)
......@@ -212,6 +220,7 @@ describe Paperclip::Attachment do
dummy = Dummy.new
dummy.id = 1234
dummy.avatar_file_name = "fake.jpg"
dummy.stubs(:new_record?).returns(false)
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
expected_string = %({"dummy":#{expected_string}})
......@@ -251,6 +260,10 @@ describe Paperclip::Attachment do
it "returns false when asked exists?" do
assert !@dummy.avatar.exists?
end
it "#url returns nil" do
assert_nil @dummy.avatar.url
end
end
context "on an Attachment" do
......@@ -635,15 +648,40 @@ describe Paperclip::Attachment do
before do
rebuild_model processor: [:thumbnail], styles: { small: '' }, whiny_thumbnails: true
@dummy = Dummy.new
Paperclip::Thumbnail.expects(:make).raises(Paperclip::Error, "cannot be processed.")
@file = StringIO.new("...")
@file.stubs(:to_tempfile).returns(@file)
@dummy.avatar = @file
end
it "correctly forwards processing error message to the instance" do
@dummy.valid?
assert_contains @dummy.errors.full_messages, "Avatar cannot be processed."
context "when error is meaningful for the end user" do
before do
Paperclip::Thumbnail.expects(:make).raises(
Paperclip::Errors::NotIdentifiedByImageMagickError,
"cannot be processed."
)
end
it "correctly forwards processing error message to the instance" do
@dummy.avatar = @file
@dummy.valid?
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
......
require 'spec_helper'
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
assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new("").detect
end
......@@ -13,7 +19,8 @@ describe Paperclip::ContentTypeDetector 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')])
Paperclip.stubs(:run).returns("video/mp4")
Paperclip::ContentTypeDetector.any_instance
.stubs(:type_from_file_contents).returns("video/mp4")
@filename = "my_file.mp4"
assert_equal "video/mp4", Paperclip::ContentTypeDetector.new(@filename).detect
end
......
......@@ -24,4 +24,3 @@ describe Paperclip::FileCommandContentTypeDetector do
Paperclip::FileCommandContentTypeDetector.new("windows").detect
end
end
......@@ -138,14 +138,7 @@ describe Paperclip::Interpolations do
assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style)
end
it "returns the partitioned id of the attachment when the id is a short 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
it "returns the partitioned id of the attachment when the id is a string" do
attachment = mock
attachment.expects(:id).returns("32fnj23oio2f")
attachment.expects(:instance).returns(attachment)
......@@ -211,7 +204,7 @@ describe Paperclip::Interpolations do
attachment.stubs(:original_filename).returns("one")
assert_equal "one", Paperclip::Interpolations.filename(attachment, :style)
end
it "returns the basename when the extension contains regexp special characters" do
attachment = mock
attachment.stubs(:styles).returns({})
......
......@@ -9,11 +9,12 @@ describe Paperclip::AbstractAdapter do
end
end
context "content type from file command" do
context "content type from file contents" do
before do
@adapter = TestAdapter.new
@adapter.stubs(:path).returns("image.png")
Paperclip.stubs(:run).returns("image/png\n")
Paperclip::ContentTypeDetector.any_instance.stubs(:type_from_mime_magic).returns("image/png")
end
it "returns the content type without newline" do
......
......@@ -73,10 +73,13 @@ describe Paperclip::FileAdapter do
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
MIME::Types.stubs(:type_for).returns([])
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)
end
......
......@@ -20,6 +20,10 @@ describe Paperclip::StringioAdapter do
assert_equal 6, @subject.size
end
it "returns the length of the data" do
assert_equal 6, @subject.length
end
it "generates an MD5 hash of the contents" do
assert_equal Digest::MD5.hexdigest(@contents), @subject.fingerprint
end
......
......@@ -53,4 +53,18 @@ describe Paperclip::MediaTypeSpoofDetector do
file = File.open(fixture_file("empty.html"))
assert ! Paperclip::MediaTypeSpoofDetector.using(file, "empty.html", "").spoofed?
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
......@@ -20,7 +20,7 @@ describe Paperclip do
it "saves Cocaine::CommandLine.path that set before" do
Cocaine::CommandLine.path = "/opt/my_app/bin"
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
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
it "honors the scheme in public url" do
assert_match(/^http:\/\//, @dummy.avatar.url)
end
it "honors the scheme in expiring url" do
assert_match(/^http:\/\//, @dummy.avatar.expiring_url)
end
end
context "with scheme not set" do
......@@ -334,15 +337,20 @@ describe Paperclip::Storage::Fog do
it "provides HTTPS public url" do
assert_match(/^https:\/\//, @dummy.avatar.url)
end
it "provides HTTPS expiring url" do
assert_match(/^https:\/\//, @dummy.avatar.expiring_url)
end
end
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
assert_match(/^https:\/\/papercliptests.s3.amazonaws.com\/avatars\/5k.png/, @dummy.avatar.url)
end
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
......@@ -390,7 +398,7 @@ describe Paperclip::Storage::Fog do
end
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
......@@ -492,6 +500,7 @@ describe Paperclip::Storage::Fog do
@file = File.new(fixture_file('5k.png'), 'rb')
@dummy = Dummy.new
@dummy.avatar = @file
@dummy.stubs(:new_record?).returns(false)
end
after do
......
......@@ -105,6 +105,7 @@ describe Paperclip::Storage::S3 do
url: ":s3_path_url"
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a url based on an S3 path" do
......@@ -145,6 +146,7 @@ describe Paperclip::Storage::S3 do
path: ":attachment/:basename:dotextension"
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a url based on an S3 path" do
......@@ -161,6 +163,7 @@ describe Paperclip::Storage::S3 do
path: ":attachment/:basename:dotextension"
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a protocol-relative URL" do
......@@ -177,6 +180,7 @@ describe Paperclip::Storage::S3 do
path: ":attachment/:basename:dotextension"
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a url based on an S3 path" do
......@@ -193,6 +197,7 @@ describe Paperclip::Storage::S3 do
path: ":attachment/:basename:dotextension"
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a url based on an S3 path" do
......@@ -236,6 +241,7 @@ describe Paperclip::Storage::S3 do
s3_host_name: "s3-ap-northeast-1.amazonaws.com"
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a url based on an :s3_host_name path" do
......@@ -259,6 +265,7 @@ describe Paperclip::Storage::S3 do
attr_accessor :value
end
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "uses s3_host_name as a proc if available" do
......@@ -281,6 +288,7 @@ describe Paperclip::Storage::S3 do
File.open(fixture_file('5k.png'), 'rb') do |file|
@dummy = Dummy.new
@dummy.avatar = file
@dummy.stubs(:new_record?).returns(false)
end
end
......@@ -342,18 +350,19 @@ describe Paperclip::Storage::S3 do
context "An attachment that uses S3 for storage and has spaces in file name" do
before do
rebuild_model styles: { large: ['500x500#', :jpg] },
rebuild_model(
styles: { large: ["500x500#", :jpg] },
storage: :s3,
bucket: "bucket",
s3_credentials: {
'access_key_id' => "12345",
'secret_access_key' => "54321"
}
s3_credentials: { "access_key_id" => "12345",
"secret_access_key" => "54321" }
)
File.open(fixture_file('spaced file.png'), 'rb') do |file|
@dummy = Dummy.new
@dummy.avatar = file
end
File.open(fixture_file("spaced file.png"), "rb") do |file|
@dummy = Dummy.new
@dummy.avatar = file
@dummy.stubs(:new_record?).returns(false)
end
end
it "returns a replaced version for path" do
......@@ -375,16 +384,17 @@ describe Paperclip::Storage::S3 do
'secret_access_key' => "54321"
}
stringio = stringy_file
class << stringio
def original_filename
"question?mark.png"
end
stringio = stringy_file
class << stringio
def original_filename
"question?mark.png"
end
file = Paperclip.io_adapters.for(stringio)
@dummy = Dummy.new
@dummy.avatar = file
@dummy.save
end
file = Paperclip.io_adapters.for(stringio)
@dummy = Dummy.new
@dummy.avatar = file
@dummy.save
@dummy.stubs(:new_record?).returns(false)
end
it "returns a replaced version for path" do
......@@ -405,6 +415,7 @@ describe Paperclip::Storage::S3 do
url: ":s3_domain_url"
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a url based on an S3 subdomain" do
......@@ -414,16 +425,20 @@ describe Paperclip::Storage::S3 do
context "" do
before do
rebuild_model storage: :s3,
rebuild_model(
storage: :s3,
s3_credentials: {
production: { bucket: "prod_bucket" },
development: { bucket: "dev_bucket" }
},
s3_host_alias: "something.something.com",
path: ":attachment/:basename:dotextension",
url: ":s3_alias_url"
production: { bucket: "prod_bucket" },
development: { bucket: "dev_bucket" }
},
bucket: "bucket",
s3_host_alias: "something.something.com",
path: ":attachment/:basename:dotextension",
url: ":s3_alias_url"
)
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a url based on the host_alias" do
......@@ -447,6 +462,7 @@ describe Paperclip::Storage::S3 do
end
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a url based on the host_alias" do
......@@ -469,6 +485,7 @@ describe Paperclip::Storage::S3 do
url: ":asset_host"
@dummy = Dummy.new
@dummy.avatar = stringy_file
@dummy.stubs(:new_record?).returns(false)
end
it "returns a relative URL for Rails to calculate assets host" do
......@@ -684,6 +701,7 @@ describe Paperclip::Storage::S3 do
@file = File.new(fixture_file('5k.png'), 'rb')
@dummy = Dummy.new
@dummy.avatar = @file
@dummy.stubs(:new_record?).returns(false)
end
after { @file.close }
......
......@@ -26,4 +26,8 @@ describe Paperclip::TempfileFactory do
file = subject.generate
assert File.exist?(file.path)
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
......@@ -481,4 +481,20 @@ describe Paperclip::Thumbnail do
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
......@@ -43,7 +43,7 @@ describe Paperclip::UrlGenerator do
end
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_interpolator = MockInterpolator.new
default_url = :to_s
......
......@@ -18,4 +18,8 @@ class FakeModel
def valid?
errors.empty?
end
def new_record?
false
end
end
......@@ -8,7 +8,16 @@ RSpec::Matchers.define :have_column do |column_name|
column && column.default.to_s == @default.to_s
end
failure_message_for_should do |columns|
"expected to find '#{column_name}', default '#{@default}' in #{columns.map{|column| [column.name, column.default] }}"
failure_message_method =
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
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