Skip to content
Browse files

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

Needs work for S3 Attachments.
  • Loading branch information...
1 parent 6388652 commit 89c8d117e756815333a0e46d387cd64a1f4d37ab @jyurek jyurek committed Dec 2, 2011
Showing with 723 additions and 511 deletions.
  1. BIN .DS_Store
  2. +19 −19 Gemfile.lock
  3. +4 −0 features/step_definitions/rails_steps.rb
  4. +4 −0 features/support/env.rb
  5. +21 −0 images.rake
  6. BIN lib/.DS_Store
  7. +10 −2 lib/paperclip.rb
  8. BIN lib/paperclip/.DS_Store
  9. +29 −55 lib/paperclip/attachment.rb
  10. +61 −0 lib/paperclip/io_adapters/attachment_adapter.rb
  11. +80 −0 lib/paperclip/io_adapters/file_adapter.rb
  12. +12 −0 lib/paperclip/io_adapters/identity_adapter.rb
  13. +34 −0 lib/paperclip/io_adapters/nil_adapter.rb
  14. +32 −0 lib/paperclip/io_adapters/registry.rb
  15. +59 −0 lib/paperclip/io_adapters/stringio_adapter.rb
  16. +57 −0 lib/paperclip/io_adapters/uploaded_file_adapter.rb
  17. +0 −45 lib/paperclip/iostream.rb
  18. +1 −1 lib/paperclip/matchers/validate_attachment_content_type_matcher.rb
  19. +0 −2 lib/paperclip/railtie.rb
  20. +5 −14 lib/paperclip/storage/filesystem.rb
  21. +2 −21 lib/paperclip/storage/fog.rb
  22. +1 −18 lib/paperclip/storage/s3.rb
  23. +0 −64 lib/paperclip/upfile.rb
  24. +1 −1 lib/tasks/paperclip.rake
  25. +5 −0 paperclip.gemspec
  26. +32 −0 test/adapter_registry_test.rb
  27. +42 −0 test/attachment_adapter_test.rb
  28. +13 −50 test/attachment_test.rb
  29. +38 −0 test/file_adapter_test.rb
  30. +4 −0 test/helper.rb
  31. +8 −0 test/identity_adapter_test.rb
  32. +30 −45 test/integration_test.rb
  33. +0 −71 test/iostream_test.rb
  34. +2 −2 test/matchers/validate_attachment_size_matcher_test.rb
  35. +25 −0 test/nil_adapter_test.rb
  36. +0 −14 test/storage/filesystem_test.rb
  37. +2 −8 test/storage/fog_test.rb
  38. +0 −9 test/storage/s3_live_test.rb
  39. +3 −17 test/storage/s3_test.rb
  40. +42 −0 test/stringio_adapter_test.rb
  41. +0 −53 test/upfile_test.rb
  42. +45 −0 test/uploaded_file_adapter_test.rb
View
BIN .DS_Store
Binary file not shown.
View
38 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,32 +120,35 @@ 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
activerecord-jdbcsqlite3-adapter
appraisal (~> 0.4.0)
aruba
aws-sdk (~> 1.3.8)
+ bourne
bundler
capybara
cocaine (~> 0.2)
cucumber (~> 1.1.0)
fakeweb
fog
jruby-openssl
+ launchy
mocha
nokogiri (~> 1.4.7)
paperclip!
+ pry
+ rake
shoulda
sqlite3
View
4 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}`
View
4 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
View
21 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
View
BIN lib/.DS_Store
Binary file not shown.
View
12 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'
View
BIN lib/paperclip/.DS_Store
Binary file not shown.
View
84 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,40 +88,25 @@ 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)
@yury
yury added a note Mar 31, 2012

this line should be instance_write(:content_type, file.content_type.to_s)
some times content_type is Mime::Type and that couse errors with postgresql.

f = File.open("spec/fixtures/big_good_file.xls") 
f.content_type
=> application/vnd.ms-excel
f.content_type.class
=> MIME::Type
@masterkain
masterkain added a note Apr 1, 2012

why this has to break everytime. everytime paperclip gets upgraded something like this break, are there no specs to catch this?

@sikachu
thoughtbot, inc. member
sikachu added a note Apr 4, 2012

We offload those stuff to the IOAdapter, so removing from here does make sense. However, I'm not sure why it returns the content type as a MIME::Type object though.

irb(main):001:0> File.open('log/development.log').content_type
=> "text/plain"
irb(main):002:0> File.open('log/development.log').content_type.class
=> String

I'll make sure to call #to_s in #805 though.

@sikachu
thoughtbot, inc. member
sikachu added a note Apr 4, 2012

Interesting.

irb(main):002:0> File.open('/Users/sikachu/Downloads/foo.xls').content_type
=> application/vnd.ms-excel
irb(main):003:0> File.open('/Users/sikachu/Downloads/foo.xls').content_type.class
=> MIME::Type

I like how sneaky this is. I'll definitely fix this. Sorry for the trouble, and thanks for reporting :D

@jyurek
thoughtbot, inc. member
jyurek added a note Apr 24, 2012

I've made sure to add a new test for this to prevent further regressions in 8b778b3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ instance_write(:file_size, file.size)
+ instance_write(:fingerprint, file.fingerprint) if instance_respond_to?(:fingerprint)
instance_write(:updated_at, Time.now)
@dirty = true
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
- # <attachment>_fingerprint attribute of the model.
+ # Returns the fingerprint of the file, if one's defined. The fingerprint is
+ # stored in the <attachment>_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
View
61 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
View
80 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
View
12 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
+
View
34 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
View
32 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
View
59 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
View
57 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
View
45 lib/paperclip/iostream.rb
@@ -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
View
2 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?
View
2 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
View
19 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
View
23 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,33 +107,14 @@ 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)
@options[:fog_host].call(self)
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'
View
19 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
@donaldpiret
donaldpiret added a note Apr 23, 2012

What should we use to replace this now that it's gone? Not entirely clear why this was removed

@sikachu
thoughtbot, inc. member
sikachu added a note Apr 23, 2012

You can use IO Adapter.

Paperclip.io_adapters.for(object.attachment)

See #833

@donaldpiret
donaldpiret added a note Apr 24, 2012

How do we reference particular styles though? you were able to do to_file(:slide_show), don't see how to replicate this with the io adapters

@donaldpiret
donaldpiret added a note Apr 24, 2012

Ok, seems like you can do Paperclip.io_adapters.for(object.attachment.styles[:style_name].attachment), but this will not work for original so you have to test for that first.
This seems like a big step backwards from the previously available to_file method though...

@donaldpiret
donaldpiret added a note Apr 24, 2012

Scratch that, that doesn't actually work, it references the original attachment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
- 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?
View
64 lib/paperclip/upfile.rb
@@ -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
View
2 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")
View
5 paperclip.gemspec
@@ -34,12 +34,17 @@ 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')
s.add_development_dependency('capybara')
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
View
32 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
View
42 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
View
63 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,22 +868,14 @@ 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
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
View
38 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
View
4 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.
View
8 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
View
75 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
View
71 test/iostream_test.rb
@@ -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
View
4 test/matchers/validate_attachment_size_matcher_test.rb
@@ -34,15 +34,15 @@ 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
setup { @dummy_class.validates_attachment_size :avatar, :less_than => 1 }
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
View
25 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
View
14 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#" }
View
10 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
View
9 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
View
20 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
View
42 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
View
53 test/upfile_test.rb
@@ -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
View
45 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

1 comment on commit 89c8d11

@edison
edison commented on 89c8d11 Mar 31, 2012

I think that something in this commit are causing this error for me:

NoMethodError: undefined method `tempfile' for #<Tempfile:0x000001030b1ce8>
    /Users/edison/.rvm/gems/ruby-1.9.2-p290/gems/rack-test-0.6.1/lib/rack/test/uploaded_file.rb:40:in `method_missing'
    /Users/edison/.rvm/gems/ruby-1.9.2-p290/gems/paperclip-3.0.1/lib/paperclip/io_adapters/uploaded_file_adapter.rb:5:in `initialize'
    /Users/edison/.rvm/gems/ruby-1.9.2-p290/gems/paperclip-3.0.1/lib/paperclip/io_adapters/registry.rb:29:in `new'
    /Users/edison/.rvm/gems/ruby-1.9.2-p290/gems/paperclip-3.0.1/lib/paperclip/io_adapters/registry.rb:29:in `for'
    /Users/edison/.rvm/gems/ruby-1.9.2-p290/gems/paperclip-3.0.1/lib/paperclip/attachment.rb:91:in `assign'
    /Users/edison/.rvm/gems/ruby-1.9.2-p290/gems/paperclip-3.0.1/lib/paperclip.rb:193:in `block in has_attached_file'
    ...
Please sign in to comment.
Something went wrong with that request. Please try again.