diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..f4ffa7d75 Binary files /dev/null and b/.DS_Store differ diff --git a/Gemfile.lock b/Gemfile.lock index 85284f63c..bb18324de 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -19,13 +19,10 @@ GEM activesupport (= 3.2.2) arel (~> 3.0.2) 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) i18n (~> 0.6) multi_json (~> 1.0) + addressable (2.2.7) appraisal (0.4.1) bundler rake @@ -40,7 +37,8 @@ GEM json (~> 1.4) nokogiri (<= 1.5.0) uuidtools (~> 2.1) - bouncy-castle-java (1.5.0146.1) + bourne (1.1.2) + mocha (= 0.10.5) builder (3.0.0) capybara (1.1.2) mime-types (>= 1.16) @@ -52,6 +50,7 @@ GEM childprocess (0.3.1) ffi (~> 1.0.6) cocaine (0.2.1) + coderay (1.0.5) cucumber (1.1.9) builder (>= 2.1.2) diff-lcs (>= 1.1.2) @@ -62,7 +61,6 @@ GEM excon (0.6.6) fakeweb (1.3.0) ffi (1.0.11) - ffi (1.0.11-java) fog (0.9.0) builder excon (~> 0.6.1) @@ -74,31 +72,30 @@ GEM nokogiri (>= 1.4.4) ruby-hmac formatador (0.2.1) - gherkin (2.9.1) - json (>= 1.4.6) - gherkin (2.9.1-java) + gherkin (2.9.3) json (>= 1.4.6) httparty (0.8.1) multi_json multi_xml i18n (0.6.0) - jdbc-sqlite3 (3.7.2) - jruby-openssl (0.7.6.1) - bouncy-castle-java (>= 1.5.0146.1) - json (1.6.5) - json (1.6.5-java) + json (1.6.6) + launchy (2.1.0) + addressable (~> 2.2.6) metaclass (0.0.1) + method_source (0.7.1) mime-types (1.18) mocha (0.10.5) metaclass (~> 0.0.1) - multi_json (1.1.0) + multi_json (1.2.0) multi_xml (0.4.2) net-scp (1.0.4) net-ssh (>= 1.99.1) net-ssh (2.3.0) nokogiri (1.4.7) - nokogiri (1.4.7-java) - weakling (>= 0.0.3) + pry (0.9.8.4) + coderay (~> 1.0.5) + method_source (~> 0.7.1) + slop (>= 2.4.4, < 3) rack (1.4.1) rack-test (0.6.1) rack (>= 1.0) @@ -123,16 +120,15 @@ GEM shoulda-matchers (~> 1.0.0) shoulda-context (1.0.0) shoulda-matchers (1.0.0) + slop (2.4.4) sqlite3 (1.3.5) term-ansicolor (1.0.7) tzinfo (0.3.32) uuidtools (2.1.2) - weakling (0.0.4-java) xpath (0.1.4) nokogiri (~> 1.3) PLATFORMS - java ruby DEPENDENCIES @@ -140,6 +136,7 @@ DEPENDENCIES appraisal (~> 0.4.0) aruba aws-sdk (~> 1.3.8) + bourne bundler capybara cocaine (~> 0.2) @@ -147,8 +144,11 @@ DEPENDENCIES fakeweb fog jruby-openssl + launchy mocha nokogiri (~> 1.4.7) paperclip! + pry + rake shoulda sqlite3 diff --git a/features/step_definitions/rails_steps.rb b/features/step_definitions/rails_steps.rb index eb6620aa4..b3d2e1cc6 100644 --- a/features/step_definitions/rails_steps.rb +++ b/features/step_definitions/rails_steps.rb @@ -1,3 +1,7 @@ +When /^I print "([^\"]*)"$/ do |whatever| + puts whatever +end + Given /^I generate a new rails application$/ do steps %{ When I run `bundle exec #{new_application_command} #{APP_NAME}` diff --git a/features/support/env.rb b/features/support/env.rb index 25fae50ba..6c075749d 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,6 +1,10 @@ require 'aruba/cucumber' require 'capybara/cucumber' require 'test/unit/assertions' +require 'pry' + +$CUCUMBER=1 + World(Test::Unit::Assertions) Before do diff --git a/images.rake b/images.rake new file mode 100644 index 000000000..6fec1b9ca --- /dev/null +++ b/images.rake @@ -0,0 +1,21 @@ +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 diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 000000000..fdfca3a8a Binary files /dev/null and b/lib/.DS_Store differ diff --git a/lib/paperclip.rb b/lib/paperclip.rb index 411f79ce4..3f5020dd1 100644 --- a/lib/paperclip.rb +++ b/lib/paperclip.rb @@ -29,8 +29,6 @@ require 'digest' require 'tempfile' require 'paperclip/version' -require 'paperclip/upfile' -require 'paperclip/iostream' require 'paperclip/geometry' require 'paperclip/processor' require 'paperclip/tempfile' @@ -49,6 +47,7 @@ require 'paperclip/logger' require 'paperclip/helpers' require 'paperclip/railtie' +require 'mime/types' require 'logger' require 'cocaine' @@ -203,3 +202,12 @@ def attachment_definitions 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' diff --git a/lib/paperclip/.DS_Store b/lib/paperclip/.DS_Store new file mode 100644 index 000000000..dab0e6f82 Binary files /dev/null and b/lib/paperclip/.DS_Store differ diff --git a/lib/paperclip/attachment.rb b/lib/paperclip/attachment.rb index 4286ff4f7..22181a5a9 100644 --- a/lib/paperclip/attachment.rb +++ b/lib/paperclip/attachment.rb @@ -7,8 +7,6 @@ module Paperclip # when the model saves, deletes when the model is destroyed, and processes # the file upon assignment. class Attachment - include IOStream - def self.default_options @default_options ||= { :convert_options => {}, @@ -90,29 +88,16 @@ def initialize(name, instance, options = {}) # new_user.avatar = old_user.avatar def assign uploaded_file 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 + return nil if file.nil? - return nil if uploaded_file.nil? - - uploaded_filename ||= uploaded_file.original_filename - stores_fingerprint = @instance.respond_to?("#{name}_fingerprint".to_sym) - @queued_for_write[:original] = to_tempfile(uploaded_file) - 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 + @queued_for_write[:original] = file + instance_write(:file_name, cleanup_filename(file.original_filename)) + instance_write(:content_type, file.content_type) + instance_write(:file_size, file.size) + instance_write(:fingerprint, file.fingerprint) if instance_respond_to?(:fingerprint) instance_write(:updated_at, Time.now) @dirty = true @@ -120,10 +105,8 @@ def assign uploaded_file post_process(*@options[:only_process]) if post_processing # Reset the file size if the original file was reprocessed. - instance_write(:file_size, @queued_for_write[:original].size.to_i) - instance_write(:fingerprint, generate_fingerprint(@queued_for_write[:original])) if stores_fingerprint - ensure - uploaded_file.close if close_uploaded_file + instance_write(:file_size, @queued_for_write[:original].size) + instance_write(:fingerprint, @queued_for_write[:original].fingerprint) if instance_respond_to?(:fingerprint) end # Returns the public URL of the attachment with a given style. This does @@ -252,16 +235,10 @@ def size instance_read(:file_size) || (@queued_for_write[:original] && @queued_for_write[:original].size) end - # Returns the hash of the file as originally assigned, and lives in the - # _fingerprint attribute of the model. + # Returns the fingerprint of the file, if one's defined. The fingerprint is + # stored in the _fingerpring attribute of the model. def fingerprint - if 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 + instance_read(:fingerprint) end # Returns the content_type of the file as originally assigned, and lives @@ -307,26 +284,16 @@ def generate_fingerprint(source) # thumbnails forcefully, by reobtaining the original file and going through # the post-process again. def reprocess!(*style_args) - new_original = Tempfile.new("paperclip-reprocess") - new_original.binmode - if old_original = to_file(:original) - 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) - + saved_only_process, @options[:only_process] = @options[:only_process], style_args + begin + assign(self) save - else - true + rescue Errno::EACCES => e + warn "#{e} - skipping file." + false + ensure + @options[:only_process] = saved_only_process end - rescue Errno::EACCES => e - warn "#{e} - skipping file" - false end # Returns true if a file has been assigned. @@ -336,6 +303,12 @@ def 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, # instance_write(:file_name, "me.jpg") will write "me.jpg" to the instance's # "avatar_file_name" field (assuming the attachment is called avatar). @@ -428,6 +401,7 @@ def post_process_style(name, style) #:nodoc: @queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor| Paperclip.processor(processor).make(file, style.processor_options, self) end + @queued_for_write[name] = Paperclip.io_adapters.for(@queued_for_write[name]) rescue Paperclip::Error => e log("An error was received while processing: #{e.inspect}") (@errors[:processing] ||= []) << e.message if @options[:whiny] @@ -463,8 +437,8 @@ def flush_errors #:nodoc: # called by storage after the writes are flushed and before @queued_for_writes is cleared def after_flush_writes @queued_for_write.each do |style, file| - file.close unless file.closed? - file.unlink if file.respond_to?(:unlink) && file.path.present? && File.exist?(file.path) + # file.close unless file.closed? + # file.unlink if file.respond_to?(:unlink) && file.path.present? && File.exist?(file.path) end end diff --git a/lib/paperclip/io_adapters/attachment_adapter.rb b/lib/paperclip/io_adapters/attachment_adapter.rb new file mode 100644 index 000000000..69ee55c3c --- /dev/null +++ b/lib/paperclip/io_adapters/attachment_adapter.rb @@ -0,0 +1,61 @@ +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 diff --git a/lib/paperclip/io_adapters/file_adapter.rb b/lib/paperclip/io_adapters/file_adapter.rb new file mode 100644 index 000000000..a4c523c6a --- /dev/null +++ b/lib/paperclip/io_adapters/file_adapter.rb @@ -0,0 +1,80 @@ +module Paperclip + class FileAdapter + def initialize(target) + @target = target + @tempfile = copy_to_tempfile(@target) + end + + def original_filename + if @target.respond_to?(:original_filename) + @target.original_filename + else + File.basename(@target.path) + end + end + + def content_type + types = MIME::Types.type_for(original_filename) + if types.length == 0 + type_from_file_command + elsif types.length == 1 + types.first.content_type + else + best_content_type_option(types) + end + end + + def fingerprint + @fingerprint ||= Digest::MD5.file(path).to_s + end + + def size + File.size(@tempfile) + end + + def nil? + @target.nil? + 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 + + 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 + +Paperclip.io_adapters.register Paperclip::FileAdapter do |target| + File === target || Tempfile === target +end diff --git a/lib/paperclip/io_adapters/identity_adapter.rb b/lib/paperclip/io_adapters/identity_adapter.rb new file mode 100644 index 000000000..1dc203488 --- /dev/null +++ b/lib/paperclip/io_adapters/identity_adapter.rb @@ -0,0 +1,12 @@ +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 + diff --git a/lib/paperclip/io_adapters/nil_adapter.rb b/lib/paperclip/io_adapters/nil_adapter.rb new file mode 100644 index 000000000..3df49e913 --- /dev/null +++ b/lib/paperclip/io_adapters/nil_adapter.rb @@ -0,0 +1,34 @@ +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 diff --git a/lib/paperclip/io_adapters/registry.rb b/lib/paperclip/io_adapters/registry.rb new file mode 100644 index 000000000..afc4fb516 --- /dev/null +++ b/lib/paperclip/io_adapters/registry.rb @@ -0,0 +1,32 @@ +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 diff --git a/lib/paperclip/io_adapters/stringio_adapter.rb b/lib/paperclip/io_adapters/stringio_adapter.rb new file mode 100644 index 000000000..9eea019f3 --- /dev/null +++ b/lib/paperclip/io_adapters/stringio_adapter.rb @@ -0,0 +1,59 @@ +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 diff --git a/lib/paperclip/io_adapters/uploaded_file_adapter.rb b/lib/paperclip/io_adapters/uploaded_file_adapter.rb new file mode 100644 index 000000000..3d6500a6e --- /dev/null +++ b/lib/paperclip/io_adapters/uploaded_file_adapter.rb @@ -0,0 +1,57 @@ +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 diff --git a/lib/paperclip/iostream.rb b/lib/paperclip/iostream.rb deleted file mode 100644 index d6d00ce55..000000000 --- a/lib/paperclip/iostream.rb +++ /dev/null @@ -1,45 +0,0 @@ -# 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 diff --git a/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb b/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb index fec6f0457..361b05cc5 100644 --- a/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +++ b/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb @@ -61,7 +61,7 @@ def description protected def type_allowed?(type) - file = StringIO.new(".") + file = Paperclip.io_adapters.for(StringIO.new(".")) file.content_type = type @subject.attachment_for(@attachment_name).assign(file) @subject.valid? diff --git a/lib/paperclip/railtie.rb b/lib/paperclip/railtie.rb index 8a1978013..0893cd044 100644 --- a/lib/paperclip/railtie.rb +++ b/lib/paperclip/railtie.rb @@ -25,8 +25,6 @@ def self.insert ActiveRecord::ConnectionAdapters::Table.send(:include, Paperclip::Schema) ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Paperclip::Schema) end - - File.send(:include, Paperclip::Upfile) end end end diff --git a/lib/paperclip/storage/filesystem.rb b/lib/paperclip/storage/filesystem.rb index c48ee59df..7ae9c39e2 100644 --- a/lib/paperclip/storage/filesystem.rb +++ b/lib/paperclip/storage/filesystem.rb @@ -27,23 +27,14 @@ def exists?(style_name = default_style) 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: @queued_for_write.each do |style_name, file| - file.close FileUtils.mkdir_p(File.dirname(path(style_name))) - log("saving #{path(style_name)}") - FileUtils.cp(file.path, path(style_name)) + File.open(path(style_name), "wb") do |new_file| + while chunk = file.read(16 * 1024) + new_file.write(chunk) + end + end FileUtils.chmod(0666&~File.umask, path(style_name)) end diff --git a/lib/paperclip/storage/fog.rb b/lib/paperclip/storage/fog.rb index f13bc5d9f..d8176ad84 100644 --- a/lib/paperclip/storage/fog.rb +++ b/lib/paperclip/storage/fog.rb @@ -84,7 +84,7 @@ def flush_writes :body => file, :key => path(style), :public => fog_public, - :content_type => file.content_type.to_s.strip + :content_type => file.content_type )) rescue Excon::Errors::NotFound raise if retried @@ -107,25 +107,6 @@ def flush_deletes @queued_for_delete = [] 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) if @options[:fog_host] host = if @options[:fog_host].respond_to?(:call) @@ -133,7 +114,7 @@ def public_url(style = default_style) else (@options[:fog_host] =~ /%d/) ? @options[:fog_host] % (path(style).hash % 4) : @options[:fog_host] end - + "#{host}/#{path(style)}" else if fog_credentials[:provider] == 'AWS' diff --git a/lib/paperclip/storage/s3.rb b/lib/paperclip/storage/s3.rb index 1db36325e..0cba6b86f 100644 --- a/lib/paperclip/storage/s3.rb +++ b/lib/paperclip/storage/s3.rb @@ -264,23 +264,6 @@ def s3_protocol(style = default_style) 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 s3_interface.buckets.create(bucket_name) end @@ -293,7 +276,7 @@ def flush_writes #:nodoc: acl = @s3_permissions[style] || @s3_permissions[:default] acl = acl.call(self, style) if acl.respond_to?(:call) write_options = { - :content_type => file.content_type.to_s.strip, + :content_type => file.content_type, :acl => acl } write_options[:metadata] = @s3_metadata unless @s3_metadata.empty? diff --git a/lib/paperclip/upfile.rb b/lib/paperclip/upfile.rb deleted file mode 100644 index df66cdd97..000000000 --- a/lib/paperclip/upfile.rb +++ /dev/null @@ -1,64 +0,0 @@ -require 'mime/types' - -module Paperclip - # The Upfile module is a convenience module for adding uploaded-file-type methods - # to the +File+ class. Useful for testing. - # user.avatar = File.new("test/test_avatar.jpg") - module Upfile - # Infer the MIME-type of the file from the extension. - def content_type - types = MIME::Types.type_for(self.original_filename) - if types.length == 0 - type_from_file_command - elsif types.length == 1 - types.first.content_type - else - iterate_over_array_to_find_best_option(types) - end - end - - def iterate_over_array_to_find_best_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 - - # Returns the file's normal name. - def original_filename - File.basename(self.path) - end - - # Returns the size of the file. - def size - File.size(self) - end - end -end - -if defined? StringIO - class StringIO - attr_accessor :original_filename, :content_type, :fingerprint - - def original_filename - @original_filename ||= "stringio.txt" - end - - def content_type - @content_type ||= "text/plain" - end - - def fingerprint - @fingerprint ||= Digest::MD5.hexdigest(self.string) - end - end -end - -class File #:nodoc: - include Paperclip::Upfile -end diff --git a/lib/tasks/paperclip.rake b/lib/tasks/paperclip.rake index 388bdfdf2..e8504510e 100644 --- a/lib/tasks/paperclip.rake +++ b/lib/tasks/paperclip.rake @@ -45,7 +45,7 @@ namespace :paperclip do names = Paperclip::Task.obtain_attachments(klass) names.each do |name| 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}_content_type=", file.content_type.to_s.strip) instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size") diff --git a/paperclip.gemspec b/paperclip.gemspec index dcb3fae80..f72815f16 100644 --- a/paperclip.gemspec +++ b/paperclip.gemspec @@ -34,6 +34,8 @@ Gem::Specification.new do |s| s.add_development_dependency('appraisal', '~> 0.4.0') s.add_development_dependency('mocha') 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('aruba') s.add_development_dependency('nokogiri', '~> 1.4.7') @@ -41,5 +43,8 @@ Gem::Specification.new do |s| s.add_development_dependency('bundler') s.add_development_dependency('cocaine', '~> 0.2') 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') end diff --git a/test/adapter_registry_test.rb b/test/adapter_registry_test.rb new file mode 100644 index 000000000..6ead08a36 --- /dev/null +++ b/test/adapter_registry_test.rb @@ -0,0 +1,32 @@ +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 diff --git a/test/attachment_adapter_test.rb b/test/attachment_adapter_test.rb new file mode 100644 index 000000000..87e44cb6d --- /dev/null +++ b/test/attachment_adapter_test.rb @@ -0,0 +1,42 @@ +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 diff --git a/test/attachment_test.rb b/test/attachment_test.rb index 46f270721..06523811d 100644 --- a/test/attachment_test.rb +++ b/test/attachment_test.rb @@ -678,10 +678,7 @@ def do_after_all; end @file = StringIO.new(".") @file.stubs(:original_filename).returns("5k.png\n\n") @file.stubs(:content_type).returns("image/png\n\n") - @file.stubs(:to_tempfile).returns(@file) @dummy = Dummy.new - Paperclip::Thumbnail.expects(:make).returns(@file) - @attachment = @dummy.avatar @dummy.avatar = @file end @@ -698,23 +695,12 @@ def do_after_all; end setup do rebuild_model - @not_file = mock("not_file") - @tempfile = mock("tempfile") - @not_file.stubs(:nil?).returns(false) - @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") + @file = StringIO.new(".") + @file.stubs(:original_filename).returns("sheep_say_bæ.png\r\n") + @file.stubs(:content_type).returns("image/png\r\n") @dummy = Dummy.new - @attachment = @dummy.avatar - @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 + @dummy.avatar = @file end should "not remove strange letters" do @@ -725,14 +711,14 @@ def do_after_all; end context "Attachment with reserved filename" do setup do rebuild_model - @file = StringIO.new(".") + @file = Paperclip.io_adapters.for(StringIO.new(".")) end context "with default configuration" do "&$+,/:;=?@<>[]{}|\^~%# ".split(//).each do |character| context "with character #{character}" do setup do - @file.stubs(:original_filename).returns("file#{character}name.png") + @file.original_filename = "file#{character}name.png" @dummy = Dummy.new @dummy.avatar = @file end @@ -796,11 +782,8 @@ def do_after_all; end end 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(:small), @attachment.url(:small) - file.close end end @@ -831,7 +814,6 @@ def do_after_all; end end 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(:blah) end @@ -886,10 +868,6 @@ def do_after_all; end assert @attachment.dirty? end - should "set uploaded_file for access beyond the paperclip lifecycle" do - assert_equal @file, @attachment.uploaded_file - end - context "and saved" do setup do @attachment.save @@ -897,11 +875,7 @@ def do_after_all; end should "commit the files to disk" do [:large, :medium, :small].each do |style| - io = @attachment.to_file(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 + assert File.exists?(@attachment.path(style)) end end @@ -918,11 +892,6 @@ def do_after_all; 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 setup do @existing_names = @attachment.styles.keys.collect do |style| @@ -1047,7 +1016,7 @@ def do_after_all; end should "return the right value when sent #avatar_file_size" do @dummy.avatar = @file - assert_equal @file.size, @dummy.avatar.size + assert_equal File.size(@file), @dummy.avatar.size end context "and avatar_updated_at column" do @@ -1068,18 +1037,12 @@ def do_after_all; end assert_equal now.to_i, @dummy.avatar.updated_at end end - - should "not calculate fingerprint after save" do - @dummy.avatar = @file - @dummy.save - assert_nil @dummy.avatar.fingerprint - end - - should "not calculate fingerprint before saving" do + + should "not calculate fingerprint" do @dummy.avatar = @file assert_nil @dummy.avatar.fingerprint end - + context "and avatar_content_type column" do setup do ActiveRecord::Base.connection.add_column :dummies, :avatar_content_type, :string @@ -1110,14 +1073,14 @@ def do_after_all; end should "return the right value when sent #avatar_file_size" do @dummy.avatar = @file - assert_equal @file.size, @dummy.avatar.size + assert_equal File.size(@file), @dummy.avatar.size end should "return the right value when saved, reloaded, and sent #avatar_file_size" do @dummy.avatar = @file @dummy.save @dummy = Dummy.find(@dummy.id) - assert_equal @file.size, @dummy.avatar.size + assert_equal File.size(@file), @dummy.avatar.size end end diff --git a/test/file_adapter_test.rb b/test/file_adapter_test.rb new file mode 100644 index 000000000..f9e1ee22b --- /dev/null +++ b/test/file_adapter_test.rb @@ -0,0 +1,38 @@ +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 diff --git a/test/helper.rb b/test/helper.rb index c8e6248bf..e627f22ca 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -5,6 +5,7 @@ require 'shoulda' require 'mocha' +require 'bourne' require 'active_record' require 'active_record/version' @@ -13,6 +14,9 @@ require 'mime/types' require 'pathname' +require 'pathname' +require 'pry' + puts "Testing against version #{ActiveRecord::VERSION::STRING}" `ruby -e 'exit 0'` # Prime $? with a value. diff --git a/test/identity_adapter_test.rb b/test/identity_adapter_test.rb new file mode 100644 index 000000000..ad26b2ecb --- /dev/null +++ b/test/identity_adapter_test.rb @@ -0,0 +1,8 @@ +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 diff --git a/test/integration_test.rb b/test/integration_test.rb index 6ac8fa1c7..31961cd5a 100644 --- a/test/integration_test.rb +++ b/test/integration_test.rb @@ -54,7 +54,6 @@ class IntegrationTest < Test::Unit::TestCase context "redefining its attachment styles" do setup do Dummy.class_eval do - has_attached_file :avatar, :styles => { :thumb => "150x25#" } has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } } end @d2 = Dummy.find(@dummy.id) @@ -71,20 +70,6 @@ class IntegrationTest < Test::Unit::TestCase should "change the timestamp" do assert_not_equal @original_timestamp, @d2.avatar_updated_at 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 @@ -171,7 +156,7 @@ class IntegrationTest < Test::Unit::TestCase end 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 teardown { @file.close } @@ -287,6 +272,27 @@ class IntegrationTest < Test::Unit::TestCase 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 setup do rebuild_model :styles => { :large => "300x300>", @@ -322,8 +328,6 @@ class IntegrationTest < Test::Unit::TestCase assert_equal "100x15", `identify -format "%wx%h" "#{@d2.avatar.path(:medium)}"`.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.save @@ -362,13 +366,13 @@ class IntegrationTest < Test::Unit::TestCase end end - should "know the difference between good files, bad files, and not files" do - expected = @dummy.avatar.to_file - @dummy.avatar = "not a file" - assert @dummy.valid? - assert_equal expected.path, @dummy.avatar.path - expected.close + should "not abide things that don't have adapters" do + assert_raises(Paperclip::AdapterRegistry::NoHandlerError) do + @dummy.avatar = "not a file" + end + end + should "not be ok with bad files" do @dummy.avatar = @bad_file assert ! @dummy.valid? end @@ -384,31 +388,13 @@ class IntegrationTest < Test::Unit::TestCase should "be able to reload without saving and not have the file disappear" do @dummy.avatar = @file - assert @dummy.save + assert @dummy.save, @dummy.errors.full_messages.inspect @dummy.avatar.clear assert_nil @dummy.avatar_file_name @dummy.reload assert_equal "5k.png", @dummy.avatar_file_name 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 setup do @dummy2 = Dummy.new @@ -423,9 +409,9 @@ class IntegrationTest < Test::Unit::TestCase assert @dummy.avatar = @dummy2.avatar @dummy.save + assert_equal @dummy.avatar_file_name, @dummy2.avatar_file_name assert_equal `identify -format "%wx%h" "#{@dummy.avatar.path(:original)}"`, `identify -format "%wx%h" "#{@dummy2.avatar.path(:original)}"` - assert_equal @dummy.avatar_file_name, @dummy2.avatar_file_name end end @@ -505,7 +491,6 @@ def s3_headers_for attachment, style end should "have the same contents as the original" do - @file.rewind assert_equal @file.read, @files_on_s3[:original].read end diff --git a/test/iostream_test.rb b/test/iostream_test.rb deleted file mode 100644 index 15ef5c5f4..000000000 --- a/test/iostream_test.rb +++ /dev/null @@ -1,71 +0,0 @@ -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 diff --git a/test/matchers/validate_attachment_size_matcher_test.rb b/test/matchers/validate_attachment_size_matcher_test.rb index 82d630e06..636b766ed 100644 --- a/test/matchers/validate_attachment_size_matcher_test.rb +++ b/test/matchers/validate_attachment_size_matcher_test.rb @@ -34,7 +34,7 @@ class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase end end - context "validates_attachment_size with infinite range" do + context "allowing anything" do setup{ @matcher = self.class.validate_attachment_size(:avatar) } context "given a class with an upper limit" do @@ -42,7 +42,7 @@ class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase should_accept_dummy_class 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 } should_accept_dummy_class end diff --git a/test/nil_adapter_test.rb b/test/nil_adapter_test.rb new file mode 100644 index 000000000..746d22b33 --- /dev/null +++ b/test/nil_adapter_test.rb @@ -0,0 +1,25 @@ +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 diff --git a/test/storage/filesystem_test.rb b/test/storage/filesystem_test.rb index 704b4b7ad..66af5ad5d 100644 --- a/test/storage/filesystem_test.rb +++ b/test/storage/filesystem_test.rb @@ -23,20 +23,6 @@ class FileSystemTest < Test::Unit::TestCase assert File.exists?(@dummy.avatar.path(:thumbnail)) 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 setup do rebuild_model :styles => { :thumbnail => "25x25#" } diff --git a/test/storage/fog_test.rb b/test/storage/fog_test.rb index a84313d65..d4bdbf32c 100644 --- a/test/storage/fog_test.rb +++ b/test/storage/fog_test.rb @@ -56,14 +56,6 @@ class FogTest < Test::Unit::TestCase assert_equal File.expand_path(File.join(File.dirname(__FILE__), "../../public/avatars/5k.png")), @dummy.avatar.path 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 setup do @@ -110,12 +102,14 @@ class FogTest < Test::Unit::TestCase directory.destroy end + # NOTE: This might not be necessary, watch for this to error 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 + # NOTE: This might not be necessary, watch for this to error should "rewind file in flush_writes" do @dummy.avatar.queued_for_write.each { |style, file| file.expects(:rewind).with() } @dummy.save diff --git a/test/storage/s3_live_test.rb b/test/storage/s3_live_test.rb index 540830cb0..9b9751c07 100644 --- a/test/storage/s3_live_test.rb +++ b/test/storage/s3_live_test.rb @@ -46,10 +46,6 @@ class S3LiveTest < Test::Unit::TestCase @dummy.destroy 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 setup do @dummy.save @@ -58,11 +54,6 @@ class S3LiveTest < Test::Unit::TestCase should "be on S3" do assert true 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 diff --git a/test/storage/s3_test.rb b/test/storage/s3_test.rb index d880eab81..310078c18 100644 --- a/test/storage/s3_test.rb +++ b/test/storage/s3_test.rb @@ -241,7 +241,7 @@ def teardown 'secret_access_key' => "54321" } - file = StringIO.new(".") + file = Paperclip.io_adapters.for(StringIO.new(".")) file.original_filename = "question?mark.png" @dummy = Dummy.new @dummy.avatar = file @@ -336,17 +336,18 @@ def counter assert_match %r{^avatars/stringio\.txt}, @dummy.avatar.url end + # NOTE: This might not be necessary, watch for this to error 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 + # NOTE: This might not be necessary, watch for this to error should "rewind file in flush_writes" do @dummy.avatar.queued_for_write.each { |style, file| file.expects(:rewind).with() } @dummy.save end - end context "Generating a secure url with an expiration" do @@ -555,14 +556,6 @@ def counter 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 setup do AWS::S3::BucketCollection.any_instance.expects(:create).with("testing") @@ -1065,13 +1058,6 @@ def counter context "and saved" 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 end diff --git a/test/stringio_adapter_test.rb b/test/stringio_adapter_test.rb new file mode 100644 index 000000000..83e9faaf8 --- /dev/null +++ b/test/stringio_adapter_test.rb @@ -0,0 +1,42 @@ +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 diff --git a/test/upfile_test.rb b/test/upfile_test.rb deleted file mode 100644 index 45a1c21b8..000000000 --- a/test/upfile_test.rb +++ /dev/null @@ -1,53 +0,0 @@ -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 diff --git a/test/uploaded_file_adapter_test.rb b/test/uploaded_file_adapter_test.rb new file mode 100644 index 000000000..1662e12d3 --- /dev/null +++ b/test/uploaded_file_adapter_test.rb @@ -0,0 +1,45 @@ +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