Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of git://github.com/thoughtbot/paperclip

  • Loading branch information...
commit 1b8bb3c3d223f2f3c332cf0fb5f8c30acc5ca1b8 2 parents 289d9cf + e23d7f5
@tilsammans tilsammans authored
Showing with 450 additions and 166 deletions.
  1. +3 −0  .gitignore
  2. +8 −0 Appraisals
  3. +8 −0 Gemfile
  4. +37 −0 Gemfile.lock
  5. +7 −1 README.rdoc
  6. +6 −2 Rakefile
  7. +11 −0 gemfiles/rails2.gemfile
  8. +56 −0 gemfiles/rails2.gemfile.lock
  9. +11 −0 gemfiles/rails3.gemfile
  10. +97 −0 gemfiles/rails3.gemfile.lock
  11. +18 −9 lib/paperclip.rb
  12. +15 −9 lib/paperclip/attachment.rb
  13. +1 −1  lib/paperclip/command_line.rb
  14. +2 −1  lib/paperclip/interpolations.rb
  15. +10 −24 lib/paperclip/iostream.rb
  16. +13 −4 lib/paperclip/processor.rb
  17. +1 −1  lib/paperclip/railtie.rb
  18. +2 −0  lib/paperclip/storage.rb
  19. +1 −0  lib/paperclip/storage/filesystem.rb
  20. +12 −1 lib/paperclip/storage/s3.rb
  21. +1 −1  lib/paperclip/thumbnail.rb
  22. +0 −5 lib/paperclip/upfile.rb
  23. +1 −1  lib/paperclip/version.rb
  24. +36 −43 lib/tasks/paperclip.rake
  25. +1 −0  paperclip.gemspec
  26. +8 −8 test/attachment_test.rb
  27. +16 −11 test/command_line_test.rb
  28. +1 −1  test/geometry_test.rb
  29. +5 −17 test/helper.rb
  30. +1 −1  test/integration_test.rb
  31. +1 −1  test/interpolations_test.rb
  32. +6 −13 test/iostream_test.rb
  33. +1 −1  test/matchers/have_attached_file_matcher_test.rb
  34. +1 −1  test/matchers/validate_attachment_content_type_matcher_test.rb
  35. +1 −1  test/matchers/validate_attachment_presence_matcher_test.rb
  36. +1 −1  test/matchers/validate_attachment_size_matcher_test.rb
  37. +24 −1 test/paperclip_test.rb
  38. +1 −1  test/processor_test.rb
  39. +21 −1 test/storage_test.rb
  40. +1 −1  test/style_test.rb
  41. +2 −2 test/thumbnail_test.rb
  42. +1 −1  test/upfile_test.rb
View
3  .gitignore
@@ -5,3 +5,6 @@ test/s3.yml
public
paperclip*.gem
capybara*.html
+*.rbc
+.bundle
+*SPIKE*
View
8 Appraisals
@@ -0,0 +1,8 @@
+appraise "rails2" do
+ gem "rails", "~>2.3.0"
+end
+
+appraise "rails3" do
+ gem "rails", "~>3.0.0"
+end
+
View
8 Gemfile
@@ -0,0 +1,8 @@
+source "http://rubygems.org"
+gem "shoulda"
+gem "mocha"
+gem "rake"
+gem "ruby-debug"
+gem "aws-s3", :require => "aws/s3"
+gem "sqlite3-ruby", "~>1.3.0"
+gem "appraisal"
View
37 Gemfile.lock
@@ -0,0 +1,37 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ appraisal (0.1)
+ bundler
+ rake
+ aws-s3 (0.6.2)
+ builder
+ mime-types
+ xml-simple
+ builder (3.0.0)
+ columnize (0.3.2)
+ linecache (0.43)
+ mime-types (1.16)
+ mocha (0.9.9)
+ rake
+ rake (0.8.7)
+ ruby-debug (0.10.4)
+ columnize (>= 0.1)
+ ruby-debug-base (~> 0.10.4.0)
+ ruby-debug-base (0.10.4)
+ linecache (>= 0.3)
+ shoulda (2.11.3)
+ sqlite3-ruby (1.3.2)
+ xml-simple (1.0.12)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ appraisal
+ aws-s3
+ mocha
+ rake
+ ruby-debug
+ shoulda
+ sqlite3-ruby (~> 1.3.0)
View
8 README.rdoc
@@ -15,7 +15,13 @@ useful defaults.
See the documentation for +has_attached_file+ in Paperclip::ClassMethods for
more detailed options.
-The complete RDoc[http://rdoc.info/projects/thoughtbot/paperclip] is online.
+The complete RDoc[http://rdoc.info/gems/paperclip] is online.
+
+==Installation
+
+Include the gem in your Gemfile:
+
+ gem "paperclip", "~> 2.3"
==Installation
View
8 Rakefile
@@ -1,3 +1,7 @@
+require 'rubygems'
+require 'appraisal'
+require 'bundler/setup'
+
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'
@@ -6,11 +10,11 @@ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
require 'paperclip'
desc 'Default: run unit tests.'
-task :default => [:clean, :test]
+task :default => [:clean, :all]
desc 'Test the paperclip plugin under all supported Rails versions.'
task :all do |t|
- exec('rake RAILS_VERSION=2.1 && rake RAILS_VERSION=2.3 && rake RAILS_VERSION=3.0')
+ exec('rake appraisal test')
end
desc 'Test the paperclip plugin.'
View
11 gemfiles/rails2.gemfile
@@ -0,0 +1,11 @@
+# This file was generated by Appraisal
+
+source "http://rubygems.org"
+gem "ruby-debug"
+gem "rails", "~>2.3.0"
+gem "rake"
+gem "sqlite3-ruby", "~>1.3.0"
+gem "shoulda"
+gem "mocha"
+gem "aws-s3", {:require=>"aws/s3"}
+gem "appraisal"
View
56 gemfiles/rails2.gemfile.lock
@@ -0,0 +1,56 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ actionmailer (2.3.10)
+ actionpack (= 2.3.10)
+ actionpack (2.3.10)
+ activesupport (= 2.3.10)
+ rack (~> 1.1.0)
+ activerecord (2.3.10)
+ activesupport (= 2.3.10)
+ activeresource (2.3.10)
+ activesupport (= 2.3.10)
+ activesupport (2.3.10)
+ appraisal (0.1)
+ bundler
+ rake
+ aws-s3 (0.6.2)
+ builder
+ mime-types
+ xml-simple
+ builder (3.0.0)
+ columnize (0.3.2)
+ linecache (0.43)
+ mime-types (1.16)
+ mocha (0.9.9)
+ rake
+ rack (1.1.0)
+ rails (2.3.10)
+ actionmailer (= 2.3.10)
+ actionpack (= 2.3.10)
+ activerecord (= 2.3.10)
+ activeresource (= 2.3.10)
+ activesupport (= 2.3.10)
+ rake (>= 0.8.3)
+ rake (0.8.7)
+ ruby-debug (0.10.4)
+ columnize (>= 0.1)
+ ruby-debug-base (~> 0.10.4.0)
+ ruby-debug-base (0.10.4)
+ linecache (>= 0.3)
+ shoulda (2.11.3)
+ sqlite3-ruby (1.3.2)
+ xml-simple (1.0.12)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ appraisal
+ aws-s3
+ mocha
+ rails (~> 2.3.0)
+ rake
+ ruby-debug
+ shoulda
+ sqlite3-ruby (~> 1.3.0)
View
11 gemfiles/rails3.gemfile
@@ -0,0 +1,11 @@
+# This file was generated by Appraisal
+
+source "http://rubygems.org"
+gem "ruby-debug"
+gem "rails", ">=3.0.3"
+gem "rake"
+gem "sqlite3-ruby", "~>1.3.0"
+gem "shoulda"
+gem "mocha"
+gem "aws-s3", {:require=>"aws/s3"}
+gem "appraisal"
View
97 gemfiles/rails3.gemfile.lock
@@ -0,0 +1,97 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ abstract (1.0.0)
+ actionmailer (3.0.3)
+ actionpack (= 3.0.3)
+ mail (~> 2.2.9)
+ actionpack (3.0.3)
+ activemodel (= 3.0.3)
+ activesupport (= 3.0.3)
+ builder (~> 2.1.2)
+ erubis (~> 2.6.6)
+ i18n (~> 0.4)
+ rack (~> 1.2.1)
+ rack-mount (~> 0.6.13)
+ rack-test (~> 0.5.6)
+ tzinfo (~> 0.3.23)
+ activemodel (3.0.3)
+ activesupport (= 3.0.3)
+ builder (~> 2.1.2)
+ i18n (~> 0.4)
+ activerecord (3.0.3)
+ activemodel (= 3.0.3)
+ activesupport (= 3.0.3)
+ arel (~> 2.0.2)
+ tzinfo (~> 0.3.23)
+ activeresource (3.0.3)
+ activemodel (= 3.0.3)
+ activesupport (= 3.0.3)
+ activesupport (3.0.3)
+ appraisal (0.1)
+ bundler
+ rake
+ arel (2.0.4)
+ aws-s3 (0.6.2)
+ builder
+ mime-types
+ xml-simple
+ builder (2.1.2)
+ columnize (0.3.2)
+ erubis (2.6.6)
+ abstract (>= 1.0.0)
+ i18n (0.4.2)
+ linecache (0.43)
+ mail (2.2.10)
+ activesupport (>= 2.3.6)
+ i18n (~> 0.4.1)
+ mime-types (~> 1.16)
+ treetop (~> 1.4.8)
+ mime-types (1.16)
+ mocha (0.9.9)
+ rake
+ polyglot (0.3.1)
+ rack (1.2.1)
+ rack-mount (0.6.13)
+ rack (>= 1.0.0)
+ rack-test (0.5.6)
+ rack (>= 1.0)
+ rails (3.0.3)
+ actionmailer (= 3.0.3)
+ actionpack (= 3.0.3)
+ activerecord (= 3.0.3)
+ activeresource (= 3.0.3)
+ activesupport (= 3.0.3)
+ bundler (~> 1.0)
+ railties (= 3.0.3)
+ railties (3.0.3)
+ actionpack (= 3.0.3)
+ activesupport (= 3.0.3)
+ rake (>= 0.8.7)
+ thor (~> 0.14.4)
+ rake (0.8.7)
+ ruby-debug (0.10.4)
+ columnize (>= 0.1)
+ ruby-debug-base (~> 0.10.4.0)
+ ruby-debug-base (0.10.4)
+ linecache (>= 0.3)
+ shoulda (2.11.3)
+ sqlite3-ruby (1.3.2)
+ thor (0.14.6)
+ treetop (1.4.9)
+ polyglot (>= 0.3.1)
+ tzinfo (0.3.23)
+ xml-simple (1.0.12)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ appraisal
+ aws-s3
+ mocha
+ rails (>= 3.0.3)
+ rake
+ ruby-debug
+ shoulda
+ sqlite3-ruby (~> 1.3.0)
View
27 lib/paperclip.rb
@@ -37,6 +37,7 @@
require 'paperclip/interpolations'
require 'paperclip/style'
require 'paperclip/attachment'
+require 'paperclip/storage'
require 'paperclip/callback_compatability'
require 'paperclip/command_line'
require 'paperclip/railtie'
@@ -103,15 +104,6 @@ def run cmd, *params
CommandLine.new(cmd, *params).run
end
- def included base #:nodoc:
- base.extend ClassMethods
- if base.respond_to?("set_callback")
- base.send :include, Paperclip::CallbackCompatability::Rails3
- else
- base.send :include, Paperclip::CallbackCompatability::Rails21
- end
- end
-
def processor name #:nodoc:
name = name.to_s.camelize
processor = Paperclip.const_get(name)
@@ -121,6 +113,12 @@ def processor name #:nodoc:
processor
end
+ def each_instance_with_attachment(klass, name)
+ Object.const_get(klass).all.each do |instance|
+ yield(instance) if instance.send(:"#{name}?")
+ end
+ end
+
# Log a paperclip-specific line. Uses ActiveRecord::Base.logger
# by default. Set Paperclip.options[:log] to false to turn off.
def log message
@@ -159,6 +157,17 @@ class NotIdentifiedByImageMagickError < PaperclipError #:nodoc:
class InfiniteInterpolationError < PaperclipError #:nodoc:
end
+ module Glue
+ def self.included base #:nodoc:
+ base.extend ClassMethods
+ if base.respond_to?("set_callback")
+ base.send :include, Paperclip::CallbackCompatability::Rails3
+ else
+ base.send :include, Paperclip::CallbackCompatability::Rails21
+ end
+ end
+ end
+
module ClassMethods
# +has_attached_file+ gives the class it is called on an attribute that maps to a file. This
# is typically a file stored somewhere on the filesystem and has been uploaded by a user.
View
24 lib/paperclip/attachment.rb
@@ -4,6 +4,7 @@ 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 ||= {
@@ -88,11 +89,11 @@ def assign uploaded_file
return nil if uploaded_file.nil?
- @queued_for_write[:original] = uploaded_file.to_tempfile
+ @queued_for_write[:original] = to_tempfile(uploaded_file)
instance_write(:file_name, uploaded_file.original_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, uploaded_file.fingerprint)
+ instance_write(:fingerprint, generate_fingerprint(uploaded_file))
instance_write(:updated_at, Time.now)
@dirty = true
@@ -101,7 +102,7 @@ def assign uploaded_file
# Reset the file size if the original file was reprocessed.
instance_write(:file_size, @queued_for_write[:original].size.to_i)
- instance_write(:fingerprint, @queued_for_write[:original].fingerprint)
+ instance_write(:fingerprint, generate_fingerprint(@queued_for_write[:original]))
ensure
uploaded_file.close if close_uploaded_file
end
@@ -180,7 +181,7 @@ def size
# Returns the hash of the file as originally assigned, and lives in the
# <attachment>_fingerprint attribute of the model.
def fingerprint
- instance_read(:fingerprint) || (@queued_for_write[:original] && @queued_for_write[:original].fingerprint)
+ instance_read(:fingerprint) || (@queued_for_write[:original] && generate_fingerprint(@queued_for_write[:original]))
end
# Returns the content_type of the file as originally assigned, and lives
@@ -196,6 +197,12 @@ def updated_at
time && time.to_f.to_i
end
+ def generate_fingerprint(source)
+ data = source.read
+ source.rewind if source.respond_to?(:rewind)
+ Digest::MD5.hexdigest(data)
+ end
+
# Paths and URLs can have a number of variables interpolated into them
# to vary the storage location based on name, id, style, class, etc.
# This method is a deprecated access into supplying and retrieving these
@@ -277,13 +284,12 @@ def valid_assignment? file #:nodoc:
end
def initialize_storage #:nodoc:
- storage_name = @storage.to_s.capitalize
+ storage_class_name = @storage.to_s.capitalize
begin
- require "paperclip/storage/#{@storage}"
- rescue MissingSourceFile
- raise StorageMethodNotFound, "Cannot find the '#{@storage}' storage adapter."
+ @storage_module = Paperclip::Storage.const_get(storage_class_name)
+ rescue NameError
+ raise StorageMethodNotFound, "Cannot load storage module '#{storage_class_name}'"
end
- @storage_module = Paperclip::Storage.const_get(storage_name)
self.extend(@storage_module)
end
View
2  lib/paperclip/command_line.rb
@@ -8,7 +8,7 @@ def initialize(binary, params = "", options = {})
@binary = binary.dup
@params = params.dup
@options = options.dup
- @swallow_stderr = @options.delete(:swallow_stderr)
+ @swallow_stderr = @options.has_key?(:swallow_stderr) ? @options.delete(:swallow_stderr) : Paperclip.options[:swallow_stderr]
@expected_outcodes = @options.delete(:expected_outcodes)
@expected_outcodes ||= [0]
end
View
3  lib/paperclip/interpolations.rb
@@ -41,8 +41,9 @@ def filename attachment, style_name
# Returns the interpolated URL. Will raise an error if the url itself
# contains ":url" to prevent infinite recursion. This interpolation
# is used in the default :path to ease default specifications.
+ RIGHT_HERE = "#{__FILE__.gsub(%r{^\./}, "")}:#{__LINE__ + 3}"
def url attachment, style_name
- raise InfiniteInterpolationError if caller.any?{|b| b.index("#{__FILE__}:#{__LINE__ + 1}") }
+ raise InfiniteInterpolationError if caller.any?{|b| b.index(RIGHT_HERE) }
attachment.url(style_name, false)
end
View
34 lib/paperclip/iostream.rb
@@ -1,29 +1,27 @@
# 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
- name = respond_to?(:original_filename) ? original_filename : (respond_to?(:path) ? path : "stream")
- tempfile = Paperclip::Tempfile.new("stream" + File.extname(name))
+ 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
- self.stream_to(tempfile)
+ 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. If this module is included in both
- # StringIO and Tempfile, then either can have its data copied anywhere else without typing
- # worries or memory overhead worries. 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 path_or_file, in_blocks_of = 8192
+ # 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 = ""
- self.rewind
- while self.read(in_blocks_of, buffer) do
+ object.rewind
+ while object.read(in_blocks_of, buffer) do
dstio.write(buffer)
end
dstio.rewind
@@ -31,18 +29,6 @@ def stream_to path_or_file, in_blocks_of = 8192
end
end
-class IO #:nodoc:
- include IOStream
-end
-
-%w( Tempfile StringIO ).each do |klass|
- if Object.const_defined? klass
- Object.const_get(klass).class_eval do
- include IOStream
- end
- end
-end
-
# Corrects a bug in Windows when asking for Tempfile size.
if defined? Tempfile
class Tempfile
View
17 lib/paperclip/processor.rb
@@ -40,10 +40,19 @@ def self.make file, options = {}, attachment = nil
# on this blog post:
# http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions
class Tempfile < ::Tempfile
- # Replaces Tempfile's +make_tmpname+ with one that honors file extensions.
- def make_tmpname(basename, n)
- extension = File.extname(basename)
- sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n.to_i, extension)
+ # This is Ruby 1.8.7's implementation.
+ if RUBY_VERSION <= "1.8.6"
+ def make_tmpname(basename, n)
+ case basename
+ when Array
+ prefix, suffix = *basename
+ else
+ prefix, suffix = basename, ''
+ end
+
+ t = Time.now.strftime("%y%m%d")
+ path = "#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-#{n}#{suffix}"
+ end
end
end
end
View
2  lib/paperclip/railtie.rb
@@ -17,7 +17,7 @@ class Railtie < Rails::Railtie
class Railtie
def self.insert
- ActiveRecord::Base.send(:include, Paperclip)
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
File.send(:include, Paperclip::Upfile)
end
end
View
2  lib/paperclip/storage.rb
@@ -0,0 +1,2 @@
+require "paperclip/storage/filesystem"
+require "paperclip/storage/s3"
View
1  lib/paperclip/storage/filesystem.rb
@@ -56,6 +56,7 @@ def flush_deletes #:nodoc:
while(true)
path = File.dirname(path)
FileUtils.rmdir(path)
+ break if File.exists?(path) # Ruby 1.9.2 does not raise if the removal failed.
end
rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR
# Stop trying to remove parent directories
View
13 lib/paperclip/storage/s3.rb
@@ -127,12 +127,20 @@ def s3_protocol
# style, in the format most representative of the current storage.
def to_file style = default_style
return @queued_for_write[style] if @queued_for_write[style]
- file = Tempfile.new(path(style))
+ filename = path(style)
+ extname = File.extname(filename)
+ basename = File.basename(filename, extname)
+ file = Tempfile.new([basename, extname])
+ file.binmode
file.write(AWS::S3::S3Object.value(path(style), bucket_name))
file.rewind
return file
end
+ def create_bucket
+ AWS::S3::Bucket.create(bucket_name)
+ end
+
def flush_writes #:nodoc:
@queued_for_write.each do |style, file|
begin
@@ -143,6 +151,9 @@ def flush_writes #:nodoc:
{:content_type => instance_read(:content_type),
:access => @s3_permissions,
}.merge(@s3_headers))
+ rescue AWS::S3::NoSuchBucket => e
+ create_bucket
+ retry
rescue AWS::S3::ResponseError => e
raise
end
View
2  lib/paperclip/thumbnail.rb
@@ -45,7 +45,7 @@ def convert_options?
# that contains the new image.
def make
src = @file
- dst = Tempfile.new([@basename, @format].compact.join("."))
+ dst = Tempfile.new([@basename, @format ? ".#{@format}" : ''])
dst.binmode
begin
View
5 lib/paperclip/upfile.rb
@@ -32,11 +32,6 @@ def original_filename
def size
File.size(self)
end
-
- # Returns the hash of the file.
- def fingerprint
- Digest::MD5.hexdigest(self.read)
- end
end
end
View
2  lib/paperclip/version.rb
@@ -1,3 +1,3 @@
module Paperclip
- VERSION = "2.3.3" unless defined? Paperclip::VERSION
+ VERSION = "2.3.8" unless defined? Paperclip::VERSION
end
View
79 lib/tasks/paperclip.rake
@@ -1,38 +1,20 @@
def obtain_class
class_name = ENV['CLASS'] || ENV['class']
raise "Must specify CLASS" unless class_name
- @klass = Object.const_get(class_name)
+ class_name
end
-def obtain_attachments
+def obtain_attachments(klass)
+ klass = Object.const_get(klass.to_s)
name = ENV['ATTACHMENT'] || ENV['attachment']
- raise "Class #{@klass.name} has no attachments specified" unless @klass.respond_to?(:attachment_definitions)
- if !name.blank? && @klass.attachment_definitions.keys.include?(name)
+ raise "Class #{klass.name} has no attachments specified" unless klass.respond_to?(:attachment_definitions)
+ if !name.blank? && klass.attachment_definitions.keys.include?(name)
[ name ]
else
- @klass.attachment_definitions.keys
+ klass.attachment_definitions.keys
end
end
-def for_all_attachments
- klass = obtain_class
- names = obtain_attachments
- ids = klass.connection.select_values(klass.send(:construct_finder_sql, :select => 'id'))
-
- ids.each do |id|
- instance = klass.find(id)
- names.each do |name|
- result = if instance.send("#{ name }?")
- yield(instance, name)
- else
- true
- end
- print result ? "." : "x"; $stdout.flush
- end
- end
- puts " Done."
-end
-
namespace :paperclip do
desc "Refreshes both metadata and thumbnails."
task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"]
@@ -41,24 +23,31 @@ namespace :paperclip do
desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)."
task :thumbnails => :environment do
errors = []
- for_all_attachments do |instance, name|
- result = instance.send(name).reprocess!
- errors << [instance.id, instance.errors] unless instance.errors.blank?
- result
+ klass = obtain_class
+ names = obtain_attachments(klass)
+ names.each do |name|
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
+ result = instance.send(name).reprocess!
+ errors << [instance.id, instance.errors] unless instance.errors.blank?
+ end
end
errors.each{|e| puts "#{e.first}: #{e.last.full_messages.inspect}" }
end
desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)."
task :metadata => :environment do
- for_all_attachments do |instance, name|
- if file = instance.send(name).to_file
- instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
- instance.send("#{name}_content_type=", file.content_type.strip)
- instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
- instance.save(false)
- else
- true
+ klass = obtain_class
+ names = obtain_attachments(klass)
+ names.each do |name|
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
+ if file = instance.send(name).to_file
+ instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
+ instance.send("#{name}_content_type=", file.content_type.strip)
+ instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
+ instance.save(false)
+ else
+ true
+ end
end
end
end
@@ -66,13 +55,17 @@ namespace :paperclip do
desc "Cleans out invalid attachments. Useful after you've added new validations."
task :clean => :environment do
- for_all_attachments do |instance, name|
- instance.send(name).send(:validate)
- if instance.send(name).valid?
- true
- else
- instance.send("#{name}=", nil)
- instance.save
+ klass = obtain_class
+ names = obtain_attachments(klass)
+ names.each do |name|
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
+ instance.send(name).send(:validate)
+ if instance.send(name).valid?
+ true
+ else
+ instance.send("#{name}=", nil)
+ instance.save
+ end
end
end
end
View
1  paperclip.gemspec
@@ -28,6 +28,7 @@ spec = Gem::Specification.new do |s|
s.add_dependency 'activerecord'
s.add_dependency 'activesupport'
s.add_development_dependency 'shoulda'
+ s.add_development_dependency 'appraisal'
s.add_development_dependency 'mocha'
s.add_development_dependency 'aws-s3'
s.add_development_dependency 'sqlite3-ruby'
View
16 test/attachment_test.rb
@@ -1,5 +1,5 @@
# encoding: utf-8
-require 'test/helper'
+require './test/helper'
class Dummy
# This is a dummy class
@@ -463,14 +463,11 @@ def do_after_all; end
setup do
rebuild_model
- @not_file = mock
- @tempfile = mock
+ @not_file = mock("not_file")
+ @tempfile = mock("tempfile")
@not_file.stubs(:nil?).returns(false)
- @not_file.stubs(:fingerprint).returns('bd94545193321376b70136f8b223abf8')
- @tempfile.stubs(:fingerprint).returns('bd94545193321376b70136f8b223abf8')
@not_file.expects(:size).returns(10)
@tempfile.expects(:size).returns(10)
- @not_file.expects(:to_tempfile).returns(@tempfile)
@not_file.expects(:original_filename).returns("sheep_say_bæ.png\r\n")
@not_file.expects(:content_type).returns("image/png\r\n")
@@ -479,6 +476,9 @@ def do_after_all; end
@attachment.expects(:valid_assignment?).with(@not_file).returns(true)
@attachment.expects(:queue_existing_for_delete)
@attachment.expects(:post_process)
+ @attachment.expects(:to_tempfile).returns(@tempfile)
+ @attachment.expects(:generate_fingerprint).with(@tempfile).returns("12345")
+ @attachment.expects(:generate_fingerprint).with(@not_file).returns("12345")
@dummy.avatar = @not_file
end
@@ -606,7 +606,7 @@ def do_after_all; end
[: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)
+ assert File.exists?(io.path)
assert ! io.is_a?(::Tempfile)
io.close
end
@@ -703,7 +703,7 @@ def do_after_all; end
now = Time.now
Time.stubs(:now).returns(now)
@dummy.avatar = @file
- assert now, @dummy.avatar.updated_at
+ assert_equal now.to_i, @dummy.avatar.updated_at.to_i
end
should "return nil when reloaded and sent #avatar_updated_at" do
View
27 test/command_line_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class CommandLineTest < Test::Unit::TestCase
def setup
@@ -7,13 +7,13 @@ def setup
end
should "take a command and parameters and produce a shell command for bash" do
- cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png")
+ cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
assert_equal "convert a.jpg b.png", cmd.command
end
should "be able to set a path and produce commands with that path" do
Paperclip::CommandLine.path = "/opt/bin"
- cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png")
+ cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
assert_equal "/opt/bin/convert a.jpg b.png", cmd.command
end
@@ -21,7 +21,8 @@ def setup
cmd = Paperclip::CommandLine.new("convert",
":one :{two}",
:one => "a.jpg",
- :two => "b.png")
+ :two => "b.png",
+ :swallow_stderr => false)
assert_equal "convert 'a.jpg' 'b.png'", cmd.command
end
@@ -30,7 +31,8 @@ def setup
cmd = Paperclip::CommandLine.new("convert",
":one :{two}",
:one => "a.jpg",
- :two => "b.png")
+ :two => "b.png",
+ :swallow_stderr => false)
assert_equal 'convert "a.jpg" "b.png"', cmd.command
end
@@ -38,7 +40,8 @@ def setup
cmd = Paperclip::CommandLine.new("convert",
":one :two",
:one => "`rm -rf`.jpg",
- :two => "ha'ha.png")
+ :two => "ha'ha.png",
+ :swallow_stderr => false)
assert_equal "convert '`rm -rf`.jpg' 'ha'\\''ha.png'", cmd.command
end
@@ -47,7 +50,8 @@ def setup
cmd = Paperclip::CommandLine.new("convert",
":one :two",
:one => "`rm -rf`.jpg",
- :two => "ha'ha.png")
+ :two => "ha'ha.png",
+ :swallow_stderr => false)
assert_equal %{convert "`rm -rf`.jpg" "ha'ha.png"}, cmd.command
end
@@ -80,7 +84,7 @@ def setup
end
should "run the #command it's given and return the output" do
- cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png")
+ cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
cmd.class.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
with_exitstatus_returning(0) do
assert_equal :correct_value, cmd.run
@@ -88,7 +92,7 @@ def setup
end
should "raise a PaperclipCommandLineError if the result code isn't expected" do
- cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png")
+ cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
cmd.class.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
with_exitstatus_returning(1) do
assert_raises(Paperclip::PaperclipCommandLineError) do
@@ -100,7 +104,8 @@ def setup
should "not raise a PaperclipCommandLineError if the result code is expected" do
cmd = Paperclip::CommandLine.new("convert",
"a.jpg b.png",
- :expected_outcodes => [0, 1])
+ :expected_outcodes => [0, 1],
+ :swallow_stderr => false)
cmd.class.stubs(:"`").with("convert a.jpg b.png").returns(:correct_value)
with_exitstatus_returning(1) do
assert_nothing_raised do
@@ -110,7 +115,7 @@ def setup
end
should "log the command" do
- cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png")
+ cmd = Paperclip::CommandLine.new("convert", "a.jpg b.png", :swallow_stderr => false)
cmd.class.stubs(:'`')
Paperclip.expects(:log).with("convert a.jpg b.png")
cmd.run
View
2  test/geometry_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class GeometryTest < Test::Unit::TestCase
context "Paperclip::Geometry" do
View
22 test/helper.rb
@@ -5,18 +5,6 @@
require 'shoulda'
require 'mocha'
-case ENV['RAILS_VERSION']
-when '2.1' then
- gem 'activerecord', '~>2.1.0'
- gem 'activesupport', '~>2.1.0'
-when '3.0' then
- gem 'activerecord', '~>3.0.0'
- gem 'activesupport', '~>3.0.0'
-else
- gem 'activerecord', '~>2.3.0'
- gem 'activesupport', '~>2.3.0'
-end
-
require 'active_record'
require 'active_record/version'
require 'active_support'
@@ -53,7 +41,7 @@ def setup
require File.join(ROOT, 'lib', 'paperclip.rb')
-require 'shoulda_macros/paperclip'
+require './shoulda_macros/paperclip'
FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
@@ -61,10 +49,10 @@ def setup
ActiveRecord::Base.establish_connection(config['test'])
def reset_class class_name
- ActiveRecord::Base.send(:include, Paperclip)
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
Object.send(:remove_const, class_name) rescue nil
klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
- klass.class_eval{ include Paperclip }
+ klass.class_eval{ include Paperclip::Glue }
klass
end
@@ -90,11 +78,11 @@ def rebuild_model options = {}
end
def rebuild_class options = {}
- ActiveRecord::Base.send(:include, Paperclip)
+ ActiveRecord::Base.send(:include, Paperclip::Glue)
Object.send(:remove_const, "Dummy") rescue nil
Object.const_set("Dummy", Class.new(ActiveRecord::Base))
Dummy.class_eval do
- include Paperclip
+ include Paperclip::Glue
has_attached_file :avatar, options
end
end
View
2  test/integration_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class IntegrationTest < Test::Unit::TestCase
context "Many models at once" do
View
2  test/interpolations_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class InterpolationsTest < Test::Unit::TestCase
should "return all methods but the infrastructure when sent #all" do
View
19 test/iostream_test.rb
@@ -1,14 +1,7 @@
-require 'test/helper'
+require './test/helper'
class IOStreamTest < Test::Unit::TestCase
- context "IOStream" do
- should "be included in IO, File, Tempfile, and StringIO" do
- [IO, File, Tempfile, StringIO].each do |klass|
- assert klass.included_modules.include?(IOStream), "Not in #{klass}"
- end
- end
- end
-
+ include IOStream
context "A file" do
setup do
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
@@ -21,7 +14,7 @@ class IOStreamTest < Test::Unit::TestCase
context "and given a String" do
setup do
FileUtils.mkdir_p(File.join(ROOT, 'tmp'))
- assert @result = @file.stream_to(File.join(ROOT, 'tmp', 'iostream.string.test'))
+ assert @result = stream_to(@file, File.join(ROOT, 'tmp', 'iostream.string.test'))
end
should "return a File" do
@@ -38,7 +31,7 @@ class IOStreamTest < Test::Unit::TestCase
setup do
tempfile = Tempfile.new('iostream.test')
tempfile.binmode
- assert @result = @file.stream_to(tempfile)
+ assert @result = stream_to(@file, tempfile)
end
should "return a Tempfile" do
@@ -53,9 +46,9 @@ class IOStreamTest < Test::Unit::TestCase
end
- context "that is sent #to_tempfile" do
+ context "that is converted #to_tempfile" do
setup do
- assert @tempfile = @file.to_tempfile
+ assert @tempfile = to_tempfile(@file)
end
should "convert it to a Paperclip Tempfile" do
View
2  test/matchers/have_attached_file_matcher_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class HaveAttachedFileMatcherTest < Test::Unit::TestCase
context "have_attached_file" do
View
2  test/matchers/validate_attachment_content_type_matcher_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class ValidateAttachmentContentTypeMatcherTest < Test::Unit::TestCase
context "validate_attachment_content_type" do
View
2  test/matchers/validate_attachment_presence_matcher_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase
context "validate_attachment_presence" do
View
2  test/matchers/validate_attachment_size_matcher_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class ValidateAttachmentSizeMatcherTest < Test::Unit::TestCase
context "validate_attachment_size" do
View
25 test/paperclip_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class PaperclipTest < Test::Unit::TestCase
context "Calling Paperclip.run" do
@@ -43,6 +43,23 @@ class PaperclipTest < Test::Unit::TestCase
end
end
+ context "Paperclip.each_instance_with_attachment" do
+ setup do
+ @file = File.new(File.join(FIXTURES_DIR, "5k.png"), 'rb')
+ d1 = Dummy.create(:avatar => @file)
+ d2 = Dummy.create
+ d3 = Dummy.create(:avatar => @file)
+ @expected = [d1, d3]
+ end
+ should "yield every instance of a model that has an attachment" do
+ actual = []
+ Paperclip.each_instance_with_attachment("Dummy", "avatar") do |instance|
+ actual << instance
+ end
+ assert_same_elements @expected, actual
+ end
+ end
+
should "raise when sent #processor and the name of a class that exists but isn't a subclass of Processor" do
assert_raises(Paperclip::PaperclipError){ Paperclip.processor(:attachment) }
end
@@ -172,6 +189,12 @@ class ::SubDummy < Dummy; end
end
end
+ should "not have Attachment in the ActiveRecord::Base namespace" do
+ assert_raises(NameError) do
+ ActiveRecord::Base::Attachment
+ end
+ end
+
def self.should_validate validation, options, valid_file, invalid_file
context "with #{validation} validation and #{options.inspect} options" do
setup do
View
2  test/processor_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class ProcessorTest < Test::Unit::TestCase
should "instantiate and call #make when sent #make to the class" do
View
22 test/storage_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
require 'aws/s3'
class StorageTest < Test::Unit::TestCase
@@ -185,6 +185,21 @@ def rails_env(env)
end
end
+ context "and saved without a bucket" do
+ setup do
+ class AWS::S3::NoSuchBucket < AWS::S3::ResponseError
+ # Force the class to be created as a proper subclass of ResponseError thanks to AWS::S3's autocreation of exceptions
+ end
+ AWS::S3::Bucket.expects(:create).with("testing")
+ AWS::S3::S3Object.stubs(:store).raises(AWS::S3::NoSuchBucket.new(:message, :response)).then.returns(true)
+ @dummy.save
+ end
+
+ should "succeed" do
+ assert true
+ end
+ end
+
context "and remove" do
setup do
AWS::S3::S3Object.stubs(:exists?).returns(true)
@@ -336,6 +351,11 @@ def rails_env(env)
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
2  test/style_test.rb
@@ -1,5 +1,5 @@
# encoding: utf-8
-require 'test/helper'
+require './test/helper'
class StyleTest < Test::Unit::TestCase
View
4 test/thumbnail_test.rb
@@ -1,10 +1,10 @@
-require 'test/helper'
+require './test/helper'
class ThumbnailTest < Test::Unit::TestCase
context "A Paperclip Tempfile" do
setup do
- @tempfile = Paperclip::Tempfile.new("file.jpg")
+ @tempfile = Paperclip::Tempfile.new(["file", ".jpg"])
end
should "have its path contain a real extension" do
View
2  test/upfile_test.rb
@@ -1,4 +1,4 @@
-require 'test/helper'
+require './test/helper'
class UpfileTest < Test::Unit::TestCase
{ %w(jpg jpe jpeg) => 'image/jpeg',
Please sign in to comment.
Something went wrong with that request. Please try again.