Commit 2784b380 by jyurek

Huge refactoring.

git-svn-id: https://svn.thoughtbot.com/plugins/paperclip/trunk@390 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
parent c77ba25e
......@@ -11,7 +11,7 @@ See the documentation for the +has_attached_file+ method for options.
In your model:
class User < ActiveRecord::Base
has_attached_file :avatar, :thumbnails => { :medium => "300x300>", :thumb => "100x100>" }
has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }
end
In your edit and new views:
......@@ -23,12 +23,11 @@ In your edit and new views:
In your controller:
def create
@user = User.create( params[:user][:avatar] )
@user = User.create( params[:user] )
end
In your show view:
<%= image_tag @user.avatar.url %>
<%= image_tag @user.avatar.url(:original) %>
<%= image_tag @user.avatar.url(:medium) %>
<%= image_tag @user.avatar.url(:thumb) %>
# Install hook code here
module Paperclip
# Defines the geometry of an image.
class Geometry
attr_accessor :height, :width, :modifier
# Gives a Geometry representing the given height and width
def initialize width = nil, height = nil, modifier = nil
height = nil if height == ""
width = nil if width == ""
@height = (height || width).to_f
@width = (width || height).to_f
@modifier = modifier
end
# Uses ImageMagick to determing the dimensions of a file, passed in as either a
# File or path.
def self.from_file file
file = file.path if file.respond_to? "path"
parse(`#{Paperclip.path_for_command('identify')} "#{file}" 2>/dev/null`) ||
raise(Errno::ENOENT, file)
end
# Parses a "WxH" formatted string, where W is the width and H is the height.
def self.parse string
if match = (string && string.match(/\b(\d*)x(\d*)([><\#\@\%^!])?\b/))
Geometry.new(*match[1,3])
end
end
# True if the dimensions represent a square
def square?
height == width
end
# True if the dimensions represent a horizontal rectangle
def horizontal?
height < width
end
# True if the dimensions represent a vertical rectangle
def vertical?
height > width
end
# The aspect ratio of the dimensions.
def aspect
width / height
end
# Returns the larger of the two dimensions
def larger
[height, width].max
end
# Returns the smaller of the two dimensions
def smaller
[height, width].min
end
# Returns the width and height in a format suitable to be passed to Geometry.parse
def to_s
"%dx%d" % [width, height]
end
# Same as to_s
def inspect
to_s
end
# Returns the scaling and cropping geometries (in string-based ImageMagick format)
# neccessary to transform this Geometry into the Geometry given. If crop is true,
# then it is assumed the destination Geometry will be the exact final resolution.
# In this case, the source Geometry is scaled so that an image containing the
# destination Geometry would be completely filled by the source image, and any
# overhanging image would be cropped. Useful for square thumbnail images. The cropping
# is weighted at the center of the Geometry.
def transformation_to dst, crop = false
ratio = Geometry.new( dst.width / self.width, dst.height / self.height )
if crop
scale_geometry, scale = if ratio.horizontal? || ratio.square?
[ "%dx" % dst.width, ratio.width ]
else
[ "x%d" % dst.height, ratio.height ]
end
crop_geometry = if ratio.horizontal? || ratio.square?
"%dx%d+%d+%d" % [ dst.width, dst.height, 0, (self.height * scale - dst.height) / 2 ]
else
"%dx%d+%d+%d" % [ dst.width, dst.height, (self.width * scale - dst.width) / 2, 0 ]
end
else
scale_geometry = dst.to_s
end
[ scale_geometry, crop_geometry ]
end
end
end
# Provides method that can be included on File-type objects (IO, StringIO, Tempfile, etc) to allow stream copying
# and Tempfile conversion.
module IOStream
# Returns a Tempfile containing the contents of the readable object.
def to_tempfile
tempfile = Tempfile.new("stream")
self.stream_to(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
# 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
dstio = case path_or_file
when String then File.new(path_or_file, "w+")
when IO then path_or_file
when Tempfile then path_or_file
end
buffer = ""
self.rewind
while self.read(in_blocks_of, buffer) do
dstio.write(buffer)
end
dstio.rewind
dstio
end
end
class IO
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
module Paperclip
module Storage
module Filesystem
def write_attachment
ensure_directories
each_unsaved do |style, data|
File.open( file_name(style), "w" ) do |file|
file.rewind
file.write(data)
end
end
end
def read_attachment style = nil
IO.read(file_name(style))
end
def delete_attachment complain = false
styles.each do |style|
file_path = file_name(style)
begin
FileUtils.rm file_path if file_path
rescue SystemCallError => e
raise PaperclipError, "could not be deleted." if Paperclip.options[:whiny_deletes] || complain
end
end
end
def attachment_exists? style = nil
File.exists?( file_name(style) )
end
def file_name style = nil
style ||= definition.default_style
interpolate( style, definition.path )
end
def ensure_directories
each_unsaved do |style, file|
dirname = File.dirname( file_name(style) )
FileUtils.mkdir_p dirname
end
end
end
end
end
\ No newline at end of file
module Paperclip
module Storage
module S3
def self.extended(base)
Paperclip.options[:s3] ||= {}
Paperclip::Attachment.interpolations[:bucket] = lambda{|style, atch| atch.definition.bucket }
access_key, secret_key = credentials
require 'aws/s3'
AWS::S3::Base.establish_connection!(
:access_key_id => access_key,
:secret_access_key => secret_key,
:persistent => Paperclip.options[:s3][:persistent] || true
)
class << base
alias_method_chain :url, :s3
end
end
def self.credentials
if credentials_file
creds = YAML.load_file(credentials_file)
creds = creds[RAILS_ENV] || creds if Object.const_defined?("RAILS_ENV")
[ creds['access_key_id'], creds['secret_access_key'] ]
else
[ Paperclip.options[:s3][:access_key_id], Paperclip.options[:s3][:secret_access_key] ]
end
end
def self.credentials_file
@file ||= [ Paperclip.options[:s3][:credentials_file], File.join(RAILS_ROOT, "config", "s3.yml") ].compact.find do |f|
File.exists?(f)
end
end
def url_with_s3 style = nil
http_host = definition.s3_host || "http://s3.amazonaws.com"
"#{http_host}/#{bucket}#{url_without_s3(style)}"
end
def file_name style = nil
style ||= definition.default_style
interpolate( style, definition.url )
end
def bucket
definition.bucket
end
def ensure_bucket
begin
AWS::S3::Bucket.create(bucket)
bucket
rescue AWS::S3::S3Exception => e
raise Paperclip::PaperclipError, "You are not allowed access to the bucket '#{bucket_name}'."
end
end
def stream style = nil, &block
AWS::S3::S3Object.stream( file_name(style), bucket, &block )
end
# These four methods are the primary interface for the storage module.
# Everything above this is support for these methods.
def attachment_exists? style = nil
AWS::S3::S3Object.exists?( file_name(style), bucket )
end
def write_attachment
ensure_bucket
each_unsaved do |style, data|
AWS::S3::S3Object.store( file_name(style), data, bucket, :access => definition.s3_access || :public_read )
end
end
def read_attachment style = nil
AWS::S3::S3Object.value( file_name(style), bucket )
end
def delete_attachment complain = false
styles.each do |style, data|
AWS::S3::S3Object.delete( file_name(style), bucket )
end
end
end
end
end
\ No newline at end of file
module Paperclip
class Thumbnail
class Geometry
attr_accessor :height, :width
def initialize width = nil, height = nil
@height = (height || width).to_f
@width = (width || height).to_f
end
attr_accessor :file, :current_geometry, :target_geometry, :format, :whiny_thumbnails
def self.parse string
if match = (string && string.match(/(\d*)x(\d*)/))
Geometry.new(*match[1,2])
end
end
# Creates a Thumbnail object set to work on the +file+ given. It
# will attempt to transform the image into one defined by +target_geometry+
# which is a "WxH"-style string. +format+ will be inferred from the +file+
# unless specified. Thumbnail creation will raise no errors unless
# +whiny_thumbnails+ is true (which it is, by default.
def initialize file, target_geometry, format = nil, whiny_thumbnails = true
@file = file
@crop = target_geometry[-1,1] == '#'
@target_geometry = Geometry.parse target_geometry
@current_geometry = Geometry.from_file file
@whiny_thumbnails = whiny_thumbnails
def square?
height == width
end
@current_format = File.extname(@file.path)
@basename = File.basename(@file.path, @current_format)
def horizontal?
height < width
@format = format
end
def vertical?
height > width
# Creates a thumbnail, as specified in +initialize+, +make+s it, and returns the
# resulting Tempfile.
def self.make file, dimensions, format = nil, whiny_thumbnails = true
new(file, dimensions, format, whiny_thumbnails).make
end
def aspect
width / height
end
def larger
[height, width].max
end
def smaller
[height, width].min
end
def to_s
"#{width}x#{height}"
end
def inspect
to_s
end
end
attr_accessor :geometry, :data
def initialize geometry, data, whiny_thumbnails = nil
@geometry, @data = geometry, data
@whiny_thumbnails = Paperclip.options[:whiny_thumbnails]
@whiny_thumbnails = whiny_thumbnails unless whiny_thumbnails.nil?
end
def self.make geometry, data, whiny_thumbnails = nil
new(geometry, data, whiny_thumbnails).make
# Returns true if the +target_geometry+ is meant to crop.
def crop?
@crop
end
# Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile
# that contains the new image.
def make
return data if geometry.nil?
operator = geometry[-1,1]
begin
scale_geometry = geometry
scale_geometry, crop_geometry = geometry_for_crop if operator == '#'
convert = Paperclip.path_for_command("convert")
command = "#{convert} - -scale '#{scale_geometry}' #{operator == '#' ? "-crop '#{crop_geometry}'" : ""} - 2>/dev/null"
thumb = piping data, :to => command
rescue Errno::EPIPE => e
raise PaperclipError, "could not be thumbnailed. Is ImageMagick or GraphicsMagick installed and available?"
rescue SystemCallError => e
raise PaperclipError, "could not be thumbnailed."
rescue PaperclipError
raise if @whiny_thumbnails
end
if @whiny_thumbnails && !$?.success?
raise PaperclipError, "could not be thumbnailed because of an error with 'convert'."
end
thumb
end
src = @file
dst = Tempfile.new([@basename, @format].compact.join("."))
def geometry_for_crop
identify = Paperclip.path_for_command("identify")
piping data, :to => "#{identify} - 2>/dev/null" do |pipeout|
dimensions = pipeout.split[2]
if src = Geometry.parse(dimensions)
dst = Geometry.parse(geometry)
command = <<-end_command
#{ Paperclip.path_for_command('convert') }
"#{ File.expand_path(src.path) }"
#{ transformation_command }
"#{ File.expand_path(dst.path) }"
end_command
success = system(command.gsub(/\s+/, " "))
ratio = Geometry.new( dst.width / src.width, dst.height / src.height )
scale_geometry, scale = if ratio.horizontal? || ratio.square?
[ "%dx" % dst.width, ratio.width ]
else
[ "x%d" % dst.height, ratio.height ]
if success && $?.exitstatus != 0 && @whiny_thumbnails
raise PaperclipError, "There was an error processing this thumbnail"
end
crop_geometry = if ratio.horizontal? || ratio.square?
"%dx%d+%d+%d" % [ dst.width, dst.height, 0, (src.height * scale - dst.height) / 2 ]
else
"%dx%d+%d+%d" % [ dst.width, dst.height, (src.width * scale - dst.width) / 2, 0 ]
dst
end
[ scale_geometry, crop_geometry ]
else
raise PaperclipError, "does not contain a valid image."
end
# Returns the command ImageMagick's +convert+ needs to transform the image
# into the thumbnail.
def transformation_command
scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
trans = "-scale #{scale}"
trans << " -crop #{crop} +repage" if crop
trans
end
end
def piping data, command, &block
self.class.piping(data, command, &block)
end
def self.piping data, command, &block
command = command[:to] if command.respond_to?(:[]) && command[:to]
block ||= lambda {|d| d }
IO.popen(command, "w+") do |io|
io.write(data)
io.close_write
block.call(io.read)
end
# Due to how ImageMagick handles its image format conversion and how Tempfile
# handles its naming scheme, it is necessary to override how Tempfile makes
# its names so as to allow for file extensions. Idea taken from the comments
# 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, extension)
end
end
end
......@@ -26,3 +26,7 @@ module Paperclip
end
end
class File #:nodoc:
include Paperclip::Upfile
end
......@@ -2,7 +2,7 @@ require 'environment'
def obtain_class
class_name = ENV['CLASS'] || ENV['class']
@klass = eval(class_name)
@klass = Object.const_get(class_name)
end
def obtain_attachments
......@@ -10,7 +10,7 @@ def obtain_attachments
if !name.blank? && @klass.attachment_names.include?(name)
[ name ]
else
@klass.attachment_names
@klass.attachment_definitions.keys
end
end
......@@ -21,12 +21,17 @@ namespace :paperclip do
instances = klass.find(:all)
names = obtain_attachments
puts "Regenerating thumbnails for #{instances.length} instances:"
puts "Regenerating thumbnails for #{instances.length} instances of #{klass.name}:"
instances.each do |instance|
names.each do |name|
instance.send("process_#{name}_thumbnails")
result = if instance.send("#{ name }?")
instance.send(name).send("post_process")
instance.send(name).save
else
true
end
print result ? "." : "x"; $stdout.flush
end
print instance.save ? "." : "x"; $stdout.flush
end
puts " Done."
end
......
......@@ -2,3 +2,4 @@ test:
adapter: sqlite3
#dbfile: paperclip.db
database: ":memory:"
This is not an image.
require 'rubygems'
require 'test/unit'
require 'shoulda'
require 'mocha'
require 'tempfile'
require 'active_record'
require 'ruby-debug'
ROOT = File.join(File.dirname(__FILE__), '..')
RAILS_ROOT = ROOT
$LOAD_PATH << File.join(ROOT, 'lib')
$LOAD_PATH << File.join(ROOT, 'lib', 'paperclip')
require File.join(ROOT, 'lib', 'paperclip.rb')
FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
ActiveRecord::Base.establish_connection(config[ENV['RAILS_ENV'] || 'test'])
def rebuild_model options = {}
ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
table.column :avatar_file_name, :string
table.column :avatar_content_type, :string
table.column :avatar_file_size, :integer
end
ActiveRecord::Base.send(:include, Paperclip)
Object.send(:remove_const, "Dummy") rescue nil
Object.const_set("Dummy", Class.new(ActiveRecord::Base))
Dummy.class_eval do
include Paperclip
has_attached_file :avatar, options
end
end
class << Test::Unit::TestCase
def context name, &block
(@contexts ||= []) << name
(@context_blocks ||= []) << block
saved_setups = (@context_setups ||= []).dup
saved_teardowns = (@context_teardowns ||= []).dup
self.instance_eval(&block)
@context_setups = saved_setups
@context_teardowns = saved_teardowns
@contexts.pop
@context_blocks.pop
end
def setup &block
@context_setups << block
end
def teardown &block
@context_teardowns << block
end
def should name, &test
context_setups = @context_setups.dup
context_teardowns = @context_teardowns.dup
define_method(["test:", @contexts, "should", name].flatten.join(" ")) do
context_setups.each { |setup| self.instance_eval(&setup) }
self.instance_eval(&test)
context_teardowns.each { |teardown| self.instance_eval(&teardown) }
end
end
def should_eventually name
define_method(["test:", @contexts, "should eventually", name].flatten.join(" ")) do
STDOUT.print "X"
assert true
end
end
end
\ No newline at end of file
require 'test/unit'
require File.dirname(__FILE__) + "/test_helper.rb"
require 'test/helper'
class TestAttachment < Test::Unit::TestCase
context "An attachment" do
setup do
@dummy = {}
@definition = Paperclip::AttachmentDefinition.new("thing", {})
@attachment = Paperclip::Attachment.new(@dummy, "thing", @definition)
end
end
context "The class Foo" do
setup do
ActiveRecord::Base.connection.create_table :foos, :force => true do |table|
table.column :image_file_name, :string
table.column :image_content_type, :string
table.column :image_file_size, :integer
table.column :document_file_name, :string
table.column :document_content_type, :string
table.column :document_file_size, :integer
end
Object.send(:remove_const, :Foo) rescue nil
class ::Foo < ActiveRecord::Base; end
end
context "with an image attached to :image" do
setup do
assert Foo.has_attached_file(:image)
@foo = Foo.new
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "test_image.jpg"))
assert_nothing_raised{ @foo.image = @file }
end
should "be able to have a file assigned with :image=" do
assert_equal "test_image.jpg", @foo.image.original_filename
assert_equal "image/jpg", @foo.image.content_type
end
should "be able to retrieve the data as a blob" do
@file.rewind
assert_equal @file.read, @foo.image.read
end
class Dummy
# This is a dummy class
end
context "and saved" do
class AttachmentTest < Test::Unit::TestCase
context "An attachment" do
setup do
assert @foo.save
end
should "have no errors" do
assert @foo.image.errors.blank?
assert @foo.errors.blank?
end
should "have a file on the filesystem" do
assert @foo.image.send(:file_name)
assert File.file?(@foo.image.send(:file_name)), @foo.image.send(:file_name)
assert File.size(@foo.image.send(:file_name)) > 0
assert_match /405x375/, `identify '#{@foo.image.send(:file_name)}'`
assert_equal IO.read(@file.path), @foo.image.read
end
context "and then deleted" do
@default_options = {
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
}
@instance = stub
@instance.stubs(:id).returns(41)
@instance.stubs(:class).returns(Dummy)
@instance.stubs(:[]).with(:test_file_name).returns("5k.png")
@instance.stubs(:[]).with(:test_content_type).returns("image/png")
@instance.stubs(:[]).with(:test_file_size).returns(12345)
@attachment = Paperclip::Attachment.new(:test, @instance, @default_options)
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"))
end
context "when expecting three styles" do
setup do
assert @foo.destroy
end
should "have no errors" do
assert @foo.image.errors.blank?
end
should "have no files on the filesystem" do
assert !File.file?(@foo.image.send(:file_name)), @foo.image.send(:file_name)
assert !File.exist?(@foo.image.send(:file_name)), @foo.image.send(:file_name)
end
@attachment = Paperclip::Attachment.new(:test, @instance, @default_options.merge({
:styles => { :large => ["400x400", :png],
:medium => ["100x100", :gif],
:small => ["32x32#", :jpg]}
}))
end
context "and then set to null and resaved" do
context "and assigned a file" do
setup do
@foo.image = nil
assert @foo.save
@instance.expects(:[]=).with(:test_file_name, File.basename(@file.path))
@instance.expects(:[]=).with(:test_content_type, "image/png")
@instance.expects(:[]=).with(:test_file_size, @file.size)
@instance.expects(:[]=).with(:test_file_name, nil)
@instance.expects(:[]=).with(:test_content_type, nil)
@instance.expects(:[]=).with(:test_file_size, nil)
@attachment.assign(@file)
end
should "have no errors" do
assert @foo.image.errors.blank?
should "be dirty" do
assert @attachment.dirty?
end
should "have no files on the filesystem" do
assert !File.file?(@foo.image.send(:file_name)), @foo.image.send(:file_name)
assert !File.exist?(@foo.image.send(:file_name)), @foo.image.send(:file_name)
end
end
should "have its image and attachments as tempfiles" do
[nil, :large, :medium, :small].each do |style|
assert File.exists?(@attachment.to_io(style))
end
end
context "with an image with thumbnails attached to :image and saved" do
context "and saved" do
setup do
assert Foo.has_attached_file(:image, :styles => {:small => "16x16", :medium => "100x100", :large => "250x250", :square => "32x32#"})
@foo = Foo.new
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "test_image.jpg"))
assert_nothing_raised{ @foo.image = @file }
assert @foo.save
end
should "have no errors" do
assert @foo.image.errors.blank?, @foo.image.errors.inspect
assert @foo.errors.blank?
end
[:original, :small, :medium, :large, :square].each do |style|
should "have a file for #{style} on the filesystem" do
assert @foo.image.send(:file_name)
assert File.file?(@foo.image.send(:file_name)), @foo.image.send(:file_name)
assert File.size(@foo.image.send(:file_name)) > 0
assert_equal IO.read(@file.path), @foo.image.read
end
should "return the correct urls when asked for the #{style} image" do
assert_equal "/foos/images/1/#{style}_test_image.jpg", @foo.image.url(style)
end
end
should "produce the correct dimensions when each style is identified" do
assert_match /16x15/, `identify '#{@foo.image.send(:file_name, :small)}'`
assert_match /32x32/, `identify '#{@foo.image.send(:file_name, :square)}'`
assert_match /100x93/, `identify '#{@foo.image.send(:file_name, :medium)}'`
assert_match /250x231/, `identify '#{@foo.image.send(:file_name, :large)}'`
assert_match /405x375/, `identify '#{@foo.image.send(:file_name, :original)}'`
end
@attachment.save
end
context "with an image with thumbnails attached to :image and a document attached to :document" do
should "commit the files to disk" do
[nil, :large, :medium, :small].each do |style|
io = @attachment.to_io(style)
assert File.exists?(io)
assert ! io.is_a?(::Tempfile)
end
context "with an invalid image with a square thumbnail attached to :image" do
setup do
assert Foo.has_attached_file(:image, :styles => {:square => "32x32#"})
assert Foo.validates_attached_file(:image)
@foo = Foo.new
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "test_invalid_image.jpg"))
assert_nothing_raised{ @foo.image = @file }
end
should "not save and should report errors from identify" do
assert !@foo.save
assert @foo.errors.on(:image)
assert @foo.errors.on(:image).any?{|e| e.match(/does not contain a valid image/) }, @foo.errors.on(:image)
should "save the files as the right formats and sizes" do
[[:large, 400, 61, "PNG"], [:medium, 100, 15, "GIF"], [:small, 32, 32, "JPEG"]].each do |style|
out = `identify -format "%w %h %b %m" #{@attachment.to_io(style.first).path}`
width, height, size, format = out.split(" ")
assert_equal style[1].to_s, width.to_s
assert_equal style[2].to_s, height.to_s
assert_equal style[3].to_s, format.to_s
end
end
context "with an invalid image attached to :image" do
setup do
assert Foo.has_attached_file(:image, :styles => {:sorta_square => "32x32"})
assert Foo.validates_attached_file(:image)
@foo = Foo.new
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "test_invalid_image.jpg"))
assert_nothing_raised{ @foo.image = @file }
end
should "not save and should report errors from convert" do
assert !@foo.save
assert @foo.errors.on(:image)
assert @foo.errors.on(:image).any?{|e| e.match(/because of an error/) }, @foo.errors.on(:image)
end
end
end
......
require 'test/unit'
require File.dirname(__FILE__) + "/test_helper.rb"
class TestAttachmentDefinition < Test::Unit::TestCase
context "Attachment definitions" do
should "allow overriding options" do
not_expected = Paperclip::AttachmentDefinition.defaults[:path]
Paperclip::AttachmentDefinition.defaults[:path] = "123"
assert_not_equal not_expected, Paperclip::AttachmentDefinition.defaults[:path]
assert_equal "123", Paperclip::AttachmentDefinition.defaults[:path]
end
should "accept options that override defaults" do
@def = Paperclip::AttachmentDefinition.new "attachment", :path => "123", :delete_on_destroy => false
assert_not_equal Paperclip::AttachmentDefinition.defaults[:path], @def.path
assert_not_equal Paperclip::AttachmentDefinition.defaults[:delete_on_destroy], @def.delete_on_destroy
assert_equal "123", @def.path
assert_equal false, @def.delete_on_destroy
end
end
context "An attachment defintion" do
setup do
@options = {
:path => "/home/stuff/place",
:url => "/attachments/:attachment/:name",
:custom_definition => :boogie!,
:styles => {:thumb => "100x100", :large => "300x300>"},
:validates_existance => true,
:validates_size => [0, 2048]
}
@def = Paperclip::AttachmentDefinition.new "attachment", @options
end
should "automatically look in the hash for missing methods" do
assert ! @def.respond_to?(:custom_defintion)
assert_equal :boogie!, @def.custom_definition
end
should "be able to read options using attribute readers" do
(@options.keys - [:styles]).each do |key|
assert_equal @options[key], @def.send(key)
end
end
should "return styles as the styles option plus the original" do
assert_equal( (@options[:styles].keys + [:original]).map(&:to_s).sort.uniq, @def.styles.keys.map(&:to_s).sort )
end
should "return all validations when sent :validations" do
assert @def.validations[:existance] == true, @def.validations[:existance]
assert @def.validations[:size] == [0, 2048], @def.validations[:size]
end
end
end
\ No newline at end of file
require 'rubygems'
require 'test/unit'
require 'shoulda'
require File.join(File.dirname(__FILE__), '..', 'lib', 'paperclip', 'geometry.rb')
class PaperclipTest < Test::Unit::TestCase
context "Paperclip::Geometry" do
should "correctly report its given dimensions" do
assert @geo = Paperclip::Geometry.new(1024, 768)
assert_equal 1024, @geo.width
assert_equal 768, @geo.height
end
should "correctly create a square if the height dimension is missing" do
assert @geo = Paperclip::Geometry.new(1024)
assert_equal 1024, @geo.width
assert_equal 1024, @geo.height
end
should "correctly create a square if the width dimension is missing" do
assert @geo = Paperclip::Geometry.new(nil, 768)
assert_equal 768, @geo.width
assert_equal 768, @geo.height
end
should "be generated from a WxH-formatted string" do
assert @geo = Paperclip::Geometry.parse("800x600")
assert_equal 800, @geo.width
assert_equal 600, @geo.height
end
should "be generated from a xH-formatted string" do
assert @geo = Paperclip::Geometry.parse("x600")
assert_equal 600, @geo.width
assert_equal 600, @geo.height
end
should "be generated from a Wx-formatted string" do
assert @geo = Paperclip::Geometry.parse("800x")
assert_equal 800, @geo.width
assert_equal 800, @geo.height
end
should "be generated from a file" do
file = Dir.glob("/Users/jyurek/Pictures/*.jpg").first
file = File.new(file)
assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
assert @geo.height > 0
assert @geo.width > 0
end
should "be generated from a file path" do
file = Dir.glob("/Users/jyurek/Pictures/*.jpg").first
assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
assert @geo.height > 0
assert @geo.width > 0
end
should "not generate from a bad file" do
file = "/home/This File Does Not Exist.omg"
assert_raise(Errno::ENOENT){ @geo = Paperclip::Geometry.from_file(file) }
end
[['vertical', 900, 1440, true, false, false, 1440, 900, 0.625],
['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333],
['square', 100, 100, false, false, true, 100, 100, 1]].each do |args|
context "performing calculations on a #{args[0]} viewport" do
setup do
@geo = Paperclip::Geometry.new(args[1], args[2])
end
should "#{args[3] ? "" : "not"} be vertical" do
assert_equal args[3], @geo.vertical?
end
should "#{args[4] ? "" : "not"} be horizontal" do
assert_equal args[4], @geo.horizontal?
end
should "#{args[5] ? "" : "not"} be square" do
assert_equal args[5], @geo.square?
end
should "report that #{args[6]} is the larger dimension" do
assert_equal args[6], @geo.larger
end
should "report that #{args[7]} is the smaller dimension" do
assert_equal args[7], @geo.smaller
end
should "have an aspect ratio of #{args[8]}" do
assert_in_delta args[8], @geo.aspect, 0.0001
end
end
end
[[ [1000, 100], [64, 64], "x64", "64x64+288+0" ],
[ [100, 1000], [50, 950], "x950", "50x950+22+0" ],
[ [100, 1000], [50, 25], "50x", "50x25+0+237" ]]. each do |args|
context "of #{args[0].inspect} and given a Geometry #{args[1].inspect} and sent transform_to" do
setup do
@geo = Paperclip::Geometry.new(*args[0])
@dst = Paperclip::Geometry.new(*args[1])
@scale, @crop = @geo.transformation_to @dst, true
end
should "be able to return the correct scaling transformation geometry #{args[2]}" do
assert_equal args[2], @scale
end
should "be able to return the correct crop transformation geometry #{args[3]}" do
assert_equal args[3], @crop
end
end
end
end
end
require 'rubygems'
require 'test/unit'
require 'active_record'
require 'active_record/fixtures'
require 'fileutils'
require 'pp'
require File.dirname(__FILE__) + "/simply_shoulda.rb"
require File.dirname(__FILE__) + "/../init.rb"
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
ActiveRecord::Base.establish_connection(config[ENV['RAILS_ENV'] || 'test'])
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
RAILS_ROOT = "test" unless Object.const_defined? "RAILS_ROOT"
class Test::Unit::TestCase #:nodoc:
def create_fixtures(*table_names)
if block_given?
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
else
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
end
end
def self.load_all_fixtures
all_fixtures = Dir.glob("#{File.dirname(__FILE__)}/fixtures/*.yml").collect do |f|
puts "Loading fixture '#{f}'"
File.basename(f).gsub(/\.yml$/, "").to_sym
end
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, all_fixtures)
end
# Turn off transactional fixtures if you're working with MyISAM tables in MySQL
self.use_transactional_fixtures = true
# Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
self.use_instantiated_fixtures = false
# Add more helper methods to be used by all tests here...
end
\ No newline at end of file
require 'test/helper.rb'
class PaperclipTest < Test::Unit::TestCase
context "A model with an attachment" do
setup do
rebuild_model :styles => { :large => "300x300>",
:medium => "100x100",
:thumb => ["32x32#", :gif] },
:default_style => :medium,
:url => "/:attachment/:class/:style/:id/:basename.:extension",
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
end
should "integrate" do
@dummy = Dummy.new
@file = File.new(File.join(FIXTURES_DIR, "5k.png"))
@bad_file = File.new(File.join(FIXTURES_DIR, "bad.png"))
assert @dummy.avatar = @file
assert @dummy.valid?
assert @dummy.save
assert_equal "100x15", `identify -format "%wx%h" #{@dummy.avatar.to_io.path}`.chomp
assert_equal "434x66", `identify -format "%wx%h" #{@dummy.avatar.to_io(:original).path}`.chomp
assert_equal "300x46", `identify -format "%wx%h" #{@dummy.avatar.to_io(:large).path}`.chomp
assert_equal "100x15", `identify -format "%wx%h" #{@dummy.avatar.to_io(:medium).path}`.chomp
assert_equal "32x32", `identify -format "%wx%h" #{@dummy.avatar.to_io(:thumb).path}`.chomp
saved_paths = [:thumb, :medium, :large, :original].collect{|s| @dummy.avatar.to_io(s).path }
@d2 = Dummy.find(@dummy.id)
assert_equal "100x15", `identify -format "%wx%h" #{@dummy.avatar.to_io.path}`.chomp
assert_equal "434x66", `identify -format "%wx%h" #{@dummy.avatar.to_io(:original).path}`.chomp
assert_equal "300x46", `identify -format "%wx%h" #{@d2.avatar.to_io(:large).path}`.chomp
assert_equal "100x15", `identify -format "%wx%h" #{@d2.avatar.to_io(:medium).path}`.chomp
assert_equal "32x32", `identify -format "%wx%h" #{@d2.avatar.to_io(:thumb).path}`.chomp
@dummy.avatar = nil
assert_nil @dummy.avatar_file_name
assert @dummy.valid?
assert @dummy.save
saved_paths.each do |p|
assert ! File.exists?(p)
end
@d2 = Dummy.find(@dummy.id)
assert_nil @d2.avatar_file_name
@d2.avatar = @bad_file
assert ! @d2.valid?
@d2.avatar = nil
assert @d2.valid?
Dummy.validates_attachment_presence :avatar
@d3 = Dummy.find(@d2.id)
@d3.avatar = @file
assert @d3.valid?
@d3.avatar = @bad_file
assert ! @d3.valid?
@d3.avatar = nil
assert ! @d3.valid?
@dummy.avatar = @file
assert @dummy.save
@dummy.avatar = nil
assert_nil @dummy.avatar_file_name
@dummy.reload
assert_equal "5k.png", @dummy.avatar_file_name
end
end
end
require 'rubygems'
require 'test/unit'
require 'stringio'
require 'tempfile'
require 'shoulda'
require File.join(File.dirname(__FILE__), '..', 'lib', 'paperclip', 'iostream.rb')
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
context "A file" do
setup do
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"))
end
context "that is sent #stream_to" do
[["/tmp/iostream.string.test", File],
[Tempfile.new('iostream.test'), Tempfile]].each do |args|
context "and given a #{args[0].class.to_s}" do
setup do
assert @result = @file.stream_to(args[0])
end
should "return a #{args[1].to_s}" do
assert @result.is_a?(args[1])
end
should "contain the same data as the original file" do
@file.rewind; @result.rewind
assert_equal @file.read, @result.read
end
end
end
end
context "that is sent #to_tempfile" do
setup do
assert @tempfile = @file.to_tempfile
end
should "convert it to a Tempfile" do
assert @tempfile.is_a?(Tempfile)
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
require 'test/unit'
require File.dirname(__FILE__) + "/test_helper.rb"
require 'test/helper.rb'
class TestPaperclip < Test::Unit::TestCase
context "Paperclip" do
should "allow overriding options" do
[:image_magick_path, :whiny_deletes, :whiny_thumbnails].each do |option|
not_expected = Paperclip.options[option]
Paperclip.options[option] = "123"
assert_equal "123", Paperclip.options[option]
assert_not_equal not_expected, Paperclip.options[option]
end
end
should "give the correct path for a command" do
expected = "/usr/bin/wtf"
Paperclip.options[:image_magick_path] = "/usr/bin"
assert_equal expected, Paperclip.path_for_command("wtf")
expected = "wtf"
Paperclip.options[:image_magick_path] = nil
assert_equal expected, Paperclip.path_for_command("wtf")
end
context "being used on improper class Improper" do
class PaperclipTest < Test::Unit::TestCase
context "An ActiveRecord model with an 'avatar' attachment" do
setup do
ActiveRecord::Base.connection.create_table :impropers, :force => true do |table|
# Empty table
rebuild_model
end
Object.send(:remove_const, :Improper) rescue nil
class ::Improper < ActiveRecord::Base; end
should "have an #avatar method" do
assert Dummy.new.respond_to?(:avatar)
end
should "raises an error when an attachment is defined" do
assert_raises(Paperclip::PaperclipError){ Improper.has_attached_file :image }
should "have an #avatar= method" do
assert Dummy.new.respond_to?(:avatar=)
end
[:file_name, :content_type].each do |column|
context "which has only the #{column} column" do
[[:presence, nil, "5k.png", nil],
[:size, {:in => 1..10240}, "5k.png", "12k.png"]].each do |args|
context "with #{args[0]} validations" do
setup do
ActiveRecord::Base.connection.create_table :impropers, :force => true do |table|
table.column :"image_#{column}", :string
end
Object.send(:remove_const, :Improper) rescue nil
class ::Improper < ActiveRecord::Base; end
end
should "raises an error when an attachment is defined" do
assert_raises(Paperclip::PaperclipError){ Improper.has_attached_file :image }
end
end
Dummy.class_eval do
send(*[:"validates_attachment_#{args[0]}", :avatar, args[1]].compact)
end
@dummy = Dummy.new
end
context "being used on class Foo" do
context "and a valid file" do
setup do
ActiveRecord::Base.connection.create_table :foos, :force => true do |table|
table.column :image_file_name, :string
table.column :image_content_type, :string
table.column :image_file_size, :integer
@file = args[2] && File.new(File.join(FIXTURES_DIR, args[2]))
end
table.column :document_file_name, :string
table.column :document_content_type, :string
table.column :document_file_size, :integer
should "not have any errors" do
@dummy.avatar = @file
assert @dummy.avatar.valid?
assert_equal 0, @dummy.avatar.errors.length
end
Object.send(:remove_const, :Foo) rescue nil
class ::Foo < ActiveRecord::Base; end
end
should "be able to assign a default attachment" do
assert Foo.has_attached_file(:image)
assert_equal [:image], Foo.attached_files
foo = Foo.new
assert foo.respond_to?(:image)
assert foo.image.is_a?(Paperclip::Attachment)
context "and an invalid file" do
setup do
@file = args[3] && File.new(File.join(FIXTURES_DIR, args[3]))
end
should "be able to assign two attachments separately" do
assert Foo.has_attached_file(:image)
assert Foo.has_attached_file(:document)
assert_equal [:image, :document], Foo.attached_files
foo = Foo.new
assert foo.respond_to?(:image)
assert foo.respond_to?(:document)
assert foo.image.is_a?(Paperclip::Attachment)
assert foo.document.is_a?(Paperclip::Attachment)
assert foo.image != foo.document
should "have errors" do
@dummy.avatar = @file
assert ! @dummy.avatar.valid?
assert_equal 1, @dummy.avatar.errors.length
end
should "be able to assign two attachments simultaneously" do
assert Foo.has_attached_file(:image, :document)
assert_equal [:image, :document], Foo.attached_files
foo = Foo.new
assert foo.respond_to?(:image)
assert foo.respond_to?(:document)
assert foo.image.is_a?(Paperclip::Attachment)
assert foo.document.is_a?(Paperclip::Attachment)
assert foo.image != foo.document
end
should "be able to set options on attachments" do
assert Foo.has_attached_file :image, :thumbnails => {:thumb => "100x100"}
assert_equal [:image], Foo.attached_files
assert_equal( {:thumb => "100x100"}, Foo.attachment_definition_for(:image).thumbnails )
foo = Foo.new
assert foo.respond_to?(:image)
assert foo.image.is_a?(Paperclip::Attachment)
end
end
end
end
require 'rubygems'
require 'test/unit'
require 'shoulda'
require 'mocha'
require 'tempfile'
require File.join(File.dirname(__FILE__), '..', 'lib', 'paperclip', 'geometry.rb')
require File.join(File.dirname(__FILE__), '..', 'lib', 'paperclip', 'thumbnail.rb')
class ThumbnailTest < Test::Unit::TestCase
context "A Paperclip Tempfile" do
setup do
@tempfile = Paperclip::Tempfile.new("file.jpg")
end
should "have its path contain a real extension" do
assert_equal ".jpg", File.extname(@tempfile.path)
end
should "be a real Tempfile" do
assert @tempfile.is_a?(::Tempfile)
end
end
context "Another Paperclip Tempfile" do
setup do
@tempfile = Paperclip::Tempfile.new("file")
end
should "not have an extension if not given one" do
assert_equal "", File.extname(@tempfile.path)
end
should "still be a real Tempfile" do
assert @tempfile.is_a?(::Tempfile)
end
end
context "An image" do
setup do
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"))
end
context "being thumbnailed at 100x50 with cropping" do
setup do
@thumb = Paperclip::Thumbnail.new(@file, "100x50#")
end
should "report its correct current and target geometries" do
assert_equal "100x50", @thumb.target_geometry.to_s
assert_equal "434x66", @thumb.current_geometry.to_s
end
should "report its correct format" do
assert_nil @thumb.format
end
should "have whiny_thumbnails turned on by default" do
assert @thumb.whiny_thumbnails
end
should "send the right command to convert when sent #make" do
@thumb.expects(:system).with do |arg|
arg.match %r{convert\s+"#{File.expand_path(@thumb.file.path)}"\s+-scale\s+x50\s+-crop\s+100x50\+114\+0\s+\+repage\s+".*?"}
end
@thumb.make
end
should "create the thumbnail when sent #make" do
dst = @thumb.make
assert_match /100x50/, `identify #{dst.path}`
end
end
end
end
require 'test/unit'
require File.dirname(__FILE__) + "/test_helper.rb"
class TestThumbnailer < Test::Unit::TestCase
context "The Thumbnailer" do
should "calculate geometries for cropping images" do
@file = IO.read(File.join(File.dirname(__FILE__), "fixtures", "test_image.jpg"))
assert_equal ["50x", "50x25+0+10"], Paperclip::Thumbnail.new("50x25", @file).geometry_for_crop
assert_equal ["x50", "50x50+2+0"], Paperclip::Thumbnail.new("50x50", @file).geometry_for_crop
assert_equal ["x50", "25x50+14+0"], Paperclip::Thumbnail.new("25x50", @file).geometry_for_crop
end
should "be able to pipe commands" do
doc = %w(one two three four five)
expected = %w(five four one three two)
assert_equal expected, Paperclip::Thumbnail.piping(doc.join("\n"), "sort").split("\n")
assert_equal "Hello, World!\n", Paperclip::Thumbnail.piping("World", "ruby -e 'puts %Q{Hello, \#{STDIN.read}!}'")
end
[
[:square, 125, 125],
[:long, 53, 225],
[:tall, 225, 53],
[:tiny, 16, 16]
].each do |size, width, height|
context "given a #{size} image" do
setup do
@base_file = IO.read(File.join(File.dirname(__FILE__), "fixtures", "test_image.jpg"))
@file = Paperclip::Thumbnail.piping(@base_file, "convert - -scale '#{width}x#{height}!' -")
assert_match /#{width}x#{height}/, Paperclip::Thumbnailer.piping(@file, "identify -")
@targets = {
:small => "50x50",
:same => nil,
:large => "100x100",
:shrink_to_large => "100x100>",
:crop_medium => "75x75#"
}
end
should_eventually "generate correct thumbnails for the image"
end
end
end
end
\ No newline at end of file
require 'test/unit'
require File.dirname(__FILE__) + "/test_helper.rb"
class TestUpfile < Test::Unit::TestCase
context "Using Upfile" do
setup do
File.send :include, Paperclip::Upfile
@filename = File.join(File.dirname(__FILE__), "fixtures", "test_image.jpg")
@file = File.new(@filename)
end
should "allow File objects to respond as uploaded files do" do
assert_respond_to @file, :original_filename
assert_respond_to @file, :content_type
assert_respond_to @file, :size
assert_equal "test_image.jpg", @file.original_filename
assert_equal "image/jpg", @file.content_type
assert_equal @file.stat.size, @file.size
end
end
end
\ No newline at end of file
# Uninstall hook code here
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment