paperclip-cloudfiles 2.3.1.1.0 → 2.3.1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +5 -1
- data/lib/paperclip/attachment.rb +46 -126
- data/lib/paperclip/interpolations.rb +17 -17
- data/lib/paperclip/storage.rb +12 -12
- data/lib/paperclip/style.rb +90 -0
- data/lib/paperclip/thumbnail.rb +2 -0
- data/lib/paperclip.rb +3 -2
- data/test/attachment_test.rb +21 -37
- data/test/paperclip_test.rb +0 -21
- data/test/style_test.rb +141 -0
- data/test/thumbnail_test.rb +1 -1
- metadata +4 -2
data/README.rdoc
CHANGED
@@ -16,7 +16,11 @@ See the documentation for +has_attached_file+ in Paperclip::ClassMethods for
|
|
16
16
|
more detailed options.
|
17
17
|
|
18
18
|
This fork has support for Rackspace Cloud Files. It requires the "cloudfiles"
|
19
|
-
gem, >= 1.4.4, from Gemcutter.org.
|
19
|
+
gem, >= 1.4.4, from Gemcutter.org. The Thoughtbot guys have indicated that they
|
20
|
+
don't want to pull any code into the official Paperclip mainline that they don't
|
21
|
+
personally use on projects, so until they discover the joy of Cloud Files, this
|
22
|
+
fork is available as the {paperclip-cloudfiles gem}[http://gemcutter.org/gems/paperclip-cloudfiles]
|
23
|
+
on Gemcutter's gem server.
|
20
24
|
|
21
25
|
==Quick Start
|
22
26
|
|
data/lib/paperclip/attachment.rb
CHANGED
@@ -7,18 +7,19 @@ module Paperclip
|
|
7
7
|
|
8
8
|
def self.default_options
|
9
9
|
@default_options ||= {
|
10
|
-
:url
|
11
|
-
:path
|
12
|
-
:styles
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
10
|
+
:url => "/system/:attachment/:id/:style/:filename",
|
11
|
+
:path => ":rails_root/public:url",
|
12
|
+
:styles => {},
|
13
|
+
:processors => [:thumbnail],
|
14
|
+
:convert_options => {},
|
15
|
+
:default_url => "/:attachment/:style/missing.png",
|
16
|
+
:default_style => :original,
|
17
|
+
:storage => :filesystem,
|
18
|
+
:whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails]
|
18
19
|
}
|
19
20
|
end
|
20
21
|
|
21
|
-
attr_reader :name, :instance, :
|
22
|
+
attr_reader :name, :instance, :default_style, :convert_options, :queued_for_write, :whiny, :options
|
22
23
|
|
23
24
|
# Creates an Attachment object. +name+ is the name of the attachment,
|
24
25
|
# +instance+ is the ActiveRecord object instance it's attached to, and
|
@@ -34,33 +35,42 @@ module Paperclip
|
|
34
35
|
@path = options[:path]
|
35
36
|
@path = @path.call(self) if @path.is_a?(Proc)
|
36
37
|
@styles = options[:styles]
|
37
|
-
@
|
38
|
+
@normalized_styles = nil
|
38
39
|
@default_url = options[:default_url]
|
39
|
-
@validations = options[:validations]
|
40
40
|
@default_style = options[:default_style]
|
41
41
|
@storage = options[:storage]
|
42
42
|
@whiny = options[:whiny_thumbnails] || options[:whiny]
|
43
|
-
@convert_options = options[:convert_options]
|
44
|
-
@processors = options[:processors]
|
43
|
+
@convert_options = options[:convert_options]
|
44
|
+
@processors = options[:processors]
|
45
45
|
@options = options
|
46
46
|
@queued_for_delete = []
|
47
47
|
@queued_for_write = {}
|
48
48
|
@errors = {}
|
49
|
-
@validation_errors = nil
|
50
49
|
@dirty = false
|
51
50
|
|
52
|
-
normalize_style_definition
|
53
51
|
initialize_storage
|
54
52
|
end
|
53
|
+
|
54
|
+
def styles
|
55
|
+
unless @normalized_styles
|
56
|
+
@normalized_styles = {}
|
57
|
+
(@styles.respond_to?(:call) ? @styles.call(self) : @styles).each do |name, args|
|
58
|
+
@normalized_styles[name] = Paperclip::Style.new(name, args, self)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
@normalized_styles
|
62
|
+
end
|
63
|
+
|
64
|
+
def processors
|
65
|
+
@processors.respond_to?(:call) ? @processors.call(instance) : @processors
|
66
|
+
end
|
55
67
|
|
56
68
|
# What gets called when you call instance.attachment = File. It clears
|
57
|
-
# errors, assigns attributes, processes the file
|
69
|
+
# errors, assigns attributes, and processes the file. It
|
58
70
|
# also queues up the previous file for deletion, to be flushed away on
|
59
71
|
# #save of its host. In addition to form uploads, you can also assign
|
60
72
|
# another Paperclip attachment:
|
61
73
|
# new_user.avatar = old_user.avatar
|
62
|
-
# If the file that is assigned is not valid, the processing (i.e.
|
63
|
-
# thumbnailing, etc) will NOT be run.
|
64
74
|
def assign uploaded_file
|
65
75
|
ensure_required_accessors!
|
66
76
|
|
@@ -84,13 +94,12 @@ module Paperclip
|
|
84
94
|
|
85
95
|
@dirty = true
|
86
96
|
|
87
|
-
post_process
|
97
|
+
post_process
|
88
98
|
|
89
99
|
# Reset the file size if the original file was reprocessed.
|
90
100
|
instance_write(:file_size, @queued_for_write[:original].size.to_i)
|
91
101
|
ensure
|
92
102
|
uploaded_file.close if close_uploaded_file
|
93
|
-
validate
|
94
103
|
end
|
95
104
|
|
96
105
|
# Returns the public URL of the attachment, with a given style. Note that
|
@@ -100,8 +109,8 @@ module Paperclip
|
|
100
109
|
# security, however, for performance reasons. set
|
101
110
|
# include_updated_timestamp to false if you want to stop the attachment
|
102
111
|
# update time appended to the url
|
103
|
-
def url
|
104
|
-
url = original_filename.nil? ? interpolate(@default_url,
|
112
|
+
def url style_name = default_style, include_updated_timestamp = true
|
113
|
+
url = original_filename.nil? ? interpolate(@default_url, style_name) : interpolate(@url, style_name)
|
105
114
|
include_updated_timestamp && updated_at ? [url, updated_at].compact.join(url.include?("?") ? "&" : "?") : url
|
106
115
|
end
|
107
116
|
|
@@ -109,19 +118,13 @@ module Paperclip
|
|
109
118
|
# file is stored in the filesystem the path refers to the path of the file
|
110
119
|
# on disk. If the file is stored in S3, the path is the "key" part of the
|
111
120
|
# URL, and the :bucket option refers to the S3 bucket.
|
112
|
-
def path
|
113
|
-
original_filename.nil? ? nil : interpolate(@path,
|
121
|
+
def path style_name = default_style
|
122
|
+
original_filename.nil? ? nil : interpolate(@path, style_name)
|
114
123
|
end
|
115
124
|
|
116
125
|
# Alias to +url+
|
117
|
-
def to_s
|
118
|
-
url(
|
119
|
-
end
|
120
|
-
|
121
|
-
# Returns true if there are no errors on this attachment.
|
122
|
-
def valid?
|
123
|
-
validate
|
124
|
-
errors.empty?
|
126
|
+
def to_s style_name = nil
|
127
|
+
url(style_name)
|
125
128
|
end
|
126
129
|
|
127
130
|
# Returns an array containing the errors on this attachment.
|
@@ -137,15 +140,10 @@ module Paperclip
|
|
137
140
|
# Saves the file, if there are no errors. If there are, it flushes them to
|
138
141
|
# the instance's errors and returns false, cancelling the save.
|
139
142
|
def save
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
true
|
145
|
-
else
|
146
|
-
flush_errors
|
147
|
-
false
|
148
|
-
end
|
143
|
+
flush_deletes
|
144
|
+
flush_writes
|
145
|
+
@dirty = false
|
146
|
+
true
|
149
147
|
end
|
150
148
|
|
151
149
|
# Clears out the attachment. Has the same effect as previously assigning
|
@@ -154,7 +152,6 @@ module Paperclip
|
|
154
152
|
def clear
|
155
153
|
queue_existing_for_delete
|
156
154
|
@errors = {}
|
157
|
-
@validation_errors = nil
|
158
155
|
end
|
159
156
|
|
160
157
|
# Destroys the attachment. Has the same effect as previously assigning
|
@@ -267,82 +264,6 @@ module Paperclip
|
|
267
264
|
file.nil? || (file.respond_to?(:original_filename) && file.respond_to?(:content_type))
|
268
265
|
end
|
269
266
|
|
270
|
-
def validate #:nodoc:
|
271
|
-
unless @validation_errors
|
272
|
-
@validation_errors = @validations.inject({}) do |errors, validation|
|
273
|
-
name, options = validation
|
274
|
-
errors[name] = send(:"validate_#{name}", options) if allow_validation?(options)
|
275
|
-
errors
|
276
|
-
end
|
277
|
-
@validation_errors.reject!{|k,v| v == nil }
|
278
|
-
@errors.merge!(@validation_errors)
|
279
|
-
end
|
280
|
-
@validation_errors
|
281
|
-
end
|
282
|
-
|
283
|
-
def allow_validation? options #:nodoc:
|
284
|
-
(options[:if].nil? || check_guard(options[:if])) && (options[:unless].nil? || !check_guard(options[:unless]))
|
285
|
-
end
|
286
|
-
|
287
|
-
def check_guard guard #:nodoc:
|
288
|
-
if guard.respond_to? :call
|
289
|
-
guard.call(instance)
|
290
|
-
elsif ! guard.blank?
|
291
|
-
instance.send(guard.to_s)
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
def validate_size options #:nodoc:
|
296
|
-
if file? && !options[:range].include?(size.to_i)
|
297
|
-
options[:message].gsub(/:min/, options[:min].to_s).gsub(/:max/, options[:max].to_s)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
def validate_presence options #:nodoc:
|
302
|
-
options[:message] unless file?
|
303
|
-
end
|
304
|
-
|
305
|
-
def validate_content_type options #:nodoc:
|
306
|
-
valid_types = [options[:content_type]].flatten
|
307
|
-
unless original_filename.blank?
|
308
|
-
unless valid_types.blank?
|
309
|
-
content_type = instance_read(:content_type)
|
310
|
-
unless valid_types.any?{|t| content_type.nil? || t === content_type }
|
311
|
-
options[:message] || "is not one of the allowed file types."
|
312
|
-
end
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
def normalize_style_definition #:nodoc:
|
318
|
-
@styles.each do |name, args|
|
319
|
-
unless args.is_a? Hash
|
320
|
-
dimensions, format = [args, nil].flatten[0..1]
|
321
|
-
format = nil if format.blank?
|
322
|
-
@styles[name] = {
|
323
|
-
:processors => @processors,
|
324
|
-
:geometry => dimensions,
|
325
|
-
:format => format,
|
326
|
-
:whiny => @whiny,
|
327
|
-
:convert_options => extra_options_for(name)
|
328
|
-
}
|
329
|
-
else
|
330
|
-
@styles[name] = {
|
331
|
-
:processors => @processors,
|
332
|
-
:whiny => @whiny,
|
333
|
-
:convert_options => extra_options_for(name)
|
334
|
-
}.merge(@styles[name])
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
def solidify_style_definitions #:nodoc:
|
340
|
-
@styles.each do |name, args|
|
341
|
-
@styles[name][:geometry] = @styles[name][:geometry].call(instance) if @styles[name][:geometry].respond_to?(:call)
|
342
|
-
@styles[name][:processors] = @styles[name][:processors].call(instance) if @styles[name][:processors].respond_to?(:call)
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
267
|
def initialize_storage #:nodoc:
|
347
268
|
@storage_module = Paperclip::Storage.const_get(@storage.to_s.classify)
|
348
269
|
self.extend(@storage_module)
|
@@ -359,7 +280,6 @@ module Paperclip
|
|
359
280
|
|
360
281
|
def post_process #:nodoc:
|
361
282
|
return if @queued_for_write[:original].nil?
|
362
|
-
solidify_style_definitions
|
363
283
|
return if fire_events(:before)
|
364
284
|
post_process_styles
|
365
285
|
return if fire_events(:after)
|
@@ -375,11 +295,11 @@ module Paperclip
|
|
375
295
|
end
|
376
296
|
|
377
297
|
def post_process_styles #:nodoc:
|
378
|
-
|
298
|
+
styles.each do |name, style|
|
379
299
|
begin
|
380
|
-
raise RuntimeError.new("Style #{name} has no processors defined.") if
|
381
|
-
@queued_for_write[name] =
|
382
|
-
Paperclip.processor(processor).make(file,
|
300
|
+
raise RuntimeError.new("Style #{name} has no processors defined.") if style.processors.blank?
|
301
|
+
@queued_for_write[name] = style.processors.inject(@queued_for_write[:original]) do |file, processor|
|
302
|
+
Paperclip.processor(processor).make(file, style.processor_options, self)
|
383
303
|
end
|
384
304
|
rescue PaperclipError => e
|
385
305
|
log("An error was received while processing: #{e.inspect}")
|
@@ -388,13 +308,13 @@ module Paperclip
|
|
388
308
|
end
|
389
309
|
end
|
390
310
|
|
391
|
-
def interpolate pattern,
|
392
|
-
Paperclip::Interpolations.interpolate(pattern, self,
|
311
|
+
def interpolate pattern, style_name = default_style #:nodoc:
|
312
|
+
Paperclip::Interpolations.interpolate(pattern, self, style_name)
|
393
313
|
end
|
394
314
|
|
395
315
|
def queue_existing_for_delete #:nodoc:
|
396
316
|
return unless file?
|
397
|
-
@queued_for_delete += [:original,
|
317
|
+
@queued_for_delete += [:original, *styles.keys].uniq.map do |style|
|
398
318
|
path(style) if exists?(style)
|
399
319
|
end.compact
|
400
320
|
instance_write(:file_name, nil)
|
@@ -34,30 +34,30 @@ module Paperclip
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# Returns the filename, the same way as ":basename.:extension" would.
|
37
|
-
def filename attachment,
|
38
|
-
"#{basename(attachment,
|
37
|
+
def filename attachment, style_name
|
38
|
+
"#{basename(attachment, style_name)}.#{extension(attachment, style_name)}"
|
39
39
|
end
|
40
40
|
|
41
41
|
# Returns the interpolated URL. Will raise an error if the url itself
|
42
42
|
# contains ":url" to prevent infinite recursion. This interpolation
|
43
43
|
# is used in the default :path to ease default specifications.
|
44
|
-
def url attachment,
|
44
|
+
def url attachment, style_name
|
45
45
|
raise InfiniteInterpolationError if attachment.options[:url].include?(":url")
|
46
|
-
attachment.url(
|
46
|
+
attachment.url(style_name, false)
|
47
47
|
end
|
48
48
|
|
49
49
|
# Returns the timestamp as defined by the <attachment>_updated_at field
|
50
|
-
def timestamp attachment,
|
50
|
+
def timestamp attachment, style_name
|
51
51
|
attachment.instance_read(:updated_at).to_s
|
52
52
|
end
|
53
53
|
|
54
54
|
# Returns the RAILS_ROOT constant.
|
55
|
-
def rails_root attachment,
|
55
|
+
def rails_root attachment, style_name
|
56
56
|
RAILS_ROOT
|
57
57
|
end
|
58
58
|
|
59
59
|
# Returns the RAILS_ENV constant.
|
60
|
-
def rails_env attachment,
|
60
|
+
def rails_env attachment, style_name
|
61
61
|
RAILS_ENV
|
62
62
|
end
|
63
63
|
|
@@ -65,44 +65,44 @@ module Paperclip
|
|
65
65
|
# e.g. "users" for the User class.
|
66
66
|
# NOTE: The arguments need to be optional, because some tools fetch
|
67
67
|
# all class names. Calling #class will return the expected class.
|
68
|
-
def class attachment = nil,
|
69
|
-
return super() if attachment.nil? &&
|
68
|
+
def class attachment = nil, style_name = nil
|
69
|
+
return super() if attachment.nil? && style_name.nil?
|
70
70
|
attachment.instance.class.to_s.underscore.pluralize
|
71
71
|
end
|
72
72
|
|
73
73
|
# Returns the basename of the file. e.g. "file" for "file.jpg"
|
74
|
-
def basename attachment,
|
74
|
+
def basename attachment, style_name
|
75
75
|
attachment.original_filename.gsub(/#{File.extname(attachment.original_filename)}$/, "")
|
76
76
|
end
|
77
77
|
|
78
78
|
# Returns the extension of the file. e.g. "jpg" for "file.jpg"
|
79
79
|
# If the style has a format defined, it will return the format instead
|
80
80
|
# of the actual extension.
|
81
|
-
def extension attachment,
|
82
|
-
((style = attachment.styles[
|
81
|
+
def extension attachment, style_name
|
82
|
+
((style = attachment.styles[style_name]) && style[:format]) ||
|
83
83
|
File.extname(attachment.original_filename).gsub(/^\.+/, "")
|
84
84
|
end
|
85
85
|
|
86
86
|
# Returns the id of the instance.
|
87
|
-
def id attachment,
|
87
|
+
def id attachment, style_name
|
88
88
|
attachment.instance.id
|
89
89
|
end
|
90
90
|
|
91
91
|
# Returns the id of the instance in a split path form. e.g. returns
|
92
92
|
# 000/001/234 for an id of 1234.
|
93
|
-
def id_partition attachment,
|
93
|
+
def id_partition attachment, style_name
|
94
94
|
("%09d" % attachment.instance.id).scan(/\d{3}/).join("/")
|
95
95
|
end
|
96
96
|
|
97
97
|
# Returns the pluralized form of the attachment name. e.g.
|
98
98
|
# "avatars" for an attachment of :avatar
|
99
|
-
def attachment attachment,
|
99
|
+
def attachment attachment, style_name
|
100
100
|
attachment.name.to_s.downcase.pluralize
|
101
101
|
end
|
102
102
|
|
103
103
|
# Returns the style, or the default style if nil is supplied.
|
104
|
-
def style attachment,
|
105
|
-
|
104
|
+
def style attachment, style_name
|
105
|
+
style_name || attachment.default_style
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
data/lib/paperclip/storage.rb
CHANGED
@@ -20,9 +20,9 @@ module Paperclip
|
|
20
20
|
def self.extended base
|
21
21
|
end
|
22
22
|
|
23
|
-
def exists?(
|
23
|
+
def exists?(style_name = default_style)
|
24
24
|
if original_filename
|
25
|
-
File.exist?(path(
|
25
|
+
File.exist?(path(style_name))
|
26
26
|
else
|
27
27
|
false
|
28
28
|
end
|
@@ -30,17 +30,17 @@ module Paperclip
|
|
30
30
|
|
31
31
|
# Returns representation of the data of the file assigned to the given
|
32
32
|
# style, in the format most representative of the current storage.
|
33
|
-
def to_file
|
34
|
-
@queued_for_write[
|
33
|
+
def to_file style_name = default_style
|
34
|
+
@queued_for_write[style_name] || (File.new(path(style_name), 'rb') if exists?(style_name))
|
35
35
|
end
|
36
36
|
|
37
37
|
def flush_writes #:nodoc:
|
38
|
-
@queued_for_write.each do |
|
38
|
+
@queued_for_write.each do |style_name, file|
|
39
39
|
file.close
|
40
|
-
FileUtils.mkdir_p(File.dirname(path(
|
41
|
-
log("saving #{path(
|
42
|
-
FileUtils.mv(file.path, path(
|
43
|
-
FileUtils.chmod(0644, path(
|
40
|
+
FileUtils.mkdir_p(File.dirname(path(style_name)))
|
41
|
+
log("saving #{path(style_name)}")
|
42
|
+
FileUtils.mv(file.path, path(style_name))
|
43
|
+
FileUtils.chmod(0644, path(style_name))
|
44
44
|
end
|
45
45
|
@queued_for_write = {}
|
46
46
|
end
|
@@ -248,8 +248,8 @@ module Paperclip
|
|
248
248
|
# distribution, and is integrated into the Limelight CDN. You can find out more about
|
249
249
|
# it at http://www.rackspacecloud.com/cloud_hosting_products/files
|
250
250
|
#
|
251
|
-
# To install the Cloud Files gem, add the
|
252
|
-
# do a "gem install
|
251
|
+
# To install the Cloud Files gem, add the Gemcutter gem source ("gem sources -a http://gemcutter.org"), then
|
252
|
+
# do a "gem install cloudfiles". For more information, see the github repository at http://github.com/rackspace/ruby-cloudfiles/
|
253
253
|
#
|
254
254
|
# There are a few Cloud Files-specific options for has_attached_file:
|
255
255
|
# * +cloudfiles_credentials+: Takes a path, a File, or a Hash. The path (or File) must point
|
@@ -293,7 +293,7 @@ module Paperclip
|
|
293
293
|
@@cdn_url ||= cloudfiles_container.cdn_url
|
294
294
|
@path_filename = ":cf_path_filename" unless @url.to_s.match(/^:cf.*filename$/)
|
295
295
|
@url = @@cdn_url + "/#{URI.encode(@path_filename).gsub(/&/,'%26')}"
|
296
|
-
@path =
|
296
|
+
@path = @options[:path] || ":attachment/:id/:style/:basename.:extension"
|
297
297
|
end
|
298
298
|
Paperclip.interpolates(:cf_path_filename) do |attachment, style|
|
299
299
|
attachment.path(style)
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Paperclip
|
3
|
+
# The Style class holds the definition of a thumbnail style, applying
|
4
|
+
# whatever processing is required to normalize the definition and delaying
|
5
|
+
# the evaluation of block parameters until useful context is available.
|
6
|
+
|
7
|
+
class Style
|
8
|
+
|
9
|
+
attr_reader :name, :attachment, :format
|
10
|
+
|
11
|
+
# Creates a Style object. +name+ is the name of the attachment,
|
12
|
+
# +definition+ is the style definition from has_attached_file, which
|
13
|
+
# can be string, array or hash
|
14
|
+
def initialize name, definition, attachment
|
15
|
+
@name = name
|
16
|
+
@attachment = attachment
|
17
|
+
if definition.is_a? Hash
|
18
|
+
@geometry = definition.delete(:geometry)
|
19
|
+
@format = definition.delete(:format)
|
20
|
+
@processors = definition.delete(:processors)
|
21
|
+
@other_args = definition
|
22
|
+
else
|
23
|
+
@geometry, @format = [definition, nil].flatten[0..1]
|
24
|
+
@other_args = {}
|
25
|
+
end
|
26
|
+
@format = nil if @format.blank?
|
27
|
+
end
|
28
|
+
|
29
|
+
# retrieves from the attachment the processors defined in the has_attached_file call
|
30
|
+
# (which method (in the attachment) will call any supplied procs)
|
31
|
+
# There is an important change of interface here: a style rule can set its own processors
|
32
|
+
# by default we behave as before, though.
|
33
|
+
def processors
|
34
|
+
@processors || attachment.processors
|
35
|
+
end
|
36
|
+
|
37
|
+
# retrieves from the attachment the whiny setting
|
38
|
+
def whiny
|
39
|
+
attachment.whiny
|
40
|
+
end
|
41
|
+
|
42
|
+
# returns true if we're inclined to grumble
|
43
|
+
def whiny?
|
44
|
+
!!whiny
|
45
|
+
end
|
46
|
+
|
47
|
+
def convert_options
|
48
|
+
attachment.send(:extra_options_for, name)
|
49
|
+
end
|
50
|
+
|
51
|
+
# returns the geometry string for this style
|
52
|
+
# if a proc has been supplied, we call it here
|
53
|
+
def geometry
|
54
|
+
@geometry.respond_to?(:call) ? @geometry.call(attachment.instance) : @geometry
|
55
|
+
end
|
56
|
+
|
57
|
+
# Supplies the hash of options that processors expect to receive as their second argument
|
58
|
+
# Arguments other than the standard geometry, format etc are just passed through from
|
59
|
+
# initialization and any procs are called here, just before post-processing.
|
60
|
+
def processor_options
|
61
|
+
args = {}
|
62
|
+
@other_args.each do |k,v|
|
63
|
+
args[k] = v.respond_to?(:call) ? v.call(attachment) : v
|
64
|
+
end
|
65
|
+
[:processors, :geometry, :format, :whiny, :convert_options].each do |k|
|
66
|
+
(arg = send(k)) && args[k] = arg
|
67
|
+
end
|
68
|
+
args
|
69
|
+
end
|
70
|
+
|
71
|
+
# Supports getting and setting style properties with hash notation to ensure backwards-compatibility
|
72
|
+
# eg. @attachment.styles[:large][:geometry]@ will still work
|
73
|
+
def [](key)
|
74
|
+
if [:name, :convert_options, :whiny, :processors, :geometry, :format].include?(key)
|
75
|
+
send(key)
|
76
|
+
elsif defined? @other_args[key]
|
77
|
+
@other_args[key]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def []=(key, value)
|
82
|
+
if [:name, :convert_options, :whiny, :processors, :geometry, :format].include?(key)
|
83
|
+
send("#{key}=".intern, value)
|
84
|
+
else
|
85
|
+
@other_args[key] = value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
data/lib/paperclip/thumbnail.rb
CHANGED
@@ -12,6 +12,7 @@ module Paperclip
|
|
12
12
|
# set, the options will be appended to the convert command upon image conversion
|
13
13
|
def initialize file, options = {}, attachment = nil
|
14
14
|
super
|
15
|
+
|
15
16
|
geometry = options[:geometry]
|
16
17
|
@file = file
|
17
18
|
@crop = geometry[-1,1] == '#'
|
@@ -24,6 +25,7 @@ module Paperclip
|
|
24
25
|
|
25
26
|
@current_format = File.extname(@file.path)
|
26
27
|
@basename = File.basename(@file.path, @current_format)
|
28
|
+
|
27
29
|
end
|
28
30
|
|
29
31
|
# Returns true if the +target_geometry+ is meant to crop.
|
data/lib/paperclip.rb
CHANGED
@@ -34,6 +34,7 @@ require 'paperclip/processor'
|
|
34
34
|
require 'paperclip/thumbnail'
|
35
35
|
require 'paperclip/storage'
|
36
36
|
require 'paperclip/interpolations'
|
37
|
+
require 'paperclip/style'
|
37
38
|
require 'paperclip/attachment'
|
38
39
|
if defined? RAILS_ROOT
|
39
40
|
Dir.glob(File.join(File.expand_path(RAILS_ROOT), "lib", "paperclip_processors", "*.rb")).each do |processor|
|
@@ -45,7 +46,7 @@ end
|
|
45
46
|
# documentation for Paperclip::ClassMethods for more useful information.
|
46
47
|
module Paperclip
|
47
48
|
|
48
|
-
VERSION = "2.3.1.1.
|
49
|
+
VERSION = "2.3.1.1.1"
|
49
50
|
|
50
51
|
class << self
|
51
52
|
# Provides configurability to Paperclip. There are a number of options available, such as:
|
@@ -239,7 +240,7 @@ module Paperclip
|
|
239
240
|
|
240
241
|
validates_each(name) do |record, attr, value|
|
241
242
|
attachment = record.attachment_for(name)
|
242
|
-
attachment.send(:flush_errors)
|
243
|
+
attachment.send(:flush_errors)
|
243
244
|
end
|
244
245
|
end
|
245
246
|
|
data/test/attachment_test.rb
CHANGED
@@ -14,18 +14,6 @@ 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 "call a proc sent to check_guard" do
|
18
|
-
@dummy = Dummy.new
|
19
|
-
@dummy.expects(:one).returns(:one)
|
20
|
-
assert_equal :one, @dummy.avatar.send(:check_guard, lambda{|x| x.one })
|
21
|
-
end
|
22
|
-
|
23
|
-
should "call a method name sent to check_guard" do
|
24
|
-
@dummy = Dummy.new
|
25
|
-
@dummy.expects(:one).returns(:one)
|
26
|
-
assert_equal :one, @dummy.avatar.send(:check_guard, :one)
|
27
|
-
end
|
28
|
-
|
29
17
|
context "Attachment default_options" do
|
30
18
|
setup do
|
31
19
|
rebuild_model
|
@@ -162,11 +150,6 @@ class AttachmentTest < Test::Unit::TestCase
|
|
162
150
|
should "report the correct options when sent #extra_options_for(:large)" do
|
163
151
|
assert_equal "-do_stuff", @dummy.avatar.send(:extra_options_for, :large)
|
164
152
|
end
|
165
|
-
|
166
|
-
before_should "call extra_options_for(:thumb/:large)" do
|
167
|
-
Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb)
|
168
|
-
Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large)
|
169
|
-
end
|
170
153
|
end
|
171
154
|
|
172
155
|
context "An attachment with :convert_options that is a proc" do
|
@@ -194,11 +177,6 @@ class AttachmentTest < Test::Unit::TestCase
|
|
194
177
|
should "report the correct options when sent #extra_options_for(:large)" do
|
195
178
|
assert_equal "-all", @dummy.avatar.send(:extra_options_for, :large)
|
196
179
|
end
|
197
|
-
|
198
|
-
before_should "call extra_options_for(:thumb/:large)" do
|
199
|
-
Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:thumb)
|
200
|
-
Paperclip::Attachment.any_instance.expects(:extra_options_for).with(:large)
|
201
|
-
end
|
202
180
|
end
|
203
181
|
|
204
182
|
context "An attachment with :path that is a proc" do
|
@@ -267,10 +245,6 @@ class AttachmentTest < Test::Unit::TestCase
|
|
267
245
|
@attachment = Dummy.new.avatar
|
268
246
|
end
|
269
247
|
|
270
|
-
should "not run the procs immediately" do
|
271
|
-
assert_kind_of Proc, @attachment.styles[:normal][:geometry]
|
272
|
-
end
|
273
|
-
|
274
248
|
context "when assigned" do
|
275
249
|
setup do
|
276
250
|
@file = StringIO.new(".")
|
@@ -307,10 +281,6 @@ class AttachmentTest < Test::Unit::TestCase
|
|
307
281
|
@attachment = Dummy.new.avatar
|
308
282
|
end
|
309
283
|
|
310
|
-
should "not run the proc immediately" do
|
311
|
-
assert_kind_of Proc, @attachment.styles[:normal][:processors]
|
312
|
-
end
|
313
|
-
|
314
284
|
context "when assigned" do
|
315
285
|
setup do
|
316
286
|
@attachment.assign(StringIO.new("."))
|
@@ -354,19 +324,22 @@ class AttachmentTest < Test::Unit::TestCase
|
|
354
324
|
setup { @dummy.avatar = @file }
|
355
325
|
|
356
326
|
before_should "call #make on all specified processors" do
|
327
|
+
Paperclip::Thumbnail.expects(:make).with(any_parameters).returns(@file)
|
328
|
+
Paperclip::Test.expects(:make).with(any_parameters).returns(@file)
|
329
|
+
end
|
330
|
+
|
331
|
+
before_should "call #make with the right parameters passed as second argument" do
|
357
332
|
expected_params = @style_params[:once].merge({:processors => [:thumbnail, :test], :whiny => true, :convert_options => ""})
|
358
|
-
Paperclip::Thumbnail.expects(:make).with(
|
359
|
-
Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file)
|
333
|
+
Paperclip::Thumbnail.expects(:make).with(anything, expected_params, anything).returns(@file)
|
360
334
|
end
|
361
335
|
|
362
336
|
before_should "call #make with attachment passed as third argument" do
|
363
|
-
|
364
|
-
Paperclip::Test.expects(:make).with(@file, expected_params, @dummy.avatar).returns(@file)
|
337
|
+
Paperclip::Test.expects(:make).with(anything, anything, @dummy.avatar).returns(@file)
|
365
338
|
end
|
366
339
|
end
|
367
340
|
end
|
368
341
|
|
369
|
-
context "An attachment with no processors defined" do
|
342
|
+
context "An attachment with styles but no processors defined" do
|
370
343
|
setup do
|
371
344
|
rebuild_model :processors => [], :styles => {:something => 1}
|
372
345
|
@dummy = Dummy.new
|
@@ -377,6 +350,17 @@ class AttachmentTest < Test::Unit::TestCase
|
|
377
350
|
end
|
378
351
|
end
|
379
352
|
|
353
|
+
context "An attachment without styles and with no processors defined" do
|
354
|
+
setup do
|
355
|
+
rebuild_model :processors => [], :styles => {}
|
356
|
+
@dummy = Dummy.new
|
357
|
+
@file = StringIO.new("...")
|
358
|
+
end
|
359
|
+
should "not raise when assigned to" do
|
360
|
+
@dummy.avatar = @file
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
380
364
|
context "Assigning an attachment with post_process hooks" do
|
381
365
|
setup do
|
382
366
|
rebuild_model :styles => { :something => "100x100#" }
|
@@ -478,8 +462,6 @@ class AttachmentTest < Test::Unit::TestCase
|
|
478
462
|
@attachment.expects(:valid_assignment?).with(@not_file).returns(true)
|
479
463
|
@attachment.expects(:queue_existing_for_delete)
|
480
464
|
@attachment.expects(:post_process)
|
481
|
-
@attachment.expects(:valid?).returns(true)
|
482
|
-
@attachment.expects(:validate)
|
483
465
|
@dummy.avatar = @not_file
|
484
466
|
end
|
485
467
|
|
@@ -498,6 +480,7 @@ class AttachmentTest < Test::Unit::TestCase
|
|
498
480
|
FileUtils.rm_rf("tmp")
|
499
481
|
rebuild_model
|
500
482
|
@instance = Dummy.new
|
483
|
+
@instance.stubs(:id).returns 123
|
501
484
|
@attachment = Paperclip::Attachment.new(:avatar, @instance)
|
502
485
|
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
503
486
|
end
|
@@ -606,6 +589,7 @@ class AttachmentTest < Test::Unit::TestCase
|
|
606
589
|
should "commit the files to disk" do
|
607
590
|
[:large, :medium, :small].each do |style|
|
608
591
|
io = @attachment.to_file(style)
|
592
|
+
# p "in commit to disk test, io is #{io.inspect} and @instance.id is #{@instance.id}"
|
609
593
|
assert File.exists?(io)
|
610
594
|
assert ! io.is_a?(::Tempfile)
|
611
595
|
io.close
|
data/test/paperclip_test.rb
CHANGED
@@ -185,27 +185,6 @@ class PaperclipTest < Test::Unit::TestCase
|
|
185
185
|
should "be valid" do
|
186
186
|
assert @dummy.valid?
|
187
187
|
end
|
188
|
-
|
189
|
-
context "then has a validation added that makes it invalid" do
|
190
|
-
setup do
|
191
|
-
assert @dummy.save
|
192
|
-
Dummy.class_eval do
|
193
|
-
validates_attachment_content_type :avatar, :content_type => ["text/plain"]
|
194
|
-
end
|
195
|
-
@dummy2 = Dummy.find(@dummy.id)
|
196
|
-
end
|
197
|
-
|
198
|
-
should "be invalid when reloaded" do
|
199
|
-
assert ! @dummy2.valid?, @dummy2.errors.inspect
|
200
|
-
end
|
201
|
-
|
202
|
-
should "be able to call #valid? twice without having duplicate errors" do
|
203
|
-
@dummy2.avatar.valid?
|
204
|
-
first_errors = @dummy2.avatar.errors
|
205
|
-
@dummy2.avatar.valid?
|
206
|
-
assert_equal first_errors, @dummy2.avatar.errors
|
207
|
-
end
|
208
|
-
end
|
209
188
|
end
|
210
189
|
|
211
190
|
context "a validation with an if guard clause" do
|
data/test/style_test.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test/helper'
|
3
|
+
|
4
|
+
class StyleTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context "A style rule" do
|
7
|
+
setup do
|
8
|
+
@attachment = attachment :path => ":basename.:extension",
|
9
|
+
:styles => { :foo => {:geometry => "100x100#", :format => :png} }
|
10
|
+
@style = @attachment.styles[:foo]
|
11
|
+
end
|
12
|
+
|
13
|
+
should "be held as a Style object" do
|
14
|
+
assert_kind_of Paperclip::Style, @style
|
15
|
+
end
|
16
|
+
|
17
|
+
should "get processors from the attachment definition" do
|
18
|
+
assert_equal [:thumbnail], @style.processors
|
19
|
+
end
|
20
|
+
|
21
|
+
should "have the right geometry" do
|
22
|
+
assert_equal "100x100#", @style.geometry
|
23
|
+
end
|
24
|
+
|
25
|
+
should "be whiny if the attachment is" do
|
26
|
+
@attachment.expects(:whiny).returns(true)
|
27
|
+
assert @style.whiny?
|
28
|
+
end
|
29
|
+
|
30
|
+
should "respond to hash notation" do
|
31
|
+
assert_equal [:thumbnail], @style[:processors]
|
32
|
+
assert_equal "100x100#", @style[:geometry]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context "A style rule with properties supplied as procs" do
|
37
|
+
setup do
|
38
|
+
@attachment = attachment :path => ":basename.:extension",
|
39
|
+
:whiny_thumbnails => true,
|
40
|
+
:processors => lambda {|a| [:test]},
|
41
|
+
:styles => {
|
42
|
+
:foo => lambda{|a| "300x300#"},
|
43
|
+
:bar => {
|
44
|
+
:geometry => lambda{|a| "300x300#"}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
should "defer processing of procs until they are needed" do
|
50
|
+
assert_kind_of Proc, @attachment.styles[:foo].instance_variable_get("@geometry")
|
51
|
+
assert_kind_of Proc, @attachment.styles[:bar].instance_variable_get("@geometry")
|
52
|
+
assert_kind_of Proc, @attachment.instance_variable_get("@processors")
|
53
|
+
end
|
54
|
+
|
55
|
+
should "call procs when they are needed" do
|
56
|
+
assert_equal "300x300#", @attachment.styles[:foo].geometry
|
57
|
+
assert_equal "300x300#", @attachment.styles[:bar].geometry
|
58
|
+
assert_equal [:test], @attachment.styles[:foo].processors
|
59
|
+
assert_equal [:test], @attachment.styles[:bar].processors
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "An attachment with style rules in various forms" do
|
64
|
+
setup do
|
65
|
+
@attachment = attachment :path => ":basename.:extension",
|
66
|
+
:styles => {
|
67
|
+
:aslist => ["100x100", :png],
|
68
|
+
:ashash => {:geometry => "100x100", :format => :png},
|
69
|
+
:asstring => "100x100"
|
70
|
+
}
|
71
|
+
end
|
72
|
+
should "have the right number of styles" do
|
73
|
+
assert_kind_of Hash, @attachment.styles
|
74
|
+
assert_equal 3, @attachment.styles.size
|
75
|
+
end
|
76
|
+
|
77
|
+
should "have styles as Style objects" do
|
78
|
+
[:aslist, :ashash, :aslist].each do |s|
|
79
|
+
assert_kind_of Paperclip::Style, @attachment.styles[s]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
should "have the right geometries" do
|
84
|
+
[:aslist, :ashash, :aslist].each do |s|
|
85
|
+
assert_equal @attachment.styles[s].geometry, "100x100"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
should "have the right formats" do
|
90
|
+
assert_equal @attachment.styles[:aslist].format, :png
|
91
|
+
assert_equal @attachment.styles[:ashash].format, :png
|
92
|
+
assert_nil @attachment.styles[:asstring].format
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
context "An attachment with :convert_options" do
|
98
|
+
setup do
|
99
|
+
@attachment = attachment :path => ":basename.:extension",
|
100
|
+
:styles => {:thumb => "100x100", :large => "400x400"},
|
101
|
+
:convert_options => {:all => "-do_stuff", :thumb => "-thumbnailize"}
|
102
|
+
@style = @attachment.styles[:thumb]
|
103
|
+
@file = StringIO.new("...")
|
104
|
+
@file.stubs(:original_filename).returns("file.jpg")
|
105
|
+
end
|
106
|
+
|
107
|
+
before_should "not have called extra_options_for(:thumb/:large) on initialization" do
|
108
|
+
@attachment.expects(:extra_options_for).never
|
109
|
+
end
|
110
|
+
|
111
|
+
should "call extra_options_for(:thumb/:large) when convert options are requested" do
|
112
|
+
@attachment.expects(:extra_options_for).with(:thumb)
|
113
|
+
@attachment.styles[:thumb].convert_options
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "A style rule with its own :processors" do
|
118
|
+
setup do
|
119
|
+
@attachment = attachment :path => ":basename.:extension",
|
120
|
+
:styles => {
|
121
|
+
:foo => {
|
122
|
+
:geometry => "100x100#",
|
123
|
+
:format => :png,
|
124
|
+
:processors => [:test]
|
125
|
+
}
|
126
|
+
},
|
127
|
+
:processors => [:thumbnail]
|
128
|
+
@style = @attachment.styles[:foo]
|
129
|
+
end
|
130
|
+
|
131
|
+
should "not get processors from the attachment" do
|
132
|
+
@attachment.expects(:processors).never
|
133
|
+
assert_not_equal [:thumbnail], @style.processors
|
134
|
+
end
|
135
|
+
|
136
|
+
should "report its own processors" do
|
137
|
+
assert_equal [:test], @style.processors
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
data/test/thumbnail_test.rb
CHANGED
@@ -200,7 +200,7 @@ class ThumbnailTest < Test::Unit::TestCase
|
|
200
200
|
teardown { @file.close }
|
201
201
|
|
202
202
|
should "start with two pages with dimensions 612x792" do
|
203
|
-
cmd = %Q[identify -format "%wx%h" "#{@file.path}"]
|
203
|
+
cmd = %Q[identify -format "%wx%h" "#{@file.path}"]
|
204
204
|
assert_equal "612x792"*2, `#{cmd}`.chomp
|
205
205
|
end
|
206
206
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paperclip-cloudfiles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3.1.1.
|
4
|
+
version: 2.3.1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Yurek
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date:
|
13
|
+
date: 2010-01-27 00:00:00 -06:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -113,6 +113,7 @@ files:
|
|
113
113
|
- lib/paperclip/matchers.rb
|
114
114
|
- lib/paperclip/processor.rb
|
115
115
|
- lib/paperclip/storage.rb
|
116
|
+
- lib/paperclip/style.rb
|
116
117
|
- lib/paperclip/thumbnail.rb
|
117
118
|
- lib/paperclip/upfile.rb
|
118
119
|
- lib/paperclip.rb
|
@@ -139,6 +140,7 @@ files:
|
|
139
140
|
- test/paperclip_test.rb
|
140
141
|
- test/processor_test.rb
|
141
142
|
- test/storage_test.rb
|
143
|
+
- test/style_test.rb
|
142
144
|
- test/thumbnail_test.rb
|
143
145
|
- test/upfile_test.rb
|
144
146
|
- shoulda_macros/paperclip.rb
|