paperclip-cloudfiles 2.3.1.1.0 → 2.3.1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|