Commit 11086ba6 by jyurek

Re-refactoring, plus the beginning of lots of tests.

git-svn-id: https://svn.thoughtbot.com/plugins/paperclip/trunk@242 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
parent 26444ced
......@@ -8,7 +8,7 @@ task :default => [:clean, :test]
desc 'Test the paperclip plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib' << 'profile'
t.pattern = 'test/**/*_test.rb'
t.pattern = 'test/**/test_*.rb'
t.verbose = true
end
......
......@@ -56,8 +56,8 @@ module Paperclip
class AttachmentDefinition
def self.defaults
@defaults ||= {
:path => ":rails_root/public/:class/:attachment/:id/:style_:name",
:url => "/:class/:attachment/:id/:style_:name",
:path => ":rails_root/public/:class/:attachment/:id/:style_:filename",
:url => "/:class/:attachment/:id/:style_:filename",
:missing_url => "/:class/:attachment/:style_missing.png",
:attachment_type => :image,
:thumbnails => {},
......@@ -80,7 +80,7 @@ module Paperclip
end
def thumbnails
@thumbnails ||= @options[:thumbnails]
@thumbnails ||= @options[:thumbnails] || {}
end
def validate thing, *constraints
......@@ -90,8 +90,8 @@ module Paperclip
def validations
@validations ||= @options.inject({}) do |valids, opts|
key, val = opts
if (m = key.to_s.match(/^validate_(.+)/))
valids[m[1]] = val
if (m = key.to_s.match(/^validates?_(.+)/))
valids[m[1].to_sym] = val
end
valids
end
......@@ -108,9 +108,9 @@ module Paperclip
class Attachment
attr_reader :name, :instance, :original_filename, :content_type, :original_file_size, :definition, :errors
def initialize name, active_record, definition
def initialize active_record, name, definition
@instance = active_record
@definition = defintiion
@definition = definition
@name = name
@errors = []
......@@ -132,7 +132,7 @@ module Paperclip
self[:original] = uploaded_file
@dirty = true
if definition.type == :image
if definition.attachment_type == :image
make_thumbnails_from uploaded_file
end
end
......@@ -147,7 +147,7 @@ module Paperclip
def clear_files
@files = {}
definition.styles.each{|style| @files[style] = nil }
definition.styles.each{|style, geo| @files[style] = nil }
@dirty = false
end
......@@ -180,17 +180,18 @@ module Paperclip
clear_files
end
def queue_destroy(complain = false)
def destroy(complain = false)
returning true do
@delete_on_save = true
@complain_on_delete = complain
self.original_filename = nil
self.content_type = nil
self.original_file_size = nil
clear_files
end
end
def destroy
def destroy!
delete_attachment if definition.delete_on_destroy
end
......@@ -205,7 +206,8 @@ module Paperclip
end
def read style = nil
self[style] ? self[style].read : IO.read(file_name(style))
style ||= definition.default_style
self[style] ? (self[style].rewind && self[style].read) : IO.read(file_name(style))
end
def validate_existence *constraints
......@@ -296,7 +298,7 @@ module Paperclip
raise PaperclipError, "could not be thumbnailed."
end
if Paperclip.options[:whiny_thumbnails] && !$?.success?
raise PaperclipError, "could not be thumbaniled because of an error with 'convert'."
raise PaperclipError, "could not be thumbnailed because of an error with 'convert'."
end
thumb
end
......@@ -316,14 +318,14 @@ module Paperclip
scale_geometry, scale = if dst[0] == dst[1]
if srch
[ "x#{dst[1]}", src[1] / dst[1] ]
[ "x#{dst[1].to_i}", src[1] / dst[1] ]
else
[ "#{dst[0]}x", src[0] / dst[0] ]
[ "#{dst[0].to_i}x", src[0] / dst[0] ]
end
elsif dsth
[ "#{dst[0]}x", src[0] / dst[0] ]
[ "#{dst[0].to_i}x", src[0] / dst[0] ]
else
[ "x#{dst[1]}", src[1] / dst[1] ]
[ "x#{dst[1].to_i}", src[1] / dst[1] ]
end
crop_geometry = if dsth
......@@ -348,14 +350,16 @@ module Paperclip
:class => lambda{|style| self.instance.class.to_s.underscore.pluralize },
:style => lambda{|style| style.to_s },
:attachment => lambda{|style| self.name.to_s.pluralize },
:filename => lambda{|style| self.original_filename }
:filename => lambda{|style| self.original_filename },
:basename => lambda{|style| self.original_filename.gsub(/\..*$/, "") },
:extension => lambda{|style| self.original_filename.gsub(/^.*./, "") }
}
end
def interpolate style, source
returning source.dup do |s|
interpolations.each do |key, proc|
s.gsub!(/:#{key}/){ proc.call(instance, style) }
s.gsub!(/:#{key}/){ proc.call(style) }
end
end
end
......@@ -395,8 +399,13 @@ module Paperclip
options = attachment_names.last.is_a?(Hash) ? attachment_names.pop : {}
include InstanceMethods
after_save :save_attached_files
before_destroy :destroy_attached_files
#class_inheritable_hash :attachment_definitions
@attachment_definitions ||= {}
@attachment_names ||= []
@attachment_names += attachment_names
attachment_names.each do |aname|
whine_about_columns_for aname
......@@ -413,7 +422,7 @@ module Paperclip
end
def attached_files
@attachment_definitions.keys
@attachment_names
end
def attachment_definition_for attachment
......@@ -442,7 +451,19 @@ module Paperclip
module InstanceMethods #:nodoc:
def attachment_for name
@attachments ||= {}
@attachments[name] ||= Attachment.new(self, name)
@attachments[name] ||= Attachment.new(self, name, self.class.attachment_definition_for(name))
end
def save_attached_files
@attachments.each do |name, attachment|
attachment.save
end
end
def destroy_attached_files
@attachments.each do |name, attachment|
attachment.destroy!
end
end
end
......@@ -462,7 +483,7 @@ module Paperclip
# Returns the file's normal name.
def original_filename
self.path
File.basename(self.path)
end
# Returns the size of the file.
......
module Thoughtbot
module Paperclip
class Attachment
attr_reader :name, :instance, :original_filename, :content_type, :original_file_size, :definition, :errors
def initialize name, active_record
@instance = active_record
@definition = @instance.class.attachment_definitions[name]
@name = name
@errors = []
self.original_filename = @instance["#{name}_file_name"]
self.content_type = @instance["#{name}_content_type"]
self.original_file_size = @instance["#{name}_file_size"]
@files = {}
@dirty = false
self.class.send :include, definition.storage_module
end
def assign uploaded_file
uploaded_file = fetch_uri(uploaded_file) if uploaded_file.is_a? URI
return queue_destroy if uploaded_file.nil?
return unless is_a_file? uploaded_file
self.original_filename = sanitize_filename(uploaded_file.original_filename)
self.content_type = uploaded_file.content_type
self.original_file_size = uploaded_file.size
self[:original] = uploaded_file
@dirty = true
if definition.type == :image
make_thumbnails_from uploaded_file
end
end
def [](style)
@files ||= {}
@files[style]
end
alias_method :file_for, :[]
def []=(style, data)
@files ||= {}
@files[style] = data
end
def clear_files
@files = nil
@dirty = false
end
def for_attached_files
@files.each do |style, data|
if data
data.rewind if data.respond_to? :rewind
yield style, (data.respond_to?(:read) ? data.read : data)
end
end
end
def dirty?
@dirty
end
# Validations
def valid?
definition.validations.each do |validation, constraints|
send("validate_#{validation}", *constraints)
end
errors.empty?
end
# ActiveRecord Callbacks
def save
write_attachment if dirty?
delete_attachment if @delete_on_save
@delete_on_save = false
clear_files
end
def queue_destroy(complain = false)
returning true do
@delete_on_save = true
@complain_on_delete = complain
self.original_filename = nil
self.content_type = nil
clear_files
end
end
def destroy
delete_attachment if definition.delete_on_destroy
end
# Image Methods
def make_thumbnails_from data
begin
definition.styles.each do |style, geometry|
self[style] = make_thumbnail geometry, data
end
rescue PaperclipError => e
errors << e.message
clear_files
self[:original] = data
end
end
def make_thumbnail geometry, data
return data if geometry.nil?
operator = geometry[-1,1]
begin
geometry, crop_geometry = geometry_for_crop(geometry, data) if operator == '#'
convert = Thoughtbot::Paperclip.path_for_command("convert")
command = "#{convert} - -scale '#{geometry}' #{operator == '#' ? "-crop '#{crop_geometry}'" : ""} - 2>/dev/null"
thumb = IO.popen(command, "w+") do |io|
data.rewind
io.write(data.read)
io.close_write
StringIO.new(io.read)
end
rescue Errno::EPIPE => e
raise PaperclipError.new(self), "could not be thumbnailed. Is ImageMagick or GraphicsMagick installed and available?"
rescue SystemCallError => e
raise PaperclipError.new(self), "could not be thumbnailed."
end
if Thoughtbot::Paperclip.options[:whiny_thumbnails] && !$?.success?
raise PaperclipError.new(self), "could not be thumbaniled because of an error with 'convert'."
end
thumb
end
def geometry_for_crop geometry, orig_io
identify = Thoughtbot::Paperclip.path_for_command("identify")
IO.popen("#{identify} -", "w+") do |io|
orig_io.rewind
io.write(orig_io.read)
io.close_write
if match = io.read.split[2].match(/(\d+)x(\d+)/)
src = match[1,2].map(&:to_f)
srch = src[0] > src[1]
dst = geometry.match(/(\d+)x(\d+)/)[1,2].map(&:to_f)
dsth = dst[0] > dst[1]
ar = src[0] / src[1]
scale_geometry, scale = if dst[0] == dst[1]
if srch
[ "x#{dst[1]}", src[1] / dst[1] ]
else
[ "#{dst[0]}x", src[0] / dst[0] ]
end
elsif dsth
[ "#{dst[0]}x", src[0] / dst[0] ]
else
[ "x#{dst[1]}", src[1] / dst[1] ]
end
crop_geometry = if dsth
"%dx%d+%d+%d" % [ dst[0], dst[1], 0, (src[1] / scale - dst[1]) / 2 ]
else
"%dx%d+%d+%d" % [ dst[0], dst[1], (src[0] / scale - dst[0]) / 2, 0 ]
end
[ scale_geometry, crop_geometry ]
end
end
end
# Helper Methods
def interpolate style, source
returning source.dup do |s|
s.gsub!(/:rails_root/, RAILS_ROOT)
s.gsub!(/:id/, instance.id.to_s) if instance.id
s.gsub!(/:class/, instance.class.to_s.underscore.pluralize)
s.gsub!(/:style/, style.to_s)
s.gsub!(/:attachment/, name.to_s.pluralize)
if original_filename
file_bits = original_filename.split(".")
s.gsub!(/:name/, original_filename)
s.gsub!(/:base/, [file_bits[0], *file_bits[1..-2]].join("."))
s.gsub!(/:ext/, file_bits.last )
end
end
end
def original_filename= new_name
instance["#{name}_file_name"] = @original_filename = new_name
end
def content_type= new_type
instance["#{name}_content_type"] = @content_type = new_type
end
def original_file_size= new_size
instance["#{name}_file_size"] = @original_file_size = new_size
end
def fetch_uri uri
image = if uri.scheme == 'file'
path = url.gsub(%r{^file://}, '/')
open(path)
else
require 'open-uri'
uri
end
begin
data = StringIO.new(image.read)
uri.extend(Upfile)
class << data
attr_accessor :original_filename, :content_type
end
data.original_filename = uri.original_filename
data.content_type = uri.content_type
data
rescue OpenURI::HTTPError => e
errors << "The file at #{uri.to_s} could not be found."
return nil
end
end
def is_a_file? data
[:size, :content_type, :original_filename, :read].map do |meth|
data.respond_to? meth
end.all?
end
def sanitize_filename filename
File.basename(filename).gsub(/[^\w\.\_]/,'_')
end
protected :sanitize_filename
def to_s
url
end
end
end
end
\ No newline at end of file
module Thoughtbot
module Paperclip
class AttachmentDefinition
def self.defaults
{
:path_prefix => ":rails_root/public",
:url_prefix => "",
:path => ":attachment/:id/:style_:name",
:url => nil,
:attachment_type => :image,
:thumbnails => {},
:delete_on_destroy => true,
:default_style => :original,
:missing_url => "",
:missing_path => "",
:storage => :filesystem
}
end
def initialize name, options
@name = name
@options = AttachmentDefinition.defaults.merge options
end
def name
@name
end
def styles
unless @styles
@styles = @options[:thumbnails]
@styles[:original] = nil
end
@styles
end
def validate thing, *constraints
@options[:"validate_#{thing}"] = (constraints.length == 1 ? constraints.first : constraints)
end
def validations
@validations ||= @options.inject({}) do |valids, opts|
key, val = opts
if (m = key.to_s.match(/^validate_(.+)/))
valids[m[1]] = val
end
valids
end
end
def storage_module
@storage_module ||= Thoughtbot::Paperclip::Storage.const_get(@options[:storage].to_s.camelize)
end
def type
@options[:attachment_type]
end
def default_style
@options[:default_style]
end
def path_prefix
@options[:path_prefix]
end
def url_prefix
@options[:url_prefix]
end
def path
@options[:path]
end
def url
@options[:url]
end
def missing_file_name
@options[:missing_path]
end
def missing_url
@options[:missing_url]
end
def delete_on_destroy
@options[:delete_on_destroy]
end
end
end
end
\ No newline at end of file
module Thoughtbot
module Paperclip
module Storage
# == Filesystem
# Typically, Paperclip stores your files in the filesystem, so that Apache (or whatever your
# main asset server is) can easily access your files without Rails having to be called all
# the time.
module Filesystem
def file_name style = nil
style ||= definition.default_style
pattern = if original_filename && instance.id
File.join(definition.path_prefix, definition.path)
else
definition.missing_file_name
end
interpolate( style, pattern )
end
def url style = nil
style ||= definition.default_style
pattern = if original_filename && instance.id
[definition.url_prefix, definition.url || definition.path].compact.join("/")
else
definition.missing_url
end
interpolate( style, pattern )
end
def write_attachment
ensure_directories
for_attached_files do |style, data|
File.open( file_name(style), "w" ) do |file|
file.rewind
file.write(data)
end
end
end
def delete_attachment complain = false
definition.styles.keys.each do |style|
file_path = file_name(style)
begin
FileUtils.rm file_path if file_path
rescue SystemCallError => e
raise PaperclipError.new(self), "Could not delete thumbnail." if Thoughtbot::Paperclip.options[:whiny_deletes] || complain
end
end
end
def file_exists?(style)
style ||= definition.default_style
dirty? ? file_for(style) : File.exists?( file_name(style) )
end
def validate_existence *constraints
definition.styles.keys.each do |style|
errors << "requires a valid #{style} file." unless file_exists?(style)
end
end
def validate_size *constraints
errors << "file too large. Must be under #{constraints.last} bytes." if original_file_size > constraints.last
errors << "file too small. Must be over #{constraints.first} bytes." if original_file_size <= constraints.first
end
private
def ensure_directories
for_attached_files do |style, file|
dirname = File.dirname( file_name(style) )
FileUtils.mkdir_p dirname
end
end
end
end
end
end
\ No newline at end of file
module Thoughtbot
module Paperclip
module ClassMethods
def has_attached_file_with_s3 *attachment_names
has_attached_file_without_s3 *attachment_names
access_key = secret_key = ""
if file_name = s3_credentials_file
creds = YAML.load_file(file_name)
creds = creds[RAILS_ENV] || creds if Object.const_defined?("RAILS_ENV")
access_key = creds['access_key_id']
secret_key = creds['secret_access_key']
else
access_key = Thoughtbot::Paperclip.options[:s3_access_key_id]
secret_key = Thoughtbot::Paperclip.options[:s3_secret_access_key]
end
if definition.storage_module == Thoughtbot::Paperclip::Storage::S3
require 'aws/s3'
AWS::S3::Base.establish_connection!(
:access_key_id => access_key,
:secret_access_key => secret_key,
:persistent => Thoughtbot::Paperclip.options[:s3_persistent] || true
)
end
end
alias_method_chain :has_attached_file, :s3
private
def s3_credentials_file
[ Thoughtbot::Paperclip.options[:s3_credentials_file], File.join(RAILS_ROOT, "config", "s3.yml") ].compact.each do |f|
return f if File.exists?(f)
end
nil
end
end
class AttachmentDefinition
def s3_access
@options[:s3_access_privilege]
end
end
module Storage
# == Amazon S3 Storage
# Paperclip can store your files in Amazon's S3 Web Service. You can keep your keys in an s3.yml
# file inside the +config+ directory, similarly to your database.yml.
#
# access_key_id: 12345
# secret_access_key: 212434...4656456
#
# You can also environment-namespace the entries like you would in your database.yml:
#
# development:
# access_key_id: 12345
# secret_access_key: 212434...4656456
# production:
# access_key_id: abcde
# secret_access_key: gbkjhg...wgbrtjh
#
# The location of this file is configurable. You don't even have to use it if you don't want. Both
# the file's location or the keys themselves may be located in the Thoughtbot::Paperclip.options
# hash. The S3-related options in this hash are all prefixed with "s3".
#
# Thoughtbot::Paperclip.options = {
# :s3_persistent => true,
# :s3_credentials_file => "/home/me/.private/s3.yml"
# }
#
# This configuration is best placed in your +environment.rb+ or env-specific file.
# The complete list of options is as follows:
# * s3_access_key_id: The Amazon S3 ID you were given to access your account.
# * s3_secret_access_key: The secret key supplied by Amazon. This should be kept far away from prying
# eyes, which is why it's suggested that you keep these keys in a separate file that
# only you and the database can read.
# * s3_credentials_file: The path to the file where your credentials are kept in YAML format, as
# described above.
# * s3_persistent: Maintains an HTTP connection to the Amazon service if possible.
module S3
def file_name style = nil
style ||= definition.default_style
pattern = if original_filename && instance.id
definition.url
else
definition.missing_url
end
interpolate( style, pattern )
end
def url style = nil
"http://s3.amazonaws.com/#{bucket}/#{file_name(style)}"
end
def write_attachment
bucket = ensure_bucket
for_attached_files do |style, data|
AWS::S3::S3Object.store( file_name(style), data, bucket, :access => definition.s3_access || :public_read )
end
end
def delete_attachment complain = false
for_attached_files do |style, data|
begin
AWS::S3::S3Object.delete( file_name(style), bucket )
rescue AWS::S3::ResponseError => error
raise
end
end
end
def file_exists?(style)
style ||= definition.default_style
dirty? ? file_for(style) : AWS::S3::S3Object.exists?( file_name(style), bucket )
end
def validate_existence *constraints
definition.styles.keys.each do |style|
errors << "requires a valid #{style} file." unless file_exists?(style)
end
end
def validate_size *constraints
errors << "file too large. Must be under #{constraints.last} bytes." if original_file_size > constraints.last
errors << "file too small. Must be over #{constraints.first} bytes." if original_file_size <= constraints.first
end
private
def bucket
interpolate(nil, definition.url_prefix)
end
def ensure_bucket
begin
bucket_name = bucket
AWS::S3::Bucket.create(bucket_name)
bucket_name
rescue AWS::S3::S3Exception => e
raise Thoughtbot::Paperclip::PaperclipError.new(attachment), "You are not allowed access to the bucket '#{bucket_name}'."
end
end
end
end
end
end
\ No newline at end of file
module Thoughtbot
module Paperclip
# The Upfile module is a convenience module for adding uploaded-file-looking methods
# to the +File+ class. Useful for testing.
# f = File.new("test/test_avatar.jpg")
# f.original_filename # => "test_avatar.jpg"
# f.content_type # => "image/jpg"
# user.avatar = f
module Upfile
# Infer the MIME-type of the file from the extension.
def content_type
type = self.path.match(/\.(\w+)$/)[1]
case type
when "jpg", "png", "gif" then "image/#{type}"
when "txt", "csv", "xml", "html", "htm" then "text/#{type}"
else "x-application/#{type}"
end
end
# Returns the file's normal name.
def original_filename
self.path
end
# Returns the size of the file.
def size
File.size(self)
end
end
end
end
File.send(:include, Thoughtbot::Paperclip::Upfile)
\ No newline at end of file
begin
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
end
ActiveRecord::Base.connection.create_table :bars, :force => true do |table|
table.column :document_file_name, :string
table.column :document_content_type, :string
table.column :document_file_size, :integer
end
ActiveRecord::Base.connection.create_table :non_standards, :force => true do |table|
table.column :resume_file_name, :string
table.column :resume_content_type, :string
table.column :resume_file_size, :integer
table.column :avatar_file_name, :string
table.column :avatar_content_type, :string
table.column :avatar_file_size, :integer
end
ActiveRecord::Base.connection.create_table :ess_threes, :force => true do |table|
table.column :resume_file_name, :string
table.column :resume_content_type, :string
table.column :resume_file_size, :integer
table.column :avatar_file_name, :string
table.column :avatar_content_type, :string
table.column :avatar_file_size, :integer
end
ActiveRecord::Base.connection.create_table :negatives, :force => true do |table|
table.column :this_is_the_wrong_name_file_name, :string
end
rescue Exception
end
class Foo < ActiveRecord::Base
has_attached_file :image, :attachment_type => :image,
:thumbnails => { :thumb => "100x100>", :medium => "300x300>" },
:path_prefix => "./repository"
end
class Bar < ActiveRecord::Base
has_attached_file :document, :attachment_type => :document,
:path_prefix => "./repository"
validates_attached_file :document
end
class NonStandard < ActiveRecord::Base
has_attached_file :resume, :attachment_type => :document,
:path_prefix => "/tmp",
:path => ":attachment_:id_:name",
:missing_url => "/:class/:style/:attachment/404.txt"
has_attached_file :avatar, :attachment_type => :image,
:thumbnails => { :cropped => "200x10#",
:bigger => "1000x1000",
:smaller => "200x200>",
:square => "150x150#" },
:path_prefix => "./repository",
:path => ":class/:attachment/:id/:style_:name",
:default_style => :square,
:missing_url => "/:class/:style/:attachment/404.png"
end
# class EssThree < ActiveRecord::Base
# has_attached_file :resume, :attachment_type => :document,
# :path_prefix => "paperclip/test",
# :path => ":attachment_:id_:name",
# :missing_url => "/:class/:style/:attachment/404.txt",
# :storage => :S3
# has_attached_file :avatar, :attachment_type => :image,
# :thumbnails => { :cropped => "200x10#",
# :bigger => "1000x1000",
# :smaller => "200x200>",
# :square => "150x150#" },
# :path_prefix => "paperclip/test/images",
# :path => ":class/:attachment/:id/:style_:name",
# :default_style => :square,
# :missing_url => "/:class/:style/:attachment/404.png",
# :storage => :S3
# end
class Negative < ActiveRecord::Base
end
\ No newline at end of file
require 'test/unit'
require File.dirname(__FILE__) + "/test_helper.rb"
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
should "calculate geometries for cropping images" do
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "test_image.jpg"))
assert_equal ["50x", "50x25+0+10"], @attachment.send(:geometry_for_crop, "50x25", @file)
assert_equal ["x50", "50x50+2+0"], @attachment.send(:geometry_for_crop, "50x50", @file)
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
assert_equal @file.read, @foo.image.read
end
context "and saved" 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
end
end
context "with an image with thumbnails attached to :image and saved" do
setup do
assert Foo.has_attached_file(:image, :thumbnails => {: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?
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
end
context "with an image with thumbnails attached to :image and a document attached to :document" do
end
context "with an invalid image attached to :image" do
end
end
end
\ No newline at end of file
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!,
:thumbnails => {: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.each do |key|
assert_equal @options[key], @def.send(key)
end
end
should "return styles as thumbnails plus the original" do
assert( (@def.thumbnails.keys + [:original]).map(&:to_s).sort == @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
......@@ -5,6 +5,9 @@ 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'])
......
require 'test/unit'
require File.dirname(__FILE__) + "/test_helper.rb"
require File.dirname(__FILE__) + "/simply_shoulda.rb"
require File.dirname(__FILE__) + "/../init.rb"
class PaperclipTest < Test::Unit::TestCase
class TestPaperclip < Test::Unit::TestCase
context "Paperclip" do
should "allow overriding options" do
......@@ -16,6 +14,38 @@ class PaperclipTest < Test::Unit::TestCase
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 class Improper" do
setup do
ActiveRecord::Base.connection.create_table :impropers, :force => true do |table|
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
[:file_name, :content_type].each do |column|
context "which has only the #{column} column" 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
end
end
context "being used on class Foo" do
......@@ -36,23 +66,41 @@ class PaperclipTest < Test::Unit::TestCase
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)
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
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
......
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
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