paperclip 2.3.11 → 2.3.16
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of paperclip might be problematic. Click here for more details.
- data/README.md +30 -4
- data/Rakefile +3 -3
- data/init.rb +3 -0
- data/lib/generators/paperclip/paperclip_generator.rb +3 -1
- data/lib/paperclip/attachment.rb +27 -12
- data/lib/paperclip/{callback_compatability.rb → callback_compatibility.rb} +0 -0
- data/lib/paperclip/geometry.rb +4 -1
- data/lib/paperclip/interpolations.rb +8 -3
- data/lib/paperclip/iostream.rb +1 -1
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +20 -14
- data/lib/paperclip/processor.rb +1 -1
- data/lib/paperclip/storage/filesystem.rb +8 -3
- data/lib/paperclip/storage/fog.rb +48 -13
- data/lib/paperclip/storage/s3.rb +54 -16
- data/lib/paperclip/style.rb +4 -3
- data/lib/paperclip/thumbnail.rb +18 -3
- data/lib/paperclip/upfile.rb +20 -13
- data/lib/paperclip/version.rb +1 -1
- data/lib/paperclip.rb +60 -27
- data/lib/tasks/paperclip.rake +32 -23
- data/test/attachment_test.rb +116 -0
- data/test/fixtures/animated.gif +0 -0
- data/test/fog_test.rb +30 -19
- data/test/geometry_test.rb +29 -0
- data/test/helper.rb +3 -0
- data/test/integration_test.rb +40 -4
- data/test/interpolations_test.rb +14 -0
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +42 -2
- data/test/paperclip_test.rb +18 -40
- data/test/storage_test.rb +244 -7
- data/test/style_test.rb +30 -5
- data/test/thumbnail_test.rb +111 -6
- data/test/upfile_test.rb +3 -2
- metadata +103 -122
- data/lib/paperclip/command_line.rb +0 -86
- data/test/command_line_test.rb +0 -138
data/lib/paperclip/style.rb
CHANGED
@@ -30,8 +30,9 @@ module Paperclip
|
|
30
30
|
# (which method (in the attachment) will call any supplied procs)
|
31
31
|
# There is an important change of interface here: a style rule can set its own processors
|
32
32
|
# by default we behave as before, though.
|
33
|
+
# if a proc has been supplied, we call it here
|
33
34
|
def processors
|
34
|
-
@processors || attachment.processors
|
35
|
+
@processors.respond_to?(:call) ? @processors.call(attachment.instance) : (@processors || attachment.processors)
|
35
36
|
end
|
36
37
|
|
37
38
|
# retrieves from the attachment the whiny setting
|
@@ -71,7 +72,7 @@ module Paperclip
|
|
71
72
|
# Supports getting and setting style properties with hash notation to ensure backwards-compatibility
|
72
73
|
# eg. @attachment.styles[:large][:geometry]@ will still work
|
73
74
|
def [](key)
|
74
|
-
if [:name, :convert_options, :whiny, :processors, :geometry, :format].include?(key)
|
75
|
+
if [:name, :convert_options, :whiny, :processors, :geometry, :format, :animated].include?(key)
|
75
76
|
send(key)
|
76
77
|
elsif defined? @other_args[key]
|
77
78
|
@other_args[key]
|
@@ -79,7 +80,7 @@ module Paperclip
|
|
79
80
|
end
|
80
81
|
|
81
82
|
def []=(key, value)
|
82
|
-
if [:name, :convert_options, :whiny, :processors, :geometry, :format].include?(key)
|
83
|
+
if [:name, :convert_options, :whiny, :processors, :geometry, :format, :animated].include?(key)
|
83
84
|
send("#{key}=".intern, value)
|
84
85
|
else
|
85
86
|
@other_args[key] = value
|
data/lib/paperclip/thumbnail.rb
CHANGED
@@ -2,7 +2,11 @@ module Paperclip
|
|
2
2
|
# Handles thumbnailing images that are uploaded.
|
3
3
|
class Thumbnail < Processor
|
4
4
|
|
5
|
-
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options,
|
5
|
+
attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options,
|
6
|
+
:source_file_options, :animated
|
7
|
+
|
8
|
+
# List of formats that we need to preserve animation
|
9
|
+
ANIMATED_FORMATS = %w(gif)
|
6
10
|
|
7
11
|
# Creates a Thumbnail object set to work on the +file+ given. It
|
8
12
|
# will attempt to transform the image into one defined by +target_geometry+
|
@@ -22,6 +26,7 @@ module Paperclip
|
|
22
26
|
@convert_options = options[:convert_options]
|
23
27
|
@whiny = options[:whiny].nil? ? true : options[:whiny]
|
24
28
|
@format = options[:format]
|
29
|
+
@animated = options[:animated].nil? ? true : options[:animated]
|
25
30
|
|
26
31
|
@source_file_options = @source_file_options.split(/\s+/) if @source_file_options.respond_to?(:split)
|
27
32
|
@convert_options = @convert_options.split(/\s+/) if @convert_options.respond_to?(:split)
|
@@ -58,9 +63,11 @@ module Paperclip
|
|
58
63
|
|
59
64
|
parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
|
60
65
|
|
61
|
-
success = Paperclip.run("convert", parameters, :source => "#{File.expand_path(src.path)}[0]", :dest => File.expand_path(dst.path))
|
62
|
-
rescue
|
66
|
+
success = Paperclip.run("convert", parameters, :source => "#{File.expand_path(src.path)}#{'[0]' unless animated?}", :dest => File.expand_path(dst.path))
|
67
|
+
rescue Cocaine::ExitStatusError => e
|
63
68
|
raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny
|
69
|
+
rescue Cocaine::CommandNotFoundError => e
|
70
|
+
raise Paperclip::CommandNotFoundError.new("Could not run the `convert` command. Please install ImageMagick.")
|
64
71
|
end
|
65
72
|
|
66
73
|
dst
|
@@ -71,9 +78,17 @@ module Paperclip
|
|
71
78
|
def transformation_command
|
72
79
|
scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
|
73
80
|
trans = []
|
81
|
+
trans << "-coalesce" if animated?
|
74
82
|
trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
|
75
83
|
trans << "-crop" << %["#{crop}"] << "+repage" if crop
|
76
84
|
trans
|
77
85
|
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
# Return true if the format is animated
|
90
|
+
def animated?
|
91
|
+
@animated && ANIMATED_FORMATS.include?(@current_format[1..-1]) && (ANIMATED_FORMATS.include?(@format.to_s) || @format.blank?)
|
92
|
+
end
|
78
93
|
end
|
79
94
|
end
|
data/lib/paperclip/upfile.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'mime/types'
|
2
|
+
|
1
3
|
module Paperclip
|
2
4
|
# The Upfile module is a convenience module for adding uploaded-file-type methods
|
3
5
|
# to the +File+ class. Useful for testing.
|
@@ -6,23 +8,28 @@ module Paperclip
|
|
6
8
|
|
7
9
|
# Infer the MIME-type of the file from the extension.
|
8
10
|
def content_type
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
when "txt" then "text/plain"
|
15
|
-
when %r"html?" then "text/html"
|
16
|
-
when "js" then "application/js"
|
17
|
-
when "csv", "xml", "css" then "text/#{type}"
|
11
|
+
types = MIME::Types.type_for(self.original_filename)
|
12
|
+
if types.length == 0
|
13
|
+
type_from_file_command
|
14
|
+
elsif types.length == 1
|
15
|
+
types.first.content_type
|
18
16
|
else
|
19
|
-
|
20
|
-
content_type = (Paperclip.run("file", "-b --mime-type :file", :file => self.path).split(':').last.strip rescue "application/x-#{type}")
|
21
|
-
content_type = "application/x-#{type}" if content_type.match(/\(.*?\)/)
|
22
|
-
content_type
|
17
|
+
iterate_over_array_to_find_best_option(types)
|
23
18
|
end
|
24
19
|
end
|
25
20
|
|
21
|
+
def iterate_over_array_to_find_best_option(types)
|
22
|
+
types.reject {|type| type.content_type.match(/\/x-/) }.first
|
23
|
+
end
|
24
|
+
|
25
|
+
def type_from_file_command
|
26
|
+
# On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
|
27
|
+
type = (self.original_filename.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
|
28
|
+
mime_type = (Paperclip.run("file", "-b --mime-type :file", :file => self.path).split(':').last.strip rescue "application/x-#{type}")
|
29
|
+
mime_type = "application/x-#{type}" if mime_type.match(/\(.*?\)/)
|
30
|
+
mime_type
|
31
|
+
end
|
32
|
+
|
26
33
|
# Returns the file's normal name.
|
27
34
|
def original_filename
|
28
35
|
File.basename(self.path)
|
data/lib/paperclip/version.rb
CHANGED
data/lib/paperclip.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# columns to your table.
|
6
6
|
#
|
7
7
|
# Author:: Jon Yurek
|
8
|
-
# Copyright:: Copyright (c) 2008-
|
8
|
+
# Copyright:: Copyright (c) 2008-2011 thoughtbot, inc.
|
9
9
|
# License:: MIT License (http://www.opensource.org/licenses/mit-license.php)
|
10
10
|
#
|
11
11
|
# Paperclip defines an attachment as any file, though it makes special considerations
|
@@ -38,14 +38,9 @@ require 'paperclip/interpolations'
|
|
38
38
|
require 'paperclip/style'
|
39
39
|
require 'paperclip/attachment'
|
40
40
|
require 'paperclip/storage'
|
41
|
-
require 'paperclip/
|
42
|
-
require 'paperclip/command_line'
|
41
|
+
require 'paperclip/callback_compatibility'
|
43
42
|
require 'paperclip/railtie'
|
44
|
-
|
45
|
-
Dir.glob(File.join(File.expand_path(Rails.root), "lib", "paperclip_processors", "*.rb")).each do |processor|
|
46
|
-
require processor
|
47
|
-
end
|
48
|
-
end
|
43
|
+
require 'cocaine'
|
49
44
|
|
50
45
|
# The base module that gets included in ActiveRecord::Base. See the
|
51
46
|
# documentation for Paperclip::ClassMethods for more useful information.
|
@@ -87,7 +82,7 @@ module Paperclip
|
|
87
82
|
# symlink them so they are all in the same directory.
|
88
83
|
#
|
89
84
|
# If the command returns with a result code that is not one of the
|
90
|
-
# expected_outcodes, a
|
85
|
+
# expected_outcodes, a Cocaine::CommandLineError will be raised. Generally
|
91
86
|
# a code of 0 is expected, but a list of codes may be passed if necessary.
|
92
87
|
# These codes should be passed as a hash as the last argument, like so:
|
93
88
|
#
|
@@ -100,12 +95,13 @@ module Paperclip
|
|
100
95
|
if options[:image_magick_path]
|
101
96
|
Paperclip.log("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead")
|
102
97
|
end
|
103
|
-
CommandLine.path = options[:command_path] || options[:image_magick_path]
|
104
|
-
CommandLine.new(cmd, *params).run
|
98
|
+
Cocaine::CommandLine.path = options[:command_path] || options[:image_magick_path]
|
99
|
+
Cocaine::CommandLine.new(cmd, *params).run
|
105
100
|
end
|
106
101
|
|
107
102
|
def processor name #:nodoc:
|
108
103
|
name = name.to_s.camelize
|
104
|
+
load_processor(name) unless Paperclip.const_defined?(name)
|
109
105
|
processor = Paperclip.const_get(name)
|
110
106
|
unless processor.ancestors.include?(Paperclip::Processor)
|
111
107
|
raise PaperclipError.new("Processor #{name} was not found")
|
@@ -113,8 +109,14 @@ module Paperclip
|
|
113
109
|
processor
|
114
110
|
end
|
115
111
|
|
112
|
+
def load_processor(name)
|
113
|
+
if defined?(Rails.root) && Rails.root
|
114
|
+
require File.expand_path(Rails.root.join("lib", "paperclip_processors", "#{name.underscore}.rb"))
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
116
118
|
def each_instance_with_attachment(klass, name)
|
117
|
-
|
119
|
+
class_for(klass).all.each do |instance|
|
118
120
|
yield(instance) if instance.send(:"#{name}?")
|
119
121
|
end
|
120
122
|
end
|
@@ -126,23 +128,40 @@ module Paperclip
|
|
126
128
|
end
|
127
129
|
|
128
130
|
def logger #:nodoc:
|
129
|
-
ActiveRecord::Base.logger
|
131
|
+
defined?(ActiveRecord::Base) ? ActiveRecord::Base.logger : Rails.logger
|
130
132
|
end
|
131
133
|
|
132
134
|
def logging? #:nodoc:
|
133
135
|
options[:log]
|
134
136
|
end
|
135
|
-
end
|
136
137
|
|
137
|
-
|
138
|
+
def class_for(class_name)
|
139
|
+
# Ruby 1.9 introduces an inherit argument for Module#const_get and
|
140
|
+
# #const_defined? and changes their default behavior.
|
141
|
+
# https://github.com/rails/rails/blob/v3.0.9/activesupport/lib/active_support/inflector/methods.rb#L89
|
142
|
+
if Module.method(:const_get).arity == 1
|
143
|
+
class_name.split('::').inject(Object) do |klass, partial_class_name|
|
144
|
+
klass.const_defined?(partial_class_name) ? klass.const_get(partial_class_name) : klass.const_missing(partial_class_name)
|
145
|
+
end
|
146
|
+
else
|
147
|
+
class_name.split('::').inject(Object) do |klass, partial_class_name|
|
148
|
+
klass.const_defined?(partial_class_name) ? klass.const_get(partial_class_name, false) : klass.const_missing(partial_class_name)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
rescue ArgumentError => e
|
152
|
+
# Sadly, we need to capture ArguementError here because Rails 2.3.x
|
153
|
+
# Active Support dependency's management will try to the constant inherited
|
154
|
+
# from Object, and fail misably with "Object is not missing constant X" error
|
155
|
+
# https://github.com/rails/rails/blob/v2.3.12/activesupport/lib/active_support/dependencies.rb#L124
|
156
|
+
if e.message =~ /is not missing constant/
|
157
|
+
raise NameError, "uninitialized constant #{class_name}"
|
158
|
+
else
|
159
|
+
raise e
|
160
|
+
end
|
161
|
+
end
|
138
162
|
end
|
139
163
|
|
140
|
-
class
|
141
|
-
attr_accessor :output
|
142
|
-
def initialize(msg = nil, output = nil)
|
143
|
-
super(msg)
|
144
|
-
@output = output
|
145
|
-
end
|
164
|
+
class PaperclipError < StandardError #:nodoc:
|
146
165
|
end
|
147
166
|
|
148
167
|
class StorageMethodNotFound < PaperclipError
|
@@ -160,7 +179,8 @@ module Paperclip
|
|
160
179
|
module Glue
|
161
180
|
def self.included base #:nodoc:
|
162
181
|
base.extend ClassMethods
|
163
|
-
if base.respond_to?(
|
182
|
+
base.class_attribute :attachment_definitions if base.respond_to?(:class_attribute)
|
183
|
+
if base.respond_to?(:set_callback)
|
164
184
|
base.send :include, Paperclip::CallbackCompatability::Rails3
|
165
185
|
else
|
166
186
|
base.send :include, Paperclip::CallbackCompatability::Rails21
|
@@ -224,7 +244,7 @@ module Paperclip
|
|
224
244
|
# }
|
225
245
|
# NOTE: While not deprecated yet, it is not recommended to specify options this way.
|
226
246
|
# It is recommended that :convert_options option be included in the hash passed to each
|
227
|
-
# :styles for
|
247
|
+
# :styles for compatibility with future versions.
|
228
248
|
# NOTE: Strings supplied to :convert_options are split on space in order to undergo
|
229
249
|
# shell quoting for safety. If your options require a space, please pre-split them
|
230
250
|
# and pass an array to :convert_options instead.
|
@@ -235,7 +255,14 @@ module Paperclip
|
|
235
255
|
def has_attached_file name, options = {}
|
236
256
|
include InstanceMethods
|
237
257
|
|
238
|
-
|
258
|
+
if attachment_definitions.nil?
|
259
|
+
if respond_to?(:class_attribute)
|
260
|
+
self.attachment_definitions = {}
|
261
|
+
else
|
262
|
+
write_inheritable_attribute(:attachment_definitions, {})
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
239
266
|
attachment_definitions[name] = {:validations => []}.merge(options)
|
240
267
|
|
241
268
|
after_save :save_attached_files
|
@@ -275,7 +302,7 @@ module Paperclip
|
|
275
302
|
min = options[:greater_than] || (options[:in] && options[:in].first) || 0
|
276
303
|
max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
|
277
304
|
range = (min..max)
|
278
|
-
message = options[:message] || "file size must be between :min and :max bytes
|
305
|
+
message = options[:message] || "file size must be between :min and :max bytes"
|
279
306
|
message = message.call if message.respond_to?(:call)
|
280
307
|
message = message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s)
|
281
308
|
|
@@ -301,7 +328,7 @@ module Paperclip
|
|
301
328
|
# be run is this lambda or method returns true.
|
302
329
|
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
303
330
|
def validates_attachment_presence name, options = {}
|
304
|
-
message = options[:message] || "must be set
|
331
|
+
message = options[:message] || "must be set"
|
305
332
|
validates_presence_of :"#{name}_file_name",
|
306
333
|
:message => message,
|
307
334
|
:if => options[:if],
|
@@ -324,6 +351,8 @@ module Paperclip
|
|
324
351
|
# NOTE: If you do not specify an [attachment]_content_type field on your
|
325
352
|
# model, content_type validation will work _ONLY upon assignment_ and
|
326
353
|
# re-validation after the instance has been reloaded will always succeed.
|
354
|
+
# You'll still need to have a virtual attribute (created by +attr_accessor+)
|
355
|
+
# name +[attachment]_content_type+ to be able to use this validator.
|
327
356
|
def validates_attachment_content_type name, options = {}
|
328
357
|
validation_options = options.dup
|
329
358
|
allowed_types = [validation_options[:content_type]].flatten
|
@@ -343,7 +372,11 @@ module Paperclip
|
|
343
372
|
# Returns the attachment definitions defined by each call to
|
344
373
|
# has_attached_file.
|
345
374
|
def attachment_definitions
|
346
|
-
|
375
|
+
if respond_to?(:class_attribute)
|
376
|
+
self.attachment_definitions
|
377
|
+
else
|
378
|
+
read_inheritable_attribute(:attachment_definitions)
|
379
|
+
end
|
347
380
|
end
|
348
381
|
end
|
349
382
|
|
data/lib/tasks/paperclip.rake
CHANGED
@@ -1,17 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
module Paperclip
|
2
|
+
module Task
|
3
|
+
def self.obtain_class
|
4
|
+
class_name = ENV['CLASS'] || ENV['class']
|
5
|
+
raise "Must specify CLASS" unless class_name
|
6
|
+
class_name
|
7
|
+
end
|
6
8
|
|
7
|
-
def obtain_attachments(klass)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
def self.obtain_attachments(klass)
|
10
|
+
klass = Paperclip.class_for(klass.to_s)
|
11
|
+
name = ENV['ATTACHMENT'] || ENV['attachment']
|
12
|
+
raise "Class #{klass.name} has no attachments specified" unless klass.respond_to?(:attachment_definitions)
|
13
|
+
if !name.blank? && klass.attachment_definitions.keys.include?(name)
|
14
|
+
[ name ]
|
15
|
+
else
|
16
|
+
klass.attachment_definitions.keys
|
17
|
+
end
|
18
|
+
end
|
15
19
|
end
|
16
20
|
end
|
17
21
|
|
@@ -20,14 +24,15 @@ namespace :paperclip do
|
|
20
24
|
task :refresh => ["paperclip:refresh:metadata", "paperclip:refresh:thumbnails"]
|
21
25
|
|
22
26
|
namespace :refresh do
|
23
|
-
desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)."
|
27
|
+
desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT and STYLES splitted by comma)."
|
24
28
|
task :thumbnails => :environment do
|
25
29
|
errors = []
|
26
|
-
klass = obtain_class
|
27
|
-
names = obtain_attachments(klass)
|
30
|
+
klass = Paperclip::Task.obtain_class
|
31
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
32
|
+
styles = (ENV['STYLES'] || ENV['styles'] || '').split(',').map(&:to_sym)
|
28
33
|
names.each do |name|
|
29
34
|
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
30
|
-
|
35
|
+
instance.send(name).reprocess!(*styles)
|
31
36
|
errors << [instance.id, instance.errors] unless instance.errors.blank?
|
32
37
|
end
|
33
38
|
end
|
@@ -36,15 +41,19 @@ namespace :paperclip do
|
|
36
41
|
|
37
42
|
desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)."
|
38
43
|
task :metadata => :environment do
|
39
|
-
klass = obtain_class
|
40
|
-
names = obtain_attachments(klass)
|
44
|
+
klass = Paperclip::Task.obtain_class
|
45
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
41
46
|
names.each do |name|
|
42
47
|
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
43
|
-
if file = instance.send(name).to_file
|
48
|
+
if file = instance.send(name).to_file(:original)
|
44
49
|
instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
|
45
50
|
instance.send("#{name}_content_type=", file.content_type.strip)
|
46
51
|
instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
|
47
|
-
|
52
|
+
if Rails.version >= "3.0.0"
|
53
|
+
instance.save(:validate => false)
|
54
|
+
else
|
55
|
+
instance.save(false)
|
56
|
+
end
|
48
57
|
else
|
49
58
|
true
|
50
59
|
end
|
@@ -55,8 +64,8 @@ namespace :paperclip do
|
|
55
64
|
|
56
65
|
desc "Cleans out invalid attachments. Useful after you've added new validations."
|
57
66
|
task :clean => :environment do
|
58
|
-
klass = obtain_class
|
59
|
-
names = obtain_attachments(klass)
|
67
|
+
klass = Paperclip::Task.obtain_class
|
68
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
60
69
|
names.each do |name|
|
61
70
|
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
62
71
|
instance.send(name).send(:validate)
|
data/test/attachment_test.rb
CHANGED
@@ -14,6 +14,28 @@ class AttachmentTest < Test::Unit::TestCase
|
|
14
14
|
assert_equal "#{Rails.root}/public/fake_models/1234/fake", @attachment.path
|
15
15
|
end
|
16
16
|
|
17
|
+
should "return the url by interpolating the default_url option when no file assigned" do
|
18
|
+
@attachment = attachment :default_url => ":class/blegga.png"
|
19
|
+
@model = @attachment.instance
|
20
|
+
assert_nil @model.avatar_file_name
|
21
|
+
assert_equal "fake_models/blegga.png", @attachment.url
|
22
|
+
end
|
23
|
+
|
24
|
+
should "return the url by executing and interpolating the default_url Proc when no file assigned" do
|
25
|
+
@attachment = attachment :default_url => lambda { |a| ":class/blegga.png" }
|
26
|
+
@model = @attachment.instance
|
27
|
+
assert_nil @model.avatar_file_name
|
28
|
+
assert_equal "fake_models/blegga.png", @attachment.url
|
29
|
+
end
|
30
|
+
|
31
|
+
should "return the url by executing and interpolating the default_url Proc with attachment arg when no file assigned" do
|
32
|
+
@attachment = attachment :default_url => lambda { |a| a.instance.some_method_to_determine_default_url }
|
33
|
+
@model = @attachment.instance
|
34
|
+
@model.stubs(:some_method_to_determine_default_url).returns(":class/blegga.png")
|
35
|
+
assert_nil @model.avatar_file_name
|
36
|
+
assert_equal "fake_models/blegga.png", @attachment.url
|
37
|
+
end
|
38
|
+
|
17
39
|
context "Attachment default_options" do
|
18
40
|
setup do
|
19
41
|
rebuild_model
|
@@ -76,6 +98,19 @@ class AttachmentTest < Test::Unit::TestCase
|
|
76
98
|
end
|
77
99
|
end
|
78
100
|
end
|
101
|
+
|
102
|
+
context "with nested hash default" do
|
103
|
+
setup do
|
104
|
+
@nested_hash = {:thumb => {:first => "second" }}
|
105
|
+
Paperclip::Attachment.default_options[:styles] = @nested_hash
|
106
|
+
@dummy = Dummy.new
|
107
|
+
@attachment = @dummy.avatar
|
108
|
+
end
|
109
|
+
|
110
|
+
should "correctly clone the nested hash" do
|
111
|
+
assert_equal(@nested_hash, @attachment.instance_variable_get(:@styles))
|
112
|
+
end
|
113
|
+
end
|
79
114
|
end
|
80
115
|
end
|
81
116
|
|
@@ -228,6 +263,24 @@ class AttachmentTest < Test::Unit::TestCase
|
|
228
263
|
end
|
229
264
|
end
|
230
265
|
|
266
|
+
context "An attachment with :only_process" do
|
267
|
+
setup do
|
268
|
+
rebuild_model :styles => {
|
269
|
+
:thumb => "100x100",
|
270
|
+
:large => "400x400"
|
271
|
+
},
|
272
|
+
:only_process => [:thumb]
|
273
|
+
@file = StringIO.new("...")
|
274
|
+
@attachment = Dummy.new.avatar
|
275
|
+
end
|
276
|
+
|
277
|
+
should "only process the provided style" do
|
278
|
+
@attachment.expects(:post_process).with(:thumb)
|
279
|
+
@attachment.expects(:post_process).with(:large).never
|
280
|
+
@attachment.assign(@file)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
231
284
|
context "An attachment with :convert_options that is a proc" do
|
232
285
|
setup do
|
233
286
|
rebuild_model :styles => {
|
@@ -287,6 +340,24 @@ class AttachmentTest < Test::Unit::TestCase
|
|
287
340
|
assert_equal "50x50#", @attachment.styles[:thumb][:geometry]
|
288
341
|
end
|
289
342
|
end
|
343
|
+
|
344
|
+
context "An attachment with conditional :styles that is a proc" do
|
345
|
+
setup do
|
346
|
+
rebuild_model :styles => lambda{ |attachment| attachment.instance.other == 'a' ? {:thumb => "50x50#"} : {:large => "400x400"} }
|
347
|
+
|
348
|
+
@dummy = Dummy.new(:other => 'a')
|
349
|
+
end
|
350
|
+
|
351
|
+
should "have the correct styles for the assigned instance values" do
|
352
|
+
assert_equal "50x50#", @dummy.avatar.styles[:thumb][:geometry]
|
353
|
+
assert_nil @dummy.avatar.styles[:large]
|
354
|
+
|
355
|
+
@dummy.other = 'b'
|
356
|
+
|
357
|
+
assert_equal "400x400", @dummy.avatar.styles[:large][:geometry]
|
358
|
+
assert_nil @dummy.avatar.styles[:thumb]
|
359
|
+
end
|
360
|
+
end
|
290
361
|
|
291
362
|
context "An attachment with :url that is a proc" do
|
292
363
|
setup do
|
@@ -425,6 +496,19 @@ class AttachmentTest < Test::Unit::TestCase
|
|
425
496
|
rebuild_model :storage => :FileSystem
|
426
497
|
@dummy = Dummy.new
|
427
498
|
assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
|
499
|
+
|
500
|
+
rebuild_model :storage => :Filesystem
|
501
|
+
@dummy = Dummy.new
|
502
|
+
assert @dummy.avatar.is_a?(Paperclip::Storage::Filesystem)
|
503
|
+
end
|
504
|
+
|
505
|
+
should "convert underscored storage name to camelcase" do
|
506
|
+
rebuild_model :storage => :not_here
|
507
|
+
@dummy = Dummy.new
|
508
|
+
exception = assert_raises(Paperclip::StorageMethodNotFound) do |e|
|
509
|
+
@dummy.avatar
|
510
|
+
end
|
511
|
+
assert exception.message.include?("NotHere")
|
428
512
|
end
|
429
513
|
|
430
514
|
should "raise an error if you try to include a storage module that doesn't exist" do
|
@@ -642,6 +726,15 @@ class AttachmentTest < Test::Unit::TestCase
|
|
642
726
|
assert_equal nil, @attachment.path(:blah)
|
643
727
|
end
|
644
728
|
|
729
|
+
context "with a file assigned but not saved yet" do
|
730
|
+
should "clear out any attached files" do
|
731
|
+
@attachment.assign(@file)
|
732
|
+
assert !@attachment.queued_for_write.blank?
|
733
|
+
@attachment.clear
|
734
|
+
assert @attachment.queued_for_write.blank?
|
735
|
+
end
|
736
|
+
end
|
737
|
+
|
645
738
|
context "with a file assigned in the database" do
|
646
739
|
setup do
|
647
740
|
@attachment.stubs(:instance_read).with(:file_name).returns("5k.png")
|
@@ -918,4 +1011,27 @@ class AttachmentTest < Test::Unit::TestCase
|
|
918
1011
|
end
|
919
1012
|
end
|
920
1013
|
end
|
1014
|
+
|
1015
|
+
context "an attachment with delete_file option set to false" do
|
1016
|
+
setup do
|
1017
|
+
rebuild_model :preserve_files => true
|
1018
|
+
@dummy = Dummy.new
|
1019
|
+
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
1020
|
+
@dummy.avatar = @file
|
1021
|
+
@dummy.save!
|
1022
|
+
@attachment = @dummy.avatar
|
1023
|
+
@path = @attachment.path
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
should "not delete the files from storage when attachment is destroyed" do
|
1027
|
+
@attachment.destroy
|
1028
|
+
assert File.exists?(@path)
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
should "not dleete the file when model is destroy" do
|
1032
|
+
@dummy.destroy
|
1033
|
+
assert File.exists?(@path)
|
1034
|
+
end
|
1035
|
+
end
|
1036
|
+
|
921
1037
|
end
|
Binary file
|
data/test/fog_test.rb
CHANGED
@@ -16,15 +16,20 @@ class FogTest < Test::Unit::TestCase
|
|
16
16
|
}
|
17
17
|
|
18
18
|
@connection = Fog::Storage.new(@credentials)
|
19
|
+
@connection.directories.create(
|
20
|
+
:key => @fog_directory
|
21
|
+
)
|
19
22
|
|
20
|
-
|
23
|
+
@options = {
|
21
24
|
:fog_directory => @fog_directory,
|
22
25
|
:fog_credentials => @credentials,
|
23
26
|
:fog_host => nil,
|
24
|
-
:
|
27
|
+
:fog_file => {:cache_control => 1234},
|
25
28
|
:path => ":attachment/:basename.:extension",
|
26
29
|
:storage => :fog
|
27
|
-
|
30
|
+
}
|
31
|
+
|
32
|
+
rebuild_model(@options)
|
28
33
|
end
|
29
34
|
|
30
35
|
should "be extended by the Fog module" do
|
@@ -46,16 +51,17 @@ class FogTest < Test::Unit::TestCase
|
|
46
51
|
end
|
47
52
|
|
48
53
|
context "without a bucket" do
|
49
|
-
|
54
|
+
setup do
|
55
|
+
@connection.directories.get(@fog_directory).destroy
|
56
|
+
end
|
57
|
+
|
58
|
+
should "create the bucket" do
|
50
59
|
assert @dummy.save
|
60
|
+
assert @connection.directories.get(@fog_directory)
|
51
61
|
end
|
52
62
|
end
|
53
63
|
|
54
64
|
context "with a bucket" do
|
55
|
-
setup do
|
56
|
-
@connection.directories.create(:key => @fog_directory)
|
57
|
-
end
|
58
|
-
|
59
65
|
should "succeed" do
|
60
66
|
assert @dummy.save
|
61
67
|
end
|
@@ -63,14 +69,7 @@ class FogTest < Test::Unit::TestCase
|
|
63
69
|
|
64
70
|
context "without a fog_host" do
|
65
71
|
setup do
|
66
|
-
rebuild_model(
|
67
|
-
:fog_directory => @fog_directory,
|
68
|
-
:fog_credentials => @credentials,
|
69
|
-
:fog_host => nil,
|
70
|
-
:fog_public => true,
|
71
|
-
:path => ":attachment/:basename.:extension",
|
72
|
-
:storage => :fog
|
73
|
-
)
|
72
|
+
rebuild_model(@options.merge(:fog_host => nil))
|
74
73
|
@dummy = Dummy.new
|
75
74
|
@dummy.avatar = StringIO.new('.')
|
76
75
|
@dummy.save
|
@@ -82,12 +81,24 @@ class FogTest < Test::Unit::TestCase
|
|
82
81
|
end
|
83
82
|
|
84
83
|
context "with a fog_host" do
|
84
|
+
setup do
|
85
|
+
rebuild_model(@options.merge(:fog_host => 'http://example.com'))
|
86
|
+
@dummy = Dummy.new
|
87
|
+
@dummy.avatar = StringIO.new('.')
|
88
|
+
@dummy.save
|
89
|
+
end
|
90
|
+
|
91
|
+
should "provide a public url" do
|
92
|
+
assert @dummy.avatar.url =~ /^http:\/\/example\.com\/avatars\/stringio\.txt\?\d*$/
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with a fog_host that includes a wildcard placeholder" do
|
85
97
|
setup do
|
86
98
|
rebuild_model(
|
87
99
|
:fog_directory => @fog_directory,
|
88
100
|
:fog_credentials => @credentials,
|
89
|
-
:fog_host => 'http://example.com',
|
90
|
-
:fog_public => true,
|
101
|
+
:fog_host => 'http://img%d.example.com',
|
91
102
|
:path => ":attachment/:basename.:extension",
|
92
103
|
:storage => :fog
|
93
104
|
)
|
@@ -97,7 +108,7 @@ class FogTest < Test::Unit::TestCase
|
|
97
108
|
end
|
98
109
|
|
99
110
|
should "provide a public url" do
|
100
|
-
assert @dummy.avatar.url =~ /^http:\/\/example\.com\/avatars\/stringio\.txt\?\d*$/
|
111
|
+
assert @dummy.avatar.url =~ /^http:\/\/img[0123]\.example\.com\/avatars\/stringio\.txt\?\d*$/
|
101
112
|
end
|
102
113
|
end
|
103
114
|
|