Commit 89c8d117 by Jon Yurek

Adds IO adapters to abstract the things that can be assigned.

Needs work for S3 Attachments.
parent 63886520
File added
...@@ -19,13 +19,10 @@ GEM ...@@ -19,13 +19,10 @@ GEM
activesupport (= 3.2.2) activesupport (= 3.2.2)
arel (~> 3.0.2) arel (~> 3.0.2)
tzinfo (~> 0.3.29) tzinfo (~> 0.3.29)
activerecord-jdbc-adapter (1.2.2)
activerecord-jdbcsqlite3-adapter (1.2.2)
activerecord-jdbc-adapter (~> 1.2.2)
jdbc-sqlite3 (~> 3.7.2)
activesupport (3.2.2) activesupport (3.2.2)
i18n (~> 0.6) i18n (~> 0.6)
multi_json (~> 1.0) multi_json (~> 1.0)
addressable (2.2.7)
appraisal (0.4.1) appraisal (0.4.1)
bundler bundler
rake rake
...@@ -40,7 +37,8 @@ GEM ...@@ -40,7 +37,8 @@ GEM
json (~> 1.4) json (~> 1.4)
nokogiri (<= 1.5.0) nokogiri (<= 1.5.0)
uuidtools (~> 2.1) uuidtools (~> 2.1)
bouncy-castle-java (1.5.0146.1) bourne (1.1.2)
mocha (= 0.10.5)
builder (3.0.0) builder (3.0.0)
capybara (1.1.2) capybara (1.1.2)
mime-types (>= 1.16) mime-types (>= 1.16)
...@@ -52,6 +50,7 @@ GEM ...@@ -52,6 +50,7 @@ GEM
childprocess (0.3.1) childprocess (0.3.1)
ffi (~> 1.0.6) ffi (~> 1.0.6)
cocaine (0.2.1) cocaine (0.2.1)
coderay (1.0.5)
cucumber (1.1.9) cucumber (1.1.9)
builder (>= 2.1.2) builder (>= 2.1.2)
diff-lcs (>= 1.1.2) diff-lcs (>= 1.1.2)
...@@ -62,7 +61,6 @@ GEM ...@@ -62,7 +61,6 @@ GEM
excon (0.6.6) excon (0.6.6)
fakeweb (1.3.0) fakeweb (1.3.0)
ffi (1.0.11) ffi (1.0.11)
ffi (1.0.11-java)
fog (0.9.0) fog (0.9.0)
builder builder
excon (~> 0.6.1) excon (~> 0.6.1)
...@@ -74,31 +72,30 @@ GEM ...@@ -74,31 +72,30 @@ GEM
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
ruby-hmac ruby-hmac
formatador (0.2.1) formatador (0.2.1)
gherkin (2.9.1) gherkin (2.9.3)
json (>= 1.4.6)
gherkin (2.9.1-java)
json (>= 1.4.6) json (>= 1.4.6)
httparty (0.8.1) httparty (0.8.1)
multi_json multi_json
multi_xml multi_xml
i18n (0.6.0) i18n (0.6.0)
jdbc-sqlite3 (3.7.2) json (1.6.6)
jruby-openssl (0.7.6.1) launchy (2.1.0)
bouncy-castle-java (>= 1.5.0146.1) addressable (~> 2.2.6)
json (1.6.5)
json (1.6.5-java)
metaclass (0.0.1) metaclass (0.0.1)
method_source (0.7.1)
mime-types (1.18) mime-types (1.18)
mocha (0.10.5) mocha (0.10.5)
metaclass (~> 0.0.1) metaclass (~> 0.0.1)
multi_json (1.1.0) multi_json (1.2.0)
multi_xml (0.4.2) multi_xml (0.4.2)
net-scp (1.0.4) net-scp (1.0.4)
net-ssh (>= 1.99.1) net-ssh (>= 1.99.1)
net-ssh (2.3.0) net-ssh (2.3.0)
nokogiri (1.4.7) nokogiri (1.4.7)
nokogiri (1.4.7-java) pry (0.9.8.4)
weakling (>= 0.0.3) coderay (~> 1.0.5)
method_source (~> 0.7.1)
slop (>= 2.4.4, < 3)
rack (1.4.1) rack (1.4.1)
rack-test (0.6.1) rack-test (0.6.1)
rack (>= 1.0) rack (>= 1.0)
...@@ -123,16 +120,15 @@ GEM ...@@ -123,16 +120,15 @@ GEM
shoulda-matchers (~> 1.0.0) shoulda-matchers (~> 1.0.0)
shoulda-context (1.0.0) shoulda-context (1.0.0)
shoulda-matchers (1.0.0) shoulda-matchers (1.0.0)
slop (2.4.4)
sqlite3 (1.3.5) sqlite3 (1.3.5)
term-ansicolor (1.0.7) term-ansicolor (1.0.7)
tzinfo (0.3.32) tzinfo (0.3.32)
uuidtools (2.1.2) uuidtools (2.1.2)
weakling (0.0.4-java)
xpath (0.1.4) xpath (0.1.4)
nokogiri (~> 1.3) nokogiri (~> 1.3)
PLATFORMS PLATFORMS
java
ruby ruby
DEPENDENCIES DEPENDENCIES
...@@ -140,6 +136,7 @@ DEPENDENCIES ...@@ -140,6 +136,7 @@ DEPENDENCIES
appraisal (~> 0.4.0) appraisal (~> 0.4.0)
aruba aruba
aws-sdk (~> 1.3.8) aws-sdk (~> 1.3.8)
bourne
bundler bundler
capybara capybara
cocaine (~> 0.2) cocaine (~> 0.2)
...@@ -147,8 +144,11 @@ DEPENDENCIES ...@@ -147,8 +144,11 @@ DEPENDENCIES
fakeweb fakeweb
fog fog
jruby-openssl jruby-openssl
launchy
mocha mocha
nokogiri (~> 1.4.7) nokogiri (~> 1.4.7)
paperclip! paperclip!
pry
rake
shoulda shoulda
sqlite3 sqlite3
When /^I print "([^\"]*)"$/ do |whatever|
puts whatever
end
Given /^I generate a new rails application$/ do Given /^I generate a new rails application$/ do
steps %{ steps %{
When I run `bundle exec #{new_application_command} #{APP_NAME}` When I run `bundle exec #{new_application_command} #{APP_NAME}`
......
require 'aruba/cucumber' require 'aruba/cucumber'
require 'capybara/cucumber' require 'capybara/cucumber'
require 'test/unit/assertions' require 'test/unit/assertions'
require 'pry'
$CUCUMBER=1
World(Test::Unit::Assertions) World(Test::Unit::Assertions)
Before do Before do
......
namespace :images do
desc "Regenerate images"
task :regenerate => :environment do
require 'open-uri'
OpportunityPhoto.all.each do |photo|
begin
old_name = photo.image_file_name
new_image = open(photo.image.url(:original, escape: false))
class << new_image
def original_filename; @original_filename; end
def original_filename=(name); @original_filename = name; end
end
new_image.original_filename = old_name
photo.image = new_image
photo.save
rescue => e
puts "ERROR: #{e.message} while processing #{photo.id}"
end
end
end
end
File added
...@@ -29,8 +29,6 @@ require 'erb' ...@@ -29,8 +29,6 @@ require 'erb'
require 'digest' require 'digest'
require 'tempfile' require 'tempfile'
require 'paperclip/version' require 'paperclip/version'
require 'paperclip/upfile'
require 'paperclip/iostream'
require 'paperclip/geometry' require 'paperclip/geometry'
require 'paperclip/processor' require 'paperclip/processor'
require 'paperclip/tempfile' require 'paperclip/tempfile'
...@@ -49,6 +47,7 @@ require 'paperclip/instance_methods' ...@@ -49,6 +47,7 @@ require 'paperclip/instance_methods'
require 'paperclip/logger' require 'paperclip/logger'
require 'paperclip/helpers' require 'paperclip/helpers'
require 'paperclip/railtie' require 'paperclip/railtie'
require 'mime/types'
require 'logger' require 'logger'
require 'cocaine' require 'cocaine'
...@@ -203,3 +202,12 @@ module Paperclip ...@@ -203,3 +202,12 @@ module Paperclip
end end
end end
end end
# This stuff needs to be run after Paperclip is defined.
require 'paperclip/io_adapters/registry'
require 'paperclip/io_adapters/identity_adapter'
require 'paperclip/io_adapters/file_adapter'
require 'paperclip/io_adapters/stringio_adapter'
require 'paperclip/io_adapters/nil_adapter'
require 'paperclip/io_adapters/attachment_adapter'
require 'paperclip/io_adapters/uploaded_file_adapter'
...@@ -7,8 +7,6 @@ module Paperclip ...@@ -7,8 +7,6 @@ module Paperclip
# when the model saves, deletes when the model is destroyed, and processes # when the model saves, deletes when the model is destroyed, and processes
# the file upon assignment. # the file upon assignment.
class Attachment class Attachment
include IOStream
def self.default_options def self.default_options
@default_options ||= { @default_options ||= {
:convert_options => {}, :convert_options => {},
...@@ -90,29 +88,16 @@ module Paperclip ...@@ -90,29 +88,16 @@ module Paperclip
# new_user.avatar = old_user.avatar # new_user.avatar = old_user.avatar
def assign uploaded_file def assign uploaded_file
ensure_required_accessors! ensure_required_accessors!
file = Paperclip.io_adapters.for(uploaded_file)
if uploaded_file.is_a?(Paperclip::Attachment)
uploaded_filename = uploaded_file.original_filename
uploaded_file = uploaded_file.to_file(:original)
close_uploaded_file = uploaded_file.respond_to?(:close)
else
instance_write(:uploaded_file, uploaded_file) if uploaded_file
end
return nil unless valid_assignment?(uploaded_file)
uploaded_file.binmode if uploaded_file.respond_to? :binmode
self.clear self.clear
return nil if file.nil?
return nil if uploaded_file.nil? @queued_for_write[:original] = file
instance_write(:file_name, cleanup_filename(file.original_filename))
uploaded_filename ||= uploaded_file.original_filename instance_write(:content_type, file.content_type)
stores_fingerprint = @instance.respond_to?("#{name}_fingerprint".to_sym) instance_write(:file_size, file.size)
@queued_for_write[:original] = to_tempfile(uploaded_file) instance_write(:fingerprint, file.fingerprint) if instance_respond_to?(:fingerprint)
instance_write(:file_name, cleanup_filename(uploaded_filename.strip))
instance_write(:content_type, uploaded_file.content_type.to_s.strip)
instance_write(:file_size, uploaded_file.size.to_i)
instance_write(:fingerprint, generate_fingerprint(uploaded_file)) if stores_fingerprint
instance_write(:updated_at, Time.now) instance_write(:updated_at, Time.now)
@dirty = true @dirty = true
...@@ -120,10 +105,8 @@ module Paperclip ...@@ -120,10 +105,8 @@ module Paperclip
post_process(*@options[:only_process]) if post_processing post_process(*@options[:only_process]) if post_processing
# Reset the file size if the original file was reprocessed. # Reset the file size if the original file was reprocessed.
instance_write(:file_size, @queued_for_write[:original].size.to_i) instance_write(:file_size, @queued_for_write[:original].size)
instance_write(:fingerprint, generate_fingerprint(@queued_for_write[:original])) if stores_fingerprint instance_write(:fingerprint, @queued_for_write[:original].fingerprint) if instance_respond_to?(:fingerprint)
ensure
uploaded_file.close if close_uploaded_file
end end
# Returns the public URL of the attachment with a given style. This does # Returns the public URL of the attachment with a given style. This does
...@@ -252,16 +235,10 @@ module Paperclip ...@@ -252,16 +235,10 @@ module Paperclip
instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size) instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size)
end end
# Returns the hash of the file as originally assigned, and lives in the # Returns the fingerprint of the file, if one's defined. The fingerprint is
# <attachment>_fingerprint attribute of the model. # stored in the <attachment>_fingerpring attribute of the model.
def fingerprint def fingerprint
if instance_read(:fingerprint) instance_read(:fingerprint)
instance_read(:fingerprint)
elsif @instance.respond_to?("#{name}_fingerprint".to_sym)
@queued_for_write[:original] && generate_fingerprint(@queued_for_write[:original])
else
nil
end
end end
# Returns the content_type of the file as originally assigned, and lives # Returns the content_type of the file as originally assigned, and lives
...@@ -307,26 +284,16 @@ module Paperclip ...@@ -307,26 +284,16 @@ module Paperclip
# thumbnails forcefully, by reobtaining the original file and going through # thumbnails forcefully, by reobtaining the original file and going through
# the post-process again. # the post-process again.
def reprocess!(*style_args) def reprocess!(*style_args)
new_original = Tempfile.new("paperclip-reprocess") saved_only_process, @options[:only_process] = @options[:only_process], style_args
new_original.binmode begin
if old_original = to_file(:original) assign(self)
new_original.write( old_original.respond_to?(:get) ? old_original.get : old_original.read )
new_original.rewind
@queued_for_write = { :original => new_original }
instance_write(:updated_at, Time.now)
post_process(*style_args)
old_original.close if old_original.respond_to?(:close)
old_original.unlink if old_original.respond_to?(:unlink)
save save
else rescue Errno::EACCES => e
true warn "#{e} - skipping file."
false
ensure
@options[:only_process] = saved_only_process
end end
rescue Errno::EACCES => e
warn "#{e} - skipping file"
false
end end
# Returns true if a file has been assigned. # Returns true if a file has been assigned.
...@@ -336,6 +303,12 @@ module Paperclip ...@@ -336,6 +303,12 @@ module Paperclip
alias :present? :file? alias :present? :file?
# Determines whether the instance responds to this attribute. Used to prevent
# calculations on fields we won't even store.
def instance_respond_to?(attr)
instance.respond_to?(:"#{name}_#{attr}")
end
# Writes the attachment-specific attribute on the instance. For example, # Writes the attachment-specific attribute on the instance. For example,
# instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's # instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's
# "avatar_file_name" field (assuming the attachment is called avatar). # "avatar_file_name" field (assuming the attachment is called avatar).
...@@ -428,6 +401,7 @@ module Paperclip ...@@ -428,6 +401,7 @@ module Paperclip
@queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor| @queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
Paperclip.processor(processor).make(file, style.processor_options, self) Paperclip.processor(processor).make(file, style.processor_options, self)
end end
@queued_for_write[name] = Paperclip.io_adapters.for(@queued_for_write[name])
rescue Paperclip::Error => e rescue Paperclip::Error => 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]
...@@ -463,8 +437,8 @@ module Paperclip ...@@ -463,8 +437,8 @@ module Paperclip
# called by storage after the writes are flushed and before @queued_for_writes is cleared # called by storage after the writes are flushed and before @queued_for_writes is cleared
def after_flush_writes def after_flush_writes
@queued_for_write.each do |style, file| @queued_for_write.each do |style, file|
file.close unless file.closed? # file.close unless file.closed?
file.unlink if file.respond_to?(:unlink) && file.path.present? && File.exist?(file.path) # file.unlink if file.respond_to?(:unlink) && file.path.present? && File.exist?(file.path)
end end
end end
......
module Paperclip
class AttachmentAdapter
def initialize(target)
@target = target
cache_current_values
end
def original_filename
@original_filename
end
def content_type
@content_type
end
def size
@size
end
def nil?
false
end
def fingerprint
@fingerprint ||= Digest::MD5.file(path).to_s
end
def read(length = nil, buffer = nil)
@tempfile.read(length, buffer)
end
def eof?
@tempfile.eof?
end
def path
@tempfile.path
end
private
def cache_current_values
@tempfile = copy_to_tempfile(@target)
@original_filename = @target.original_filename
@content_type = @target.content_type
@size = @tempfile.size || @target.size
end
def copy_to_tempfile(src)
dest = Tempfile.new(src.original_filename)
FileUtils.cp(src.path(:original), dest.path)
dest
end
end
end
Paperclip.io_adapters.register Paperclip::AttachmentAdapter do |target|
Paperclip::Attachment === target
end
require 'mime/types'
module Paperclip module Paperclip
# The Upfile module is a convenience module for adding uploaded-file-type methods class FileAdapter
# to the +File+ class. Useful for testing. def initialize(target)
# user.avatar = File.new("test/test_avatar.jpg") @target = target
module Upfile @tempfile = copy_to_tempfile(@target)
# Infer the MIME-type of the file from the extension. end
def original_filename
if @target.respond_to?(:original_filename)
@target.original_filename
else
File.basename(@target.path)
end
end
def content_type def content_type
types = MIME::Types.type_for(self.original_filename) types = MIME::Types.type_for(original_filename)
if types.length == 0 if types.length == 0
type_from_file_command type_from_file_command
elsif types.length == 1 elsif types.length == 1
types.first.content_type types.first.content_type
else else
iterate_over_array_to_find_best_option(types) best_content_type_option(types)
end end
end end
def iterate_over_array_to_find_best_option(types) def fingerprint
types.reject {|type| type.content_type.match(/\/x-/) }.first @fingerprint ||= Digest::MD5.file(path).to_s
end end
def type_from_file_command def size
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist. File.size(@tempfile)
type = (self.original_filename.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
mime_type = (Paperclip.run("file", "-b --mime :file", :file => self.path).split(/[:;]\s+/)[0] rescue "application/x-#{type}")
mime_type = "application/x-#{type}" if mime_type.match(/\(.*?\)/)
mime_type
end end
# Returns the file's normal name. def nil?
def original_filename @target.nil?
File.basename(self.path)
end end
# Returns the size of the file. def read(length = nil, buffer = nil)
def size @tempfile.read(length, buffer)
File.size(self)
end end
end
end
if defined? StringIO # We don't use this directly, but aws/sdk does.
class StringIO def rewind
attr_accessor :original_filename, :content_type, :fingerprint @tempfile.rewind
end
def original_filename def eof?
@original_filename ||= "stringio.txt" @tempfile.eof?
end end
def content_type def path
@content_type ||= "text/plain" @tempfile.path
end end
def fingerprint private
@fingerprint ||= Digest::MD5.hexdigest(self.string)
def copy_to_tempfile(src)
dest = Tempfile.new(original_filename)
FileUtils.cp(src.path, dest.path)
dest
end
def best_content_type_option(types)
types.reject {|type| type.content_type.match(/\/x-/) }.first
end
def type_from_file_command
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
type = (self.original_filename.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
mime_type = (Paperclip.run("file", "-b --mime :file", :file => self.path).split(/[:;]\s+/)[0] rescue "application/x-#{type}")
mime_type = "application/x-#{type}" if mime_type.match(/\(.*?\)/)
mime_type
end end
end end
end end
class File #:nodoc: Paperclip.io_adapters.register Paperclip::FileAdapter do |target|
include Paperclip::Upfile File === target || Tempfile === target
end end
module Paperclip
class IdentityAdapter
def new(adapter)
adapter
end
end
end
Paperclip.io_adapters.register Paperclip::IdentityAdapter.new do |target|
Paperclip.io_adapters.registered?(target)
end
module Paperclip
class NilAdapter
def initialize(target)
end
def original_filename
""
end
def content_type
""
end
def size
0
end
def nil?
true
end
def read(*args)
nil
end
def eof?
true
end
end
end
Paperclip.io_adapters.register Paperclip::NilAdapter do |target|
target.nil?
end
module Paperclip
class AdapterRegistry
class NoHandlerError < PaperclipError; end
attr_reader :registered_handlers
def initialize
@registered_handlers = []
end
def register(handler_class, &block)
@registered_handlers << [block, handler_class]
end
def handler_for(target)
@registered_handlers.each do |tester, handler|
return handler if tester.call(target)
end
raise NoHandlerError.new("No handler found for #{target.inspect}")
end
def registered?(target)
@registered_handlers.any? do |tester, handler|
handler === target
end
end
def for(target)
handler_for(target).new(target)
end
end
end
module Paperclip
class StringioAdapter
def initialize(target)
@target = target
@tempfile = copy_to_tempfile(@target)
end
attr_writer :original_filename, :content_type
def original_filename
@original_filename ||= @target.original_filename if @target.respond_to?(:original_filename)
@original_filename ||= "stringio.txt"
@original_filename.strip
end
def content_type
@content_type ||= @target.content_type if @target.respond_to?(:content_type)
@content_type ||= "text/plain"
@content_type.strip
end
def size
@target.size
end
def fingerprint
Digest::MD5.hexdigest(read)
end
def read(length = nil, buffer = nil)
@tempfile.read(length, buffer)
end
def eof?
@tempfile.eof?
end
def path
@tempfile.path
end
private
def copy_to_tempfile(src)
dest = Tempfile.new(original_filename)
dest.binmode
while data = src.read(16*1024)
dest.write(data)
end
dest.rewind
dest
end
end
end
Paperclip.io_adapters.register Paperclip::StringioAdapter do |target|
StringIO === target
end
module Paperclip
class UploadedFileAdapter
def initialize(target)
@target = target
@tempfile = copy_to_tempfile(@target.tempfile)
end
def original_filename
@target.original_filename
end
def content_type
@target.content_type
end
def fingerprint
@fingerprint ||= Digest::MD5.file(path).to_s
end
def size
File.size(path)
end
def nil?
false
end
def read(length = nil, buffer = nil)
@tempfile.read(length, buffer)
end
# We don't use this directly, but aws/sdk does.
def rewind
@tempfile.rewind
end
def eof?
@tempfile.eof?
end
def path
@tempfile.path
end
private
def copy_to_tempfile(src)
dest = Tempfile.new(original_filename)
FileUtils.cp(src.path, dest.path)
dest
end
end
end
Paperclip.io_adapters.register Paperclip::UploadedFileAdapter do |target|
target.class.name.include?("UploadedFile")
end
# Provides method that can be included on File-type objects (IO, StringIO, Tempfile, etc) to allow stream copying
# and Tempfile conversion.
module IOStream
# Returns a Tempfile containing the contents of the readable object.
def to_tempfile(object)
return object.to_tempfile if object.respond_to?(:to_tempfile)
name = object.respond_to?(:original_filename) ? object.original_filename : (object.respond_to?(:path) ? object.path : "stream")
tempfile = Paperclip::Tempfile.new(["stream", File.extname(name)])
tempfile.binmode
stream_to(object, tempfile)
end
# Copies one read-able object from one place to another in blocks, obviating the need to load
# the whole thing into memory. Defaults to 8k blocks. Returns a File if a String is passed
# in as the destination and returns the IO or Tempfile as passed in if one is sent as the destination.
def stream_to object, path_or_file, in_blocks_of = 8192
dstio = case path_or_file
when String then File.new(path_or_file, "wb+")
when IO then path_or_file
when Tempfile then path_or_file
end
buffer = ""
object.rewind
while object.read(in_blocks_of, buffer) do
dstio.write(buffer)
end
dstio.rewind
dstio
end
end
# Corrects a bug in Windows when asking for Tempfile size.
if defined?(Tempfile) && RUBY_PLATFORM !~ /java/
class Tempfile
def size
if @tmpfile
@tmpfile.fsync
@tmpfile.flush
@tmpfile.stat.size
else
0
end
end
end
end
...@@ -61,7 +61,7 @@ module Paperclip ...@@ -61,7 +61,7 @@ module Paperclip
protected protected
def type_allowed?(type) def type_allowed?(type)
file = StringIO.new(".") file = Paperclip.io_adapters.for(StringIO.new("."))
file.content_type = type file.content_type = type
@subject.attachment_for(@attachment_name).assign(file) @subject.attachment_for(@attachment_name).assign(file)
@subject.valid? @subject.valid?
......
...@@ -25,8 +25,6 @@ module Paperclip ...@@ -25,8 +25,6 @@ module Paperclip
ActiveRecord::ConnectionAdapters::Table.send(:include, Paperclip::Schema) ActiveRecord::ConnectionAdapters::Table.send(:include, Paperclip::Schema)
ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Paperclip::Schema) ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Paperclip::Schema)
end end
File.send(:include, Paperclip::Upfile)
end end
end end
end end
...@@ -27,23 +27,14 @@ module Paperclip ...@@ -27,23 +27,14 @@ module Paperclip
end end
end end
# Returns representation of the data of the file assigned to the given
# style, in the format most representative of the current storage.
def to_file style_name = default_style
if @queued_for_write[style_name]
@queued_for_write[style_name].rewind
@queued_for_write[style_name]
elsif exists?(style_name)
File.new(path(style_name), 'rb')
end
end
def flush_writes #:nodoc: def flush_writes #:nodoc:
@queued_for_write.each do |style_name, file| @queued_for_write.each do |style_name, file|
file.close
FileUtils.mkdir_p(File.dirname(path(style_name))) FileUtils.mkdir_p(File.dirname(path(style_name)))
log("saving #{path(style_name)}") File.open(path(style_name), "wb") do |new_file|
FileUtils.cp(file.path, path(style_name)) while chunk = file.read(16 * 1024)
new_file.write(chunk)
end
end
FileUtils.chmod(0666&~File.umask, path(style_name)) FileUtils.chmod(0666&~File.umask, path(style_name))
end end
......
...@@ -84,7 +84,7 @@ module Paperclip ...@@ -84,7 +84,7 @@ module Paperclip
:body => file, :body => file,
:key => path(style), :key => path(style),
:public => fog_public, :public => fog_public,
:content_type => file.content_type.to_s.strip :content_type => file.content_type
)) ))
rescue Excon::Errors::NotFound rescue Excon::Errors::NotFound
raise if retried raise if retried
...@@ -107,25 +107,6 @@ module Paperclip ...@@ -107,25 +107,6 @@ module Paperclip
@queued_for_delete = [] @queued_for_delete = []
end end
# Returns representation of the data of the file assigned to the given
# style, in the format most representative of the current storage.
def to_file(style = default_style)
if @queued_for_write[style]
@queued_for_write[style].rewind
@queued_for_write[style]
else
body = directory.files.get(path(style)).body
filename = path(style)
extname = File.extname(filename)
basename = File.basename(filename, extname)
file = Tempfile.new([basename, extname])
file.binmode
file.write(body)
file.rewind
file
end
end
def public_url(style = default_style) def public_url(style = default_style)
if @options[:fog_host] if @options[:fog_host]
host = if @options[:fog_host].respond_to?(:call) host = if @options[:fog_host].respond_to?(:call)
...@@ -133,7 +114,7 @@ module Paperclip ...@@ -133,7 +114,7 @@ module Paperclip
else else
(@options[:fog_host] =~ /%d/) ? @options[:fog_host] % (path(style).hash % 4) : @options[:fog_host] (@options[:fog_host] =~ /%d/) ? @options[:fog_host] % (path(style).hash % 4) : @options[:fog_host]
end end
"#{host}/#{path(style)}" "#{host}/#{path(style)}"
else else
if fog_credentials[:provider] == 'AWS' if fog_credentials[:provider] == 'AWS'
......
...@@ -264,23 +264,6 @@ module Paperclip ...@@ -264,23 +264,6 @@ module Paperclip
end end
end end
# Returns representation of the data of the file assigned to the given
# style, in the format most representative of the current storage.
def to_file style = default_style
if @queued_for_write[style]
@queued_for_write[style].rewind
return @queued_for_write[style]
end
filename = path(style)
extname = File.extname(filename)
basename = File.basename(filename, extname)
file = Tempfile.new([basename, extname])
file.binmode
file.write(s3_object(style).read)
file.rewind
return file
end
def create_bucket def create_bucket
s3_interface.buckets.create(bucket_name) s3_interface.buckets.create(bucket_name)
end end
...@@ -293,7 +276,7 @@ module Paperclip ...@@ -293,7 +276,7 @@ module Paperclip
acl = @s3_permissions[style] || @s3_permissions[:default] acl = @s3_permissions[style] || @s3_permissions[:default]
acl = acl.call(self, style) if acl.respond_to?(:call) acl = acl.call(self, style) if acl.respond_to?(:call)
write_options = { write_options = {
:content_type => file.content_type.to_s.strip, :content_type => file.content_type,
:acl => acl :acl => acl
} }
write_options[:metadata] = @s3_metadata unless @s3_metadata.empty? write_options[:metadata] = @s3_metadata unless @s3_metadata.empty?
......
...@@ -45,7 +45,7 @@ namespace :paperclip do ...@@ -45,7 +45,7 @@ namespace :paperclip do
names = Paperclip::Task.obtain_attachments(klass) names = Paperclip::Task.obtain_attachments(klass)
names.each do |name| names.each do |name|
Paperclip.each_instance_with_attachment(klass, name) do |instance| Paperclip.each_instance_with_attachment(klass, name) do |instance|
if file = instance.send(name).to_file(:original) if file = instance.send(name)
instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip) instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
instance.send("#{name}_content_type=", file.content_type.to_s.strip) instance.send("#{name}_content_type=", file.content_type.to_s.strip)
instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size") instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
......
...@@ -34,6 +34,8 @@ Gem::Specification.new do |s| ...@@ -34,6 +34,8 @@ Gem::Specification.new do |s|
s.add_development_dependency('appraisal', '~> 0.4.0') s.add_development_dependency('appraisal', '~> 0.4.0')
s.add_development_dependency('mocha') s.add_development_dependency('mocha')
s.add_development_dependency('aws-sdk', '~> 1.3.8') s.add_development_dependency('aws-sdk', '~> 1.3.8')
s.add_development_dependency('bourne')
s.add_development_dependency('sqlite3', '~> 1.3.4')
s.add_development_dependency('cucumber', '~> 1.1.0') s.add_development_dependency('cucumber', '~> 1.1.0')
s.add_development_dependency('aruba') s.add_development_dependency('aruba')
s.add_development_dependency('nokogiri', '~> 1.4.7') s.add_development_dependency('nokogiri', '~> 1.4.7')
...@@ -41,5 +43,8 @@ Gem::Specification.new do |s| ...@@ -41,5 +43,8 @@ Gem::Specification.new do |s|
s.add_development_dependency('bundler') s.add_development_dependency('bundler')
s.add_development_dependency('cocaine', '~> 0.2') s.add_development_dependency('cocaine', '~> 0.2')
s.add_development_dependency('fog') s.add_development_dependency('fog')
s.add_development_dependency('pry')
s.add_development_dependency('launchy')
s.add_development_dependency('rake')
s.add_development_dependency('fakeweb') s.add_development_dependency('fakeweb')
end end
require './test/helper'
class AdapterRegistryTest < Test::Unit::TestCase
context "for" do
setup do
class AdapterTest
def initialize(target); end
end
@subject = Paperclip::AdapterRegistry.new
@subject.register(AdapterTest){|t| Symbol === t }
end
should "return the class registered for the adapted type" do
assert_equal AdapterTest, @subject.for(:target).class
end
end
context "registered?" do
setup do
class AdapterTest
def initialize(target); end
end
@subject = Paperclip::AdapterRegistry.new
@subject.register(AdapterTest){|t| Symbol === t }
end
should "return true when the class of this adapter has been registered" do
assert @subject.registered?(AdapterTest.new(:target))
end
should "return false when the adapter has not been registered" do
assert ! @subject.registered?(Object)
end
end
end
require './test/helper'
class AttachmentAdapterTest < Test::Unit::TestCase
def setup
rebuild_model :path => "tmp/:class/:attachment/:style/:filename"
@attachment = Dummy.new.avatar
@file = File.new(fixture_file("5k.png"))
@attachment.assign(@file)
@attachment.save
@subject = Paperclip.io_adapters.for(@attachment)
end
should "get the right filename" do
assert_equal "5k.png", @subject.original_filename
end
should "get the content type" do
assert_equal "image/png", @subject.content_type
end
should "get the file's size" do
assert_equal 4456, @subject.size
end
should "return false for a call to nil?" do
assert ! @subject.nil?
end
should "generate a MD5 hash of the contents" do
expected = Digest::MD5.file(@file.path).to_s
assert_equal expected, @subject.fingerprint
end
should "read the contents of the file" do
expected = @file.read
actual = @subject.read
assert expected.length > 0
assert_equal expected.length, actual.length
assert_equal expected, actual
end
end
...@@ -678,10 +678,7 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -678,10 +678,7 @@ class AttachmentTest < Test::Unit::TestCase
@file = StringIO.new(".") @file = StringIO.new(".")
@file.stubs(:original_filename).returns("5k.png\n\n") @file.stubs(:original_filename).returns("5k.png\n\n")
@file.stubs(:content_type).returns("image/png\n\n") @file.stubs(:content_type).returns("image/png\n\n")
@file.stubs(:to_tempfile).returns(@file)
@dummy = Dummy.new @dummy = Dummy.new
Paperclip::Thumbnail.expects(:make).returns(@file)
@attachment = @dummy.avatar
@dummy.avatar = @file @dummy.avatar = @file
end end
...@@ -698,23 +695,12 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -698,23 +695,12 @@ class AttachmentTest < Test::Unit::TestCase
setup do setup do
rebuild_model rebuild_model
@not_file = mock("not_file") @file = StringIO.new(".")
@tempfile = mock("tempfile") @file.stubs(:original_filename).returns("sheep_say_bæ.png\r\n")
@not_file.stubs(:nil?).returns(false) @file.stubs(:content_type).returns("image/png\r\n")
@not_file.expects(:size).returns(10)
@tempfile.expects(:size).returns(10)
@not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n")
@not_file.expects(:content_type).returns("image/png\r\n")
@dummy = Dummy.new @dummy = Dummy.new
@attachment = @dummy.avatar @dummy.avatar = @file
@attachment.expects(:valid_assignment?).with(@not_file).returns(true)
@attachment.expects(:queue_existing_for_delete)
@attachment.expects(:post_process)
@attachment.expects(:to_tempfile).returns(@tempfile)
@attachment.expects(:generate_fingerprint).with(@tempfile).returns("12345")
@attachment.expects(:generate_fingerprint).with(@not_file).returns("12345")
@dummy.avatar = @not_file
end end
should "not remove strange letters" do should "not remove strange letters" do
...@@ -725,14 +711,14 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -725,14 +711,14 @@ class AttachmentTest < Test::Unit::TestCase
context "Attachment with reserved filename" do context "Attachment with reserved filename" do
setup do setup do
rebuild_model rebuild_model
@file = StringIO.new(".") @file = Paperclip.io_adapters.for(StringIO.new("."))
end end
context "with default configuration" do context "with default configuration" do
"&$+,/:;=?@<>[]{}|\^~%# ".split(//).each do |character| "&$+,/:;=?@<>[]{}|\^~%# ".split(//).each do |character|
context "with character #{character}" do context "with character #{character}" do
setup do setup do
@file.stubs(:original_filename).returns("file#{character}name.png") @file.original_filename = "file#{character}name.png"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = @file @dummy.avatar = @file
end end
...@@ -796,11 +782,8 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -796,11 +782,8 @@ class AttachmentTest < Test::Unit::TestCase
end end
should "should have matching to_s and url methods" do should "should have matching to_s and url methods" do
file = @attachment.to_file
assert file
assert_match @attachment.to_s, @attachment.url assert_match @attachment.to_s, @attachment.url
assert_match @attachment.to_s(:small), @attachment.url(:small) assert_match @attachment.to_s(:small), @attachment.url(:small)
file.close
end end
end end
...@@ -831,7 +814,6 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -831,7 +814,6 @@ class AttachmentTest < Test::Unit::TestCase
end end
should "return nil as path when no file assigned" do should "return nil as path when no file assigned" do
assert @attachment.to_file.nil?
assert_equal nil, @attachment.path assert_equal nil, @attachment.path
assert_equal nil, @attachment.path(:blah) assert_equal nil, @attachment.path(:blah)
end end
...@@ -886,10 +868,6 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -886,10 +868,6 @@ class AttachmentTest < Test::Unit::TestCase
assert @attachment.dirty? assert @attachment.dirty?
end end
should "set uploaded_file for access beyond the paperclip lifecycle" do
assert_equal @file, @attachment.uploaded_file
end
context "and saved" do context "and saved" do
setup do setup do
@attachment.save @attachment.save
...@@ -897,11 +875,7 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -897,11 +875,7 @@ class AttachmentTest < Test::Unit::TestCase
should "commit the files to disk" do should "commit the files to disk" do
[:large, :medium, :small].each do |style| [:large, :medium, :small].each do |style|
io = @attachment.to_file(style) assert File.exists?(@attachment.path(style))
# p "in commit to disk test, io is #{io.inspect} and @instance.id is #{@instance.id}"
assert File.exists?(io.path)
assert ! io.is_a?(::Tempfile)
io.close
end end
end end
...@@ -918,11 +892,6 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -918,11 +892,6 @@ class AttachmentTest < Test::Unit::TestCase
end end
end end
should "still have its #file attribute not be nil" do
assert ! (file = @attachment.to_file).nil?
file.close
end
context "and trying to delete" do context "and trying to delete" do
setup do setup do
@existing_names = @attachment.styles.keys.collect do |style| @existing_names = @attachment.styles.keys.collect do |style|
...@@ -1047,7 +1016,7 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -1047,7 +1016,7 @@ class AttachmentTest < Test::Unit::TestCase
should "return the right value when sent #avatar_file_size" do should "return the right value when sent #avatar_file_size" do
@dummy.avatar = @file @dummy.avatar = @file
assert_equal @file.size, @dummy.avatar.size assert_equal File.size(@file), @dummy.avatar.size
end end
context "and avatar_updated_at column" do context "and avatar_updated_at column" do
...@@ -1068,18 +1037,12 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -1068,18 +1037,12 @@ class AttachmentTest < Test::Unit::TestCase
assert_equal now.to_i, @dummy.avatar.updated_at assert_equal now.to_i, @dummy.avatar.updated_at
end end
end end
should "not calculate fingerprint after save" do should "not calculate fingerprint" do
@dummy.avatar = @file
@dummy.save
assert_nil @dummy.avatar.fingerprint
end
should "not calculate fingerprint before saving" do
@dummy.avatar = @file @dummy.avatar = @file
assert_nil @dummy.avatar.fingerprint assert_nil @dummy.avatar.fingerprint
end end
context "and avatar_content_type column" do context "and avatar_content_type column" do
setup do setup do
ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string
...@@ -1110,14 +1073,14 @@ class AttachmentTest < Test::Unit::TestCase ...@@ -1110,14 +1073,14 @@ class AttachmentTest < Test::Unit::TestCase
should "return the right value when sent #avatar_file_size" do should "return the right value when sent #avatar_file_size" do
@dummy.avatar = @file @dummy.avatar = @file
assert_equal @file.size, @dummy.avatar.size assert_equal File.size(@file), @dummy.avatar.size
end end
should "return the right value when saved, reloaded, and sent #avatar_file_size" do should "return the right value when saved, reloaded, and sent #avatar_file_size" do
@dummy.avatar = @file @dummy.avatar = @file
@dummy.save @dummy.save
@dummy = Dummy.find(@dummy.id) @dummy = Dummy.find(@dummy.id)
assert_equal @file.size, @dummy.avatar.size assert_equal File.size(@file), @dummy.avatar.size
end end
end end
......
require './test/helper'
class FileAdapterTest < Test::Unit::TestCase
context "a new instance" do
setup do
@file = File.new(fixture_file("5k.png"))
@subject = Paperclip.io_adapters.for(@file)
end
should "get the right filename" do
assert_equal "5k.png", @subject.original_filename
end
should "get the content type" do
assert_equal "image/png", @subject.content_type
end
should "get the file's size" do
assert_equal 4456, @subject.size
end
should "return false for a call to nil?" do
assert ! @subject.nil?
end
should "generate a MD5 hash of the contents" do
expected = Digest::MD5.file(@file.path).to_s
assert_equal expected, @subject.fingerprint
end
should "read the contents of the file" do
expected = @file.read
assert expected.length > 0
assert_equal expected, @subject.read
end
end
end
...@@ -5,6 +5,7 @@ require 'test/unit' ...@@ -5,6 +5,7 @@ require 'test/unit'
require 'shoulda' require 'shoulda'
require 'mocha' require 'mocha'
require 'bourne'
require 'active_record' require 'active_record'
require 'active_record/version' require 'active_record/version'
...@@ -13,6 +14,9 @@ require 'active_support/core_ext' ...@@ -13,6 +14,9 @@ require 'active_support/core_ext'
require 'mime/types' require 'mime/types'
require 'pathname' require 'pathname'
require 'pathname'
require 'pry'
puts "Testing against version #{ActiveRecord::VERSION::STRING}" puts "Testing against version #{ActiveRecord::VERSION::STRING}"
`ruby -e 'exit 0'` # Prime $? with a value. `ruby -e 'exit 0'` # Prime $? with a value.
......
require './test/helper'
class IdentityAdapterTest < Test::Unit::TestCase
should "respond to #new by returning the argument" do
adapter = Paperclip::IdentityAdapter.new
assert_equal :target, adapter.new(:target)
end
end
...@@ -54,7 +54,6 @@ class IntegrationTest < Test::Unit::TestCase ...@@ -54,7 +54,6 @@ class IntegrationTest < Test::Unit::TestCase
context "redefining its attachment styles" do context "redefining its attachment styles" do
setup do setup do
Dummy.class_eval do Dummy.class_eval do
has_attached_file :avatar, :styles => { :thumb => "150x25#" }
has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } } has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } }
end end
@d2 = Dummy.find(@dummy.id) @d2 = Dummy.find(@dummy.id)
...@@ -71,20 +70,6 @@ class IntegrationTest < Test::Unit::TestCase ...@@ -71,20 +70,6 @@ class IntegrationTest < Test::Unit::TestCase
should "change the timestamp" do should "change the timestamp" do
assert_not_equal @original_timestamp, @d2.avatar_updated_at assert_not_equal @original_timestamp, @d2.avatar_updated_at
end end
should "clean up the old original if it is a tempfile" do
original = @d2.avatar.to_file(:original)
tf = Paperclip::Tempfile.new('original')
tf.binmode
original.binmode
tf.write(original.read)
original.close
tf.rewind
@d2.avatar.expects(:to_file).with(:original).returns(tf)
@d2.avatar.reprocess!
end
end end
end end
...@@ -171,7 +156,7 @@ class IntegrationTest < Test::Unit::TestCase ...@@ -171,7 +156,7 @@ class IntegrationTest < Test::Unit::TestCase
end end
should "report the file size of the processed file and not the original" do should "report the file size of the processed file and not the original" do
assert_not_equal @file.size, @dummy.avatar.size assert_not_equal File.size(@file.path), @dummy.avatar.size
end end
teardown { @file.close } teardown { @file.close }
...@@ -287,6 +272,27 @@ class IntegrationTest < Test::Unit::TestCase ...@@ -287,6 +272,27 @@ class IntegrationTest < Test::Unit::TestCase
end end
end end
[000,002,022].each do |umask|
context "when the umask is #{umask}" do
setup do
rebuild_model
@dummy = Dummy.new
@file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
@umask = File.umask(umask)
end
teardown do
File.umask @umask
end
should "respect the current umask" do
@dummy.avatar = @file
@dummy.save
assert_equal 0666&~umask, 0666&File.stat(@dummy.avatar.path).mode
end
end
end
context "A model with a filesystem attachment" do context "A model with a filesystem attachment" do
setup do setup do
rebuild_model :styles => { :large => "300x300>", rebuild_model :styles => { :large => "300x300>",
...@@ -322,8 +328,6 @@ class IntegrationTest < Test::Unit::TestCase ...@@ -322,8 +328,6 @@ class IntegrationTest < Test::Unit::TestCase
assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.chomp
assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp assert_equal "32x32", `identify -format "%wx%h" "#{@d2.avatar.path(:thumb)}"`.chomp
@dummy.avatar = "not a valid file but not nil"
assert_equal File.basename(@file.path), @dummy.avatar_file_name
assert @dummy.valid? assert @dummy.valid?
assert @dummy.save assert @dummy.save
...@@ -362,13 +366,13 @@ class IntegrationTest < Test::Unit::TestCase ...@@ -362,13 +366,13 @@ class IntegrationTest < Test::Unit::TestCase
end end
end end
should "know the difference between good files, bad files, and not files" do should "not abide things that don't have adapters" do
expected = @dummy.avatar.to_file assert_raises(Paperclip::AdapterRegistry::NoHandlerError) do
@dummy.avatar = "not a file" @dummy.avatar = "not a file"
assert @dummy.valid? end
assert_equal expected.path, @dummy.avatar.path end
expected.close
should "not be ok with bad files" do
@dummy.avatar = @bad_file @dummy.avatar = @bad_file
assert ! @dummy.valid? assert ! @dummy.valid?
end end
...@@ -384,31 +388,13 @@ class IntegrationTest < Test::Unit::TestCase ...@@ -384,31 +388,13 @@ class IntegrationTest < Test::Unit::TestCase
should "be able to reload without saving and not have the file disappear" do should "be able to reload without saving and not have the file disappear" do
@dummy.avatar = @file @dummy.avatar = @file
assert @dummy.save assert @dummy.save, @dummy.errors.full_messages.inspect
@dummy.avatar.clear @dummy.avatar.clear
assert_nil @dummy.avatar_file_name assert_nil @dummy.avatar_file_name
@dummy.reload @dummy.reload
assert_equal "5k.png", @dummy.avatar_file_name assert_equal "5k.png", @dummy.avatar_file_name
end end
[000,002,022].each do |umask|
context "when the umask is #{umask}" do
setup do
@umask = File.umask umask
end
teardown do
File.umask @umask
end
should "respect the current umask" do
@dummy.avatar = @file
@dummy.save
assert_equal 0666&~umask, 0666&File.stat(@dummy.avatar.path).mode
end
end
end
context "that is assigned its file from another Paperclip attachment" do context "that is assigned its file from another Paperclip attachment" do
setup do setup do
@dummy2 = Dummy.new @dummy2 = Dummy.new
...@@ -423,9 +409,9 @@ class IntegrationTest < Test::Unit::TestCase ...@@ -423,9 +409,9 @@ class IntegrationTest < Test::Unit::TestCase
assert @dummy.avatar = @dummy2.avatar assert @dummy.avatar = @dummy2.avatar
@dummy.save @dummy.save
assert_equal @dummy.avatar_file_name, @dummy2.avatar_file_name
assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`, assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`,
`identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"` `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"`
assert_equal @dummy.avatar_file_name, @dummy2.avatar_file_name
end end
end end
...@@ -505,7 +491,6 @@ class IntegrationTest < Test::Unit::TestCase ...@@ -505,7 +491,6 @@ class IntegrationTest < Test::Unit::TestCase
end end
should "have the same contents as the original" do should "have the same contents as the original" do
@file.rewind
assert_equal @file.read, @files_on_s3[:original].read assert_equal @file.read, @files_on_s3[:original].read
end end
......
require './test/helper'
class IOStreamTest < Test::Unit::TestCase
include IOStream
context "A file" do
setup do
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
end
teardown { @file.close }
context "that is sent #stream_to" do
context "and given a String" do
setup do
FileUtils.mkdir_p(File.join(ROOT, 'tmp'))
assert @result = stream_to(@file, File.join(ROOT, 'tmp', 'iostream.string.test'))
end
should "return a File" do
assert @result.is_a?(File)
end
should "contain the same data as the original file" do
@file.rewind; @result.rewind
assert_equal @file.read, @result.read
end
end
context "and given a Tempfile" do
setup do
tempfile = Tempfile.new('iostream.test')
tempfile.binmode
assert @result = stream_to(@file, tempfile)
end
should "return a Tempfile" do
assert @result.is_a?(Tempfile)
end
should "contain the same data as the original file" do
@file.rewind; @result.rewind
assert_equal @file.read, @result.read
end
end
end
context "that is converted #to_tempfile" do
setup do
assert @tempfile = to_tempfile(@file)
end
should "convert it to a Paperclip Tempfile" do
assert @tempfile.is_a?(Paperclip::Tempfile)
end
should "have the name be based on the original_filename" do
name = File.basename(@file.path)
extension = File.extname(name)
basename = File.basename(name, extension)
assert_match %r[^stream.*?#{Regexp.quote(extension)}], File.basename(@tempfile.path)
end
should "have the Tempfile contain the same data as the file" do
@file.rewind; @tempfile.rewind
assert_equal @file.read, @tempfile.read
end
end
end
end
...@@ -34,7 +34,7 @@ class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase ...@@ -34,7 +34,7 @@ class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase
end end
end end
context "validates_attachment_size with infinite range" do context "allowing anything" do
setup{ @matcher = self.class.validate_attachment_size(:avatar) } setup{ @matcher = self.class.validate_attachment_size(:avatar) }
context "given a class with an upper limit" do context "given a class with an upper limit" do
...@@ -42,7 +42,7 @@ class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase ...@@ -42,7 +42,7 @@ class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase
should_accept_dummy_class should_accept_dummy_class
end end
context "given a class with no upper limit" do context "given a class with a lower limit" do
setup { @dummy_class.validates_attachment_size :avatar, :greater_than => 1 } setup { @dummy_class.validates_attachment_size :avatar, :greater_than => 1 }
should_accept_dummy_class should_accept_dummy_class
end end
......
require './test/helper'
class NilAdapterTest < Test::Unit::TestCase
context 'a new instance' do
setup do
@subject = Paperclip.io_adapters.for(nil)
end
should "get the right filename" do
assert_equal "", @subject.original_filename
end
should "get the content type" do
assert_equal "", @subject.content_type
end
should "get the file's size" do
assert_equal 0, @subject.size
end
should "return true for a call to nil?" do
assert @subject.nil?
end
end
end
...@@ -23,20 +23,6 @@ class FileSystemTest < Test::Unit::TestCase ...@@ -23,20 +23,6 @@ class FileSystemTest < Test::Unit::TestCase
assert File.exists?(@dummy.avatar.path(:thumbnail)) assert File.exists?(@dummy.avatar.path(:thumbnail))
end end
should "clean up file objects" do
File.stubs(:exist?).returns(true)
Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
@dummy.save!
end
should "always be rewound when returning from #to_file" do
assert_equal 0, @dummy.avatar.to_file.pos
@dummy.avatar.to_file.seek(10)
assert_equal 0, @dummy.avatar.to_file.pos
end
context "with file that has space in file name" do context "with file that has space in file name" do
setup do setup do
rebuild_model :styles => { :thumbnail => "25x25#" } rebuild_model :styles => { :thumbnail => "25x25#" }
......
...@@ -56,14 +56,6 @@ class FogTest < Test::Unit::TestCase ...@@ -56,14 +56,6 @@ class FogTest < Test::Unit::TestCase
assert_equal File.expand_path(File.join(File.dirname(__FILE__), "../../public/avatars/5k.png")), assert_equal File.expand_path(File.join(File.dirname(__FILE__), "../../public/avatars/5k.png")),
@dummy.avatar.path @dummy.avatar.path
end end
should "clean up file objects" do
File.stubs(:exist?).returns(true)
Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
@dummy.save!
end
end end
setup do setup do
...@@ -110,12 +102,14 @@ class FogTest < Test::Unit::TestCase ...@@ -110,12 +102,14 @@ class FogTest < Test::Unit::TestCase
directory.destroy directory.destroy
end end
# NOTE: This might not be necessary, watch for this to error
should "always be rewound when returning from #to_file" do should "always be rewound when returning from #to_file" do
assert_equal 0, @dummy.avatar.to_file.pos assert_equal 0, @dummy.avatar.to_file.pos
@dummy.avatar.to_file.seek(10) @dummy.avatar.to_file.seek(10)
assert_equal 0, @dummy.avatar.to_file.pos assert_equal 0, @dummy.avatar.to_file.pos
end end
# NOTE: This might not be necessary, watch for this to error
should "rewind file in flush_writes" do should "rewind file in flush_writes" do
@dummy.avatar.queued_for_write.each { |style, file| file.expects(:rewind).with() } @dummy.avatar.queued_for_write.each { |style, file| file.expects(:rewind).with() }
@dummy.save @dummy.save
......
...@@ -46,10 +46,6 @@ unless ENV["S3_BUCKET"].blank? ...@@ -46,10 +46,6 @@ unless ENV["S3_BUCKET"].blank?
@dummy.destroy @dummy.destroy
end end
should "still return a Tempfile when sent #to_file" do
assert_equal Paperclip::Tempfile, @dummy.avatar.to_file.class
end
context "and saved" do context "and saved" do
setup do setup do
@dummy.save @dummy.save
...@@ -58,11 +54,6 @@ unless ENV["S3_BUCKET"].blank? ...@@ -58,11 +54,6 @@ unless ENV["S3_BUCKET"].blank?
should "be on S3" do should "be on S3" do
assert true assert true
end end
should "generate a tempfile with the right name" do
file = @dummy.avatar.to_file
assert_match /^original.*\.png$/, File.basename(file.path)
end
end end
end end
end end
......
...@@ -241,7 +241,7 @@ class S3Test < Test::Unit::TestCase ...@@ -241,7 +241,7 @@ class S3Test < Test::Unit::TestCase
'secret_access_key' => "54321" 'secret_access_key' => "54321"
} }
file = StringIO.new(".") file = Paperclip.io_adapters.for(StringIO.new("."))
file.original_filename = "question?mark.png" file.original_filename = "question?mark.png"
@dummy = Dummy.new @dummy = Dummy.new
@dummy.avatar = file @dummy.avatar = file
...@@ -336,17 +336,18 @@ class S3Test < Test::Unit::TestCase ...@@ -336,17 +336,18 @@ class S3Test < Test::Unit::TestCase
assert_match %r{^avatars/stringio\.txt}, @dummy.avatar.url assert_match %r{^avatars/stringio\.txt}, @dummy.avatar.url
end end
# NOTE: This might not be necessary, watch for this to error
should "always be rewound when returning from #to_file" do should "always be rewound when returning from #to_file" do
assert_equal 0, @dummy.avatar.to_file.pos assert_equal 0, @dummy.avatar.to_file.pos
@dummy.avatar.to_file.seek(10) @dummy.avatar.to_file.seek(10)
assert_equal 0, @dummy.avatar.to_file.pos assert_equal 0, @dummy.avatar.to_file.pos
end end
# NOTE: This might not be necessary, watch for this to error
should "rewind file in flush_writes" do should "rewind file in flush_writes" do
@dummy.avatar.queued_for_write.each { |style, file| file.expects(:rewind).with() } @dummy.avatar.queued_for_write.each { |style, file| file.expects(:rewind).with() }
@dummy.save @dummy.save
end end
end end
context "Generating a secure url with an expiration" do context "Generating a secure url with an expiration" do
...@@ -555,14 +556,6 @@ class S3Test < Test::Unit::TestCase ...@@ -555,14 +556,6 @@ class S3Test < Test::Unit::TestCase
end end
end end
should "delete tempfiles" do
File.stubs(:exist?).returns(true)
Paperclip::Tempfile.any_instance.expects(:close).at_least_once()
Paperclip::Tempfile.any_instance.expects(:unlink).at_least_once()
@dummy.save!
end
context "and saved without a bucket" do context "and saved without a bucket" do
setup do setup do
AWS::S3::BucketCollection.any_instance.expects(:create).with("testing") AWS::S3::BucketCollection.any_instance.expects(:create).with("testing")
...@@ -1065,13 +1058,6 @@ class S3Test < Test::Unit::TestCase ...@@ -1065,13 +1058,6 @@ class S3Test < Test::Unit::TestCase
context "and saved" do context "and saved" do
setup do setup do
[:thumb, :original].each do |style|
object = stub
@dummy.avatar.stubs(:s3_object).with(style).returns(object)
object.expects(:write).with(anything,
:content_type => "image/png",
:acl => style == :thumb ? :public_read : :private)
end
@dummy.save @dummy.save
end end
......
require './test/helper'
class StringioFileProxyTest < Test::Unit::TestCase
context "a new instance" do
setup do
@contents = "abc123"
@stringio = StringIO.new(@contents)
@subject = Paperclip.io_adapters.for(@stringio)
end
should "return a file name" do
assert_equal "stringio.txt", @subject.original_filename
end
should "allow us to set a name" do
@subject.original_filename = "data.txt"
assert_equal "data.txt", @subject.original_filename
end
should "return a content type" do
assert_equal "text/plain", @subject.content_type
end
should "allow us to set a content type" do
@subject.content_type = "image/jpg"
assert_equal "image/jpg", @subject.content_type
end
should "return the size of the data" do
assert_equal 6, @subject.size
end
should "generate an MD5 hash of the contents" do
assert_equal Digest::MD5.hexdigest(@contents), @subject.fingerprint
end
should "return the data contained in the StringIO" do
assert_equal "abc123", @subject.read
end
end
end
require './test/helper'
class UpfileTest < Test::Unit::TestCase
{ %w(jpg jpe jpeg) => 'image/jpeg',
%w(tif tiff) => 'image/tiff',
%w(png) => 'image/png',
%w(gif) => 'image/gif',
%w(bmp) => 'image/bmp',
%w(svg) => 'image/svg+xml',
%w(txt) => 'text/plain',
%w(htm html) => 'text/html',
%w(csv) => 'text/csv',
%w(xml) => 'application/xml',
%w(css) => 'text/css',
%w(js) => 'application/javascript',
%w(foo) => 'application/x-foo'
}.each do |extensions, content_type|
extensions.each do |extension|
should "return a content_type of #{content_type} for a file with extension .#{extension}" do
file = stub('file', :path => "basename.#{extension}")
class << file
include Paperclip::Upfile
end
assert_equal content_type, file.content_type
end
end
end
should "return a content_type of text/plain on a real file whose content_type is determined with the file command" do
file = File.new(File.join(File.dirname(__FILE__), "..", "LICENSE"))
class << file
include Paperclip::Upfile
end
assert_equal 'text/plain', file.content_type
end
{ '5k.png' => 'image/png',
'animated.gif' => 'image/gif',
'text.txt' => 'text/plain',
'twopage.pdf' => 'application/pdf'
}.each do |filename, content_type|
should "return a content type of #{content_type} from a file command for file #{filename}" do
file = File.new(File.join(File.dirname(__FILE__), "fixtures", filename))
class << file
include Paperclip::Upfile
end
assert_equal content_type, file.type_from_file_command
end
end
end
require './test/helper'
class UploadedFileAdapterTest < Test::Unit::TestCase
context "a new instance" do
setup do
class UploadedFile < OpenStruct; end
@file = UploadedFile.new(
:original_filename => "5k.png",
:content_type => "image/png",
:head => "",
:tempfile => File.new(fixture_file("5k.png"))
)
@subject = Paperclip.io_adapters.for(@file)
end
should "get the right filename" do
assert_equal "5k.png", @subject.original_filename
end
should "get the content type" do
assert_equal "image/png", @subject.content_type
end
should "get the file's size" do
assert_equal 4456, @subject.size
end
should "return false for a call to nil?" do
assert ! @subject.nil?
end
should "generate a MD5 hash of the contents" do
expected = Digest::MD5.file(@file.tempfile.path).to_s
assert_equal expected, @subject.fingerprint
end
should "read the contents of the file" do
expected = @file.tempfile.read
assert expected.length > 0
assert_equal expected, @subject.read
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