paperclip 2.3.12 → 2.3.15
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 +4 -1
- data/Rakefile +2 -2
- data/lib/generators/paperclip/paperclip_generator.rb +3 -1
- data/lib/paperclip.rb +4 -2
- data/lib/paperclip/attachment.rb +19 -9
- data/lib/paperclip/iostream.rb +1 -1
- data/lib/paperclip/storage/filesystem.rb +8 -3
- data/lib/paperclip/storage/fog.rb +15 -11
- data/lib/paperclip/storage/s3.rb +37 -12
- data/lib/paperclip/thumbnail.rb +1 -0
- data/lib/paperclip/upfile.rb +20 -14
- data/lib/paperclip/version.rb +1 -1
- data/lib/tasks/paperclip.rake +24 -20
- data/rails/init.rb +2 -0
- data/test/attachment_test.rb +85 -0
- data/test/fog_test.rb +16 -23
- data/test/helper.rb +1 -0
- data/test/integration_test.rb +23 -0
- data/test/storage_test.rb +129 -2
- data/test/style_test.rb +9 -6
- data/test/thumbnail_test.rb +8 -0
- data/test/upfile_test.rb +2 -2
- metadata +54 -80
data/README.md
CHANGED
@@ -188,9 +188,12 @@ or more or the processors, and they are expected to ignore it.
|
|
188
188
|
_NOTE: Because processors operate by turning the original attachment into the
|
189
189
|
styles, no processors will be run if there are no styles defined._
|
190
190
|
|
191
|
-
If you're interested in caching your thumbnail's width, height and size in the
|
191
|
+
If you're interested in caching your thumbnail's width, height and size in the
|
192
192
|
database, take a look at the [paperclip-meta](https://github.com/y8/paperclip-meta) gem.
|
193
193
|
|
194
|
+
Also, if you're interesting to generate the thumbnail on-the-fly, you might want
|
195
|
+
to look into the [attachment_on_the_fly](https://github.com/drpentode/Attachment-on-the-Fly) gem.
|
196
|
+
|
194
197
|
Events
|
195
198
|
------
|
196
199
|
|
data/Rakefile
CHANGED
@@ -4,7 +4,7 @@ require 'bundler/setup'
|
|
4
4
|
|
5
5
|
require 'rake'
|
6
6
|
require 'rake/testtask'
|
7
|
-
require '
|
7
|
+
require 'rdoc/task'
|
8
8
|
|
9
9
|
$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
|
10
10
|
require 'paperclip'
|
@@ -31,7 +31,7 @@ task :shell do |t|
|
|
31
31
|
end
|
32
32
|
|
33
33
|
desc 'Generate documentation for the paperclip plugin.'
|
34
|
-
|
34
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
35
35
|
rdoc.rdoc_dir = 'doc'
|
36
36
|
rdoc.title = 'Paperclip'
|
37
37
|
rdoc.options << '--line-numbers' << '--inline-source'
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'rails/generators/active_record'
|
2
2
|
|
3
3
|
class PaperclipGenerator < ActiveRecord::Generators::Base
|
4
|
-
desc "Create a migration to add paperclip-specific fields to your model."
|
4
|
+
desc "Create a migration to add paperclip-specific fields to your model. " +
|
5
|
+
"The NAME argument is the name of your model, and the following " +
|
6
|
+
"arguments are the name of the attachments"
|
5
7
|
|
6
8
|
argument :attachment_names, :required => true, :type => :array, :desc => "The names of the attachment(s) to add.",
|
7
9
|
:banner => "attachment_one attachment_two attachment_three ..."
|
data/lib/paperclip.rb
CHANGED
@@ -302,7 +302,7 @@ module Paperclip
|
|
302
302
|
min = options[:greater_than] || (options[:in] && options[:in].first) || 0
|
303
303
|
max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
|
304
304
|
range = (min..max)
|
305
|
-
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"
|
306
306
|
message = message.call if message.respond_to?(:call)
|
307
307
|
message = message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s)
|
308
308
|
|
@@ -328,7 +328,7 @@ module Paperclip
|
|
328
328
|
# be run is this lambda or method returns true.
|
329
329
|
# * +unless+: Same as +if+ but validates if lambda or method returns false.
|
330
330
|
def validates_attachment_presence name, options = {}
|
331
|
-
message = options[:message] || "must be set
|
331
|
+
message = options[:message] || "must be set"
|
332
332
|
validates_presence_of :"#{name}_file_name",
|
333
333
|
:message => message,
|
334
334
|
:if => options[:if],
|
@@ -351,6 +351,8 @@ module Paperclip
|
|
351
351
|
# NOTE: If you do not specify an [attachment]_content_type field on your
|
352
352
|
# model, content_type validation will work _ONLY upon assignment_ and
|
353
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.
|
354
356
|
def validates_attachment_content_type name, options = {}
|
355
357
|
validation_options = options.dup
|
356
358
|
allowed_types = [validation_options[:content_type]].flatten
|
data/lib/paperclip/attachment.rb
CHANGED
@@ -21,7 +21,8 @@ module Paperclip
|
|
21
21
|
:whiny => Paperclip.options[:whiny] || Paperclip.options[:whiny_thumbnails],
|
22
22
|
:use_default_time_zone => true,
|
23
23
|
:hash_digest => "SHA1",
|
24
|
-
:hash_data => ":class/:attachment/:id/:style/:updated_at"
|
24
|
+
:hash_data => ":class/:attachment/:id/:style/:updated_at",
|
25
|
+
:preserve_files => false
|
25
26
|
}
|
26
27
|
end
|
27
28
|
|
@@ -55,6 +56,7 @@ module Paperclip
|
|
55
56
|
@hash_secret = options[:hash_secret]
|
56
57
|
@convert_options = options[:convert_options]
|
57
58
|
@processors = options[:processors]
|
59
|
+
@preserve_files = options[:preserve_files]
|
58
60
|
@options = options
|
59
61
|
@post_processing = true
|
60
62
|
@queued_for_delete = []
|
@@ -67,7 +69,7 @@ module Paperclip
|
|
67
69
|
|
68
70
|
def styles
|
69
71
|
if @styles.respond_to?(:call) || !@normalized_styles
|
70
|
-
@normalized_styles =
|
72
|
+
@normalized_styles = ActiveSupport::OrderedHash.new
|
71
73
|
(@styles.respond_to?(:call) ? @styles.call(self) : @styles).each do |name, args|
|
72
74
|
@normalized_styles[name] = Paperclip::Style.new(name, args.dup, self)
|
73
75
|
end
|
@@ -167,6 +169,7 @@ module Paperclip
|
|
167
169
|
# use #destroy.
|
168
170
|
def clear
|
169
171
|
queue_existing_for_delete
|
172
|
+
@queued_for_write = {}
|
170
173
|
@errors = {}
|
171
174
|
end
|
172
175
|
|
@@ -174,8 +177,10 @@ module Paperclip
|
|
174
177
|
# nil to the attachment *and saving*. This is permanent. If you wish to
|
175
178
|
# wipe out the existing attachment but not save, use #clear.
|
176
179
|
def destroy
|
177
|
-
|
178
|
-
|
180
|
+
unless @preserve_files
|
181
|
+
clear
|
182
|
+
save
|
183
|
+
end
|
179
184
|
end
|
180
185
|
|
181
186
|
# Returns the name of the file as originally assigned, and lives in the
|
@@ -225,9 +230,13 @@ module Paperclip
|
|
225
230
|
end
|
226
231
|
|
227
232
|
def generate_fingerprint(source)
|
228
|
-
|
229
|
-
|
230
|
-
|
233
|
+
if source.respond_to?(:path) && source.path && !source.path.blank?
|
234
|
+
Digest::MD5.file(source.path).to_s
|
235
|
+
else
|
236
|
+
data = source.read
|
237
|
+
source.rewind if source.respond_to?(:rewind)
|
238
|
+
Digest::MD5.hexdigest(data)
|
239
|
+
end
|
231
240
|
end
|
232
241
|
|
233
242
|
# Paths and URLs can have a number of variables interpolated into them
|
@@ -254,6 +263,7 @@ module Paperclip
|
|
254
263
|
new_original.rewind
|
255
264
|
|
256
265
|
@queued_for_write = { :original => new_original }
|
266
|
+
instance_write(:updated_at, Time.now)
|
257
267
|
post_process(*style_args)
|
258
268
|
|
259
269
|
old_original.close if old_original.respond_to?(:close)
|
@@ -271,7 +281,7 @@ module Paperclip
|
|
271
281
|
def file?
|
272
282
|
!original_filename.blank?
|
273
283
|
end
|
274
|
-
|
284
|
+
|
275
285
|
alias :present? :file?
|
276
286
|
|
277
287
|
# Writes the attachment-specific attribute on the instance. For example,
|
@@ -361,7 +371,7 @@ module Paperclip
|
|
361
371
|
end
|
362
372
|
|
363
373
|
def queue_existing_for_delete #:nodoc:
|
364
|
-
return unless file?
|
374
|
+
return unless (file? && @preserve_files==false)
|
365
375
|
@queued_for_delete += [:original, *styles.keys].uniq.map do |style|
|
366
376
|
path(style) if exists?(style)
|
367
377
|
end.compact
|
data/lib/paperclip/iostream.rb
CHANGED
@@ -38,8 +38,13 @@ module Paperclip
|
|
38
38
|
file.close
|
39
39
|
FileUtils.mkdir_p(File.dirname(path(style_name)))
|
40
40
|
log("saving #{path(style_name)}")
|
41
|
-
|
42
|
-
|
41
|
+
begin
|
42
|
+
FileUtils.mv(file.path, path(style_name))
|
43
|
+
rescue SystemCallError
|
44
|
+
FileUtils.cp(file.path, path(style_name))
|
45
|
+
FileUtils.rm(file.path)
|
46
|
+
end
|
47
|
+
FileUtils.chmod(0666&~File.umask, path(style_name))
|
43
48
|
end
|
44
49
|
@queued_for_write = {}
|
45
50
|
end
|
@@ -58,7 +63,7 @@ module Paperclip
|
|
58
63
|
FileUtils.rmdir(path)
|
59
64
|
break if File.exists?(path) # Ruby 1.9.2 does not raise if the removal failed.
|
60
65
|
end
|
61
|
-
rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR
|
66
|
+
rescue Errno::EEXIST, Errno::ENOTEMPTY, Errno::ENOENT, Errno::EINVAL, Errno::ENOTDIR, Errno::EACCES
|
62
67
|
# Stop trying to remove parent directories
|
63
68
|
rescue SystemCallError => e
|
64
69
|
log("There was an unexpected error while deleting directories: #{e.class}")
|
@@ -45,6 +45,7 @@ module Paperclip
|
|
45
45
|
@fog_credentials = @options[:fog_credentials]
|
46
46
|
@fog_host = @options[:fog_host]
|
47
47
|
@fog_public = @options[:fog_public]
|
48
|
+
@fog_file = @options[:fog_file] || {}
|
48
49
|
|
49
50
|
@url = ':fog_public_url'
|
50
51
|
Paperclip.interpolates(:fog_public_url) do |attachment, style|
|
@@ -64,11 +65,19 @@ module Paperclip
|
|
64
65
|
def flush_writes
|
65
66
|
for style, file in @queued_for_write do
|
66
67
|
log("saving #{path(style)}")
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
retried = false
|
69
|
+
begin
|
70
|
+
directory.files.create(@fog_file.merge(
|
71
|
+
:body => file,
|
72
|
+
:key => path(style),
|
73
|
+
:public => @fog_public
|
74
|
+
))
|
75
|
+
rescue Excon::Errors::NotFound
|
76
|
+
raise if retried
|
77
|
+
retried = true
|
78
|
+
directory.save
|
79
|
+
retry
|
80
|
+
end
|
72
81
|
end
|
73
82
|
@queued_for_write = {}
|
74
83
|
end
|
@@ -115,12 +124,7 @@ module Paperclip
|
|
115
124
|
end
|
116
125
|
|
117
126
|
def directory
|
118
|
-
@directory ||=
|
119
|
-
connection.directories.get(@fog_directory) || connection.directories.create(
|
120
|
-
:key => @fog_directory,
|
121
|
-
:public => @fog_public
|
122
|
-
)
|
123
|
-
end
|
127
|
+
@directory ||= connection.directories.new(:key => @fog_directory)
|
124
128
|
end
|
125
129
|
|
126
130
|
end
|
data/lib/paperclip/storage/s3.rb
CHANGED
@@ -27,6 +27,14 @@ module Paperclip
|
|
27
27
|
# policies that S3 provides (more information can be found here:
|
28
28
|
# http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAccessPolicy.html)
|
29
29
|
# The default for Paperclip is :public_read.
|
30
|
+
#
|
31
|
+
# You can set permission on a per style bases by doing the following:
|
32
|
+
# :s3_permissions => {
|
33
|
+
# :original => :private
|
34
|
+
# }
|
35
|
+
# Or globaly:
|
36
|
+
# :s3_permissions => :private
|
37
|
+
#
|
30
38
|
# * +s3_protocol+: The protocol for the URLs generated to your S3 assets. Can be either
|
31
39
|
# 'http' or 'https'. Defaults to 'http' when your :s3_permissions are :public_read (the
|
32
40
|
# default), and 'https' when your :s3_permissions are anything else.
|
@@ -72,14 +80,17 @@ module Paperclip
|
|
72
80
|
@bucket = @options[:bucket] || @s3_credentials[:bucket]
|
73
81
|
@bucket = @bucket.call(self) if @bucket.is_a?(Proc)
|
74
82
|
@s3_options = @options[:s3_options] || {}
|
75
|
-
@s3_permissions = @options[:s3_permissions]
|
76
|
-
@s3_protocol = @options[:s3_protocol] ||
|
83
|
+
@s3_permissions = set_permissions(@options[:s3_permissions])
|
84
|
+
@s3_protocol = @options[:s3_protocol] ||
|
85
|
+
Proc.new do |style|
|
86
|
+
(@s3_permissions[style.to_sym] || @s3_permissions[:default]) == :public_read ? 'http' : 'https'
|
87
|
+
end
|
77
88
|
@s3_headers = @options[:s3_headers] || {}
|
78
89
|
@s3_host_alias = @options[:s3_host_alias]
|
79
90
|
@s3_host_alias = @s3_host_alias.call(self) if @s3_host_alias.is_a?(Proc)
|
80
91
|
unless @url.to_s.match(/^:s3.*url$/)
|
81
|
-
@path
|
82
|
-
@url
|
92
|
+
@path = @path.gsub(/:url/, @url)
|
93
|
+
@url = ":s3_path_url"
|
83
94
|
end
|
84
95
|
@url = ":asset_host" if @options[:url].to_s == ":asset_host"
|
85
96
|
AWS::S3::Base.establish_connection!( @s3_options.merge(
|
@@ -88,13 +99,13 @@ module Paperclip
|
|
88
99
|
))
|
89
100
|
end
|
90
101
|
Paperclip.interpolates(:s3_alias_url) do |attachment, style|
|
91
|
-
"#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}"
|
102
|
+
"#{attachment.s3_protocol(style)}://#{attachment.s3_host_alias}/#{attachment.path(style).gsub(%r{^/}, "")}"
|
92
103
|
end unless Paperclip::Interpolations.respond_to? :s3_alias_url
|
93
104
|
Paperclip.interpolates(:s3_path_url) do |attachment, style|
|
94
|
-
"#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
|
105
|
+
"#{attachment.s3_protocol(style)}://s3.amazonaws.com/#{attachment.bucket_name}/#{attachment.path(style).gsub(%r{^/}, "")}"
|
95
106
|
end unless Paperclip::Interpolations.respond_to? :s3_path_url
|
96
107
|
Paperclip.interpolates(:s3_domain_url) do |attachment, style|
|
97
|
-
"#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}"
|
108
|
+
"#{attachment.s3_protocol(style)}://#{attachment.bucket_name}.s3.amazonaws.com/#{attachment.path(style).gsub(%r{^/}, "")}"
|
98
109
|
end unless Paperclip::Interpolations.respond_to? :s3_domain_url
|
99
110
|
Paperclip.interpolates(:asset_host) do |attachment, style|
|
100
111
|
"#{attachment.path(style).gsub(%r{^/}, "")}"
|
@@ -102,20 +113,30 @@ module Paperclip
|
|
102
113
|
end
|
103
114
|
|
104
115
|
def expiring_url(time = 3600, style_name = default_style)
|
105
|
-
AWS::S3::S3Object.url_for(path(style_name), bucket_name, :expires_in => time, :use_ssl => (s3_protocol == 'https'))
|
116
|
+
AWS::S3::S3Object.url_for(path(style_name), bucket_name, :expires_in => time, :use_ssl => (s3_protocol(style_name) == 'https'))
|
106
117
|
end
|
107
118
|
|
108
119
|
def bucket_name
|
109
120
|
@bucket
|
110
121
|
end
|
111
122
|
|
123
|
+
def set_permissions permissions
|
124
|
+
if permissions.is_a?(Hash)
|
125
|
+
permissions[:default] = permissions[:default] || :public_read
|
126
|
+
else
|
127
|
+
permissions = { :default => permissions || :public_read }
|
128
|
+
end
|
129
|
+
permissions
|
130
|
+
end
|
131
|
+
|
112
132
|
def s3_host_alias
|
113
133
|
@s3_host_alias
|
114
134
|
end
|
115
135
|
|
116
136
|
def parse_credentials creds
|
117
137
|
creds = find_credentials(creds).stringify_keys
|
118
|
-
(
|
138
|
+
env = Object.const_defined?(:Rails) ? Rails.env : nil
|
139
|
+
(creds[env] || creds).symbolize_keys
|
119
140
|
end
|
120
141
|
|
121
142
|
def exists?(style = default_style)
|
@@ -126,8 +147,12 @@ module Paperclip
|
|
126
147
|
end
|
127
148
|
end
|
128
149
|
|
129
|
-
def s3_protocol
|
130
|
-
@s3_protocol
|
150
|
+
def s3_protocol(style)
|
151
|
+
if @s3_protocol.is_a?(Proc)
|
152
|
+
@s3_protocol.call(style)
|
153
|
+
else
|
154
|
+
@s3_protocol
|
155
|
+
end
|
131
156
|
end
|
132
157
|
|
133
158
|
# Returns representation of the data of the file assigned to the given
|
@@ -156,7 +181,7 @@ module Paperclip
|
|
156
181
|
file,
|
157
182
|
bucket_name,
|
158
183
|
{:content_type => file.content_type.to_s.strip,
|
159
|
-
:access => @s3_permissions,
|
184
|
+
:access => (@s3_permissions[style] || @s3_permissions[:default]),
|
160
185
|
}.merge(@s3_headers))
|
161
186
|
rescue AWS::S3::NoSuchBucket => e
|
162
187
|
create_bucket
|
data/lib/paperclip/thumbnail.rb
CHANGED
@@ -76,6 +76,7 @@ module Paperclip
|
|
76
76
|
def transformation_command
|
77
77
|
scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
|
78
78
|
trans = []
|
79
|
+
trans << "-coalesce" if animated?
|
79
80
|
trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
|
80
81
|
trans << "-crop" << %["#{crop}"] << "+repage" if crop
|
81
82
|
trans
|
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,24 +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 %r"svg" then "image/svg+xml"
|
15
|
-
when "txt" then "text/plain"
|
16
|
-
when %r"html?" then "text/html"
|
17
|
-
when "js" then "application/js"
|
18
|
-
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
|
19
16
|
else
|
20
|
-
|
21
|
-
content_type = (Paperclip.run("file", "-b --mime-type :file", :file => self.path).split(':').last.strip rescue "application/x-#{type}")
|
22
|
-
content_type = "application/x-#{type}" if content_type.match(/\(.*?\)/)
|
23
|
-
content_type
|
17
|
+
iterate_over_array_to_find_best_option(types)
|
24
18
|
end
|
25
19
|
end
|
26
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
|
+
|
27
33
|
# Returns the file's normal name.
|
28
34
|
def original_filename
|
29
35
|
File.basename(self.path)
|
data/lib/paperclip/version.rb
CHANGED
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
|
|
@@ -23,8 +27,8 @@ namespace :paperclip do
|
|
23
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)
|
28
32
|
styles = (ENV['STYLES'] || ENV['styles'] || '').split(',').map(&:to_sym)
|
29
33
|
names.each do |name|
|
30
34
|
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
@@ -37,11 +41,11 @@ namespace :paperclip do
|
|
37
41
|
|
38
42
|
desc "Regenerates content_type/size metadata for a given CLASS (and optional ATTACHMENT)."
|
39
43
|
task :metadata => :environment do
|
40
|
-
klass = obtain_class
|
41
|
-
names = obtain_attachments(klass)
|
44
|
+
klass = Paperclip::Task.obtain_class
|
45
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
42
46
|
names.each do |name|
|
43
47
|
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
44
|
-
if file = instance.send(name).to_file
|
48
|
+
if file = instance.send(name).to_file(:original)
|
45
49
|
instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
|
46
50
|
instance.send("#{name}_content_type=", file.content_type.strip)
|
47
51
|
instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
|
@@ -60,8 +64,8 @@ namespace :paperclip do
|
|
60
64
|
|
61
65
|
desc "Cleans out invalid attachments. Useful after you've added new validations."
|
62
66
|
task :clean => :environment do
|
63
|
-
klass = obtain_class
|
64
|
-
names = obtain_attachments(klass)
|
67
|
+
klass = Paperclip::Task.obtain_class
|
68
|
+
names = Paperclip::Task.obtain_attachments(klass)
|
65
69
|
names.each do |name|
|
66
70
|
Paperclip.each_instance_with_attachment(klass, name) do |instance|
|
67
71
|
instance.send(name).send(:validate)
|
data/rails/init.rb
ADDED
data/test/attachment_test.rb
CHANGED
@@ -98,6 +98,19 @@ class AttachmentTest < Test::Unit::TestCase
|
|
98
98
|
end
|
99
99
|
end
|
100
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
|
101
114
|
end
|
102
115
|
end
|
103
116
|
|
@@ -621,6 +634,46 @@ class AttachmentTest < Test::Unit::TestCase
|
|
621
634
|
assert_equal "sheep_say_bæ.png", @dummy.avatar.original_filename
|
622
635
|
end
|
623
636
|
end
|
637
|
+
|
638
|
+
context "Attachment with uppercase extension and a default style" do
|
639
|
+
setup do
|
640
|
+
@old_defaults = Paperclip::Attachment.default_options.dup
|
641
|
+
Paperclip::Attachment.default_options.merge!({
|
642
|
+
:path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
|
643
|
+
})
|
644
|
+
FileUtils.rm_rf("tmp")
|
645
|
+
rebuild_model
|
646
|
+
@instance = Dummy.new
|
647
|
+
@instance.stubs(:id).returns 123
|
648
|
+
|
649
|
+
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "uppercase.PNG"), 'rb')
|
650
|
+
|
651
|
+
styles = {:styles => { :large => ["400x400", :jpg],
|
652
|
+
:medium => ["100x100", :jpg],
|
653
|
+
:small => ["32x32#", :jpg]},
|
654
|
+
:default_style => :small}
|
655
|
+
@attachment = Paperclip::Attachment.new(:avatar,
|
656
|
+
@instance,
|
657
|
+
styles)
|
658
|
+
now = Time.now
|
659
|
+
Time.stubs(:now).returns(now)
|
660
|
+
@attachment.assign(@file)
|
661
|
+
@attachment.save
|
662
|
+
end
|
663
|
+
|
664
|
+
teardown do
|
665
|
+
@file.close
|
666
|
+
Paperclip::Attachment.default_options.merge!(@old_defaults)
|
667
|
+
end
|
668
|
+
|
669
|
+
should "should have matching to_s and url methods" do
|
670
|
+
file = @attachment.to_file
|
671
|
+
assert file
|
672
|
+
assert_match @attachment.to_s, @attachment.url
|
673
|
+
assert_match @attachment.to_s(:small), @attachment.url(:small)
|
674
|
+
file.close
|
675
|
+
end
|
676
|
+
end
|
624
677
|
|
625
678
|
context "Attachment with uppercase extension and a default style" do
|
626
679
|
setup do
|
@@ -700,6 +753,15 @@ class AttachmentTest < Test::Unit::TestCase
|
|
700
753
|
assert_equal nil, @attachment.path(:blah)
|
701
754
|
end
|
702
755
|
|
756
|
+
context "with a file assigned but not saved yet" do
|
757
|
+
should "clear out any attached files" do
|
758
|
+
@attachment.assign(@file)
|
759
|
+
assert !@attachment.queued_for_write.blank?
|
760
|
+
@attachment.clear
|
761
|
+
assert @attachment.queued_for_write.blank?
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
703
765
|
context "with a file assigned in the database" do
|
704
766
|
setup do
|
705
767
|
@attachment.stubs(:instance_read).with(:file_name).returns("5k.png")
|
@@ -976,4 +1038,27 @@ class AttachmentTest < Test::Unit::TestCase
|
|
976
1038
|
end
|
977
1039
|
end
|
978
1040
|
end
|
1041
|
+
|
1042
|
+
context "an attachment with delete_file option set to false" do
|
1043
|
+
setup do
|
1044
|
+
rebuild_model :preserve_files => true
|
1045
|
+
@dummy = Dummy.new
|
1046
|
+
@file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"), 'rb')
|
1047
|
+
@dummy.avatar = @file
|
1048
|
+
@dummy.save!
|
1049
|
+
@attachment = @dummy.avatar
|
1050
|
+
@path = @attachment.path
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
should "not delete the files from storage when attachment is destroyed" do
|
1054
|
+
@attachment.destroy
|
1055
|
+
assert File.exists?(@path)
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
should "not dleete the file when model is destroy" do
|
1059
|
+
@dummy.destroy
|
1060
|
+
assert File.exists?(@path)
|
1061
|
+
end
|
1062
|
+
end
|
1063
|
+
|
979
1064
|
end
|
data/test/fog_test.rb
CHANGED
@@ -16,15 +16,21 @@ 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_public => true,
|
28
|
+
:fog_file => {:cache_control => 1234},
|
25
29
|
:path => ":attachment/:basename.:extension",
|
26
30
|
:storage => :fog
|
27
|
-
|
31
|
+
}
|
32
|
+
|
33
|
+
rebuild_model(@options)
|
28
34
|
end
|
29
35
|
|
30
36
|
should "be extended by the Fog module" do
|
@@ -46,16 +52,17 @@ class FogTest < Test::Unit::TestCase
|
|
46
52
|
end
|
47
53
|
|
48
54
|
context "without a bucket" do
|
49
|
-
|
55
|
+
setup do
|
56
|
+
@connection.directories.get(@fog_directory).destroy
|
57
|
+
end
|
58
|
+
|
59
|
+
should "create the bucket" do
|
50
60
|
assert @dummy.save
|
61
|
+
assert @connection.directories.get(@fog_directory)
|
51
62
|
end
|
52
63
|
end
|
53
64
|
|
54
65
|
context "with a bucket" do
|
55
|
-
setup do
|
56
|
-
@connection.directories.create(:key => @fog_directory)
|
57
|
-
end
|
58
|
-
|
59
66
|
should "succeed" do
|
60
67
|
assert @dummy.save
|
61
68
|
end
|
@@ -63,14 +70,7 @@ class FogTest < Test::Unit::TestCase
|
|
63
70
|
|
64
71
|
context "without a fog_host" do
|
65
72
|
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
|
-
)
|
73
|
+
rebuild_model(@options.merge(:fog_host => nil))
|
74
74
|
@dummy = Dummy.new
|
75
75
|
@dummy.avatar = StringIO.new('.')
|
76
76
|
@dummy.save
|
@@ -83,14 +83,7 @@ class FogTest < Test::Unit::TestCase
|
|
83
83
|
|
84
84
|
context "with a fog_host" do
|
85
85
|
setup do
|
86
|
-
rebuild_model(
|
87
|
-
:fog_directory => @fog_directory,
|
88
|
-
:fog_credentials => @credentials,
|
89
|
-
:fog_host => 'http://example.com',
|
90
|
-
:fog_public => true,
|
91
|
-
:path => ":attachment/:basename.:extension",
|
92
|
-
:storage => :fog
|
93
|
-
)
|
86
|
+
rebuild_model(@options.merge(:fog_host => 'http://example.com'))
|
94
87
|
@dummy = Dummy.new
|
95
88
|
@dummy.avatar = StringIO.new('.')
|
96
89
|
@dummy.save
|
data/test/helper.rb
CHANGED
data/test/integration_test.rb
CHANGED
@@ -58,6 +58,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
58
58
|
has_attached_file :avatar, :styles => { :thumb => "150x25#", :dynamic => lambda { |a| '50x50#' } }
|
59
59
|
end
|
60
60
|
@d2 = Dummy.find(@dummy.id)
|
61
|
+
@original_timestamp = @d2.avatar_updated_at
|
61
62
|
@d2.avatar.reprocess!
|
62
63
|
@d2.save
|
63
64
|
end
|
@@ -66,6 +67,10 @@ class IntegrationTest < Test::Unit::TestCase
|
|
66
67
|
assert_match /\b150x25\b/, `identify "#{@dummy.avatar.path(:thumb)}"`
|
67
68
|
assert_match /\b50x50\b/, `identify "#{@dummy.avatar.path(:dynamic)}"`
|
68
69
|
end
|
70
|
+
|
71
|
+
should "change the timestamp" do
|
72
|
+
assert_not_equal @original_timestamp, @d2.avatar_updated_at
|
73
|
+
end
|
69
74
|
end
|
70
75
|
end
|
71
76
|
|
@@ -383,6 +388,24 @@ class IntegrationTest < Test::Unit::TestCase
|
|
383
388
|
assert_equal "5k.png", @dummy.avatar_file_name
|
384
389
|
end
|
385
390
|
|
391
|
+
[000,002,022].each do |umask|
|
392
|
+
context "when the umask is #{umask}" do
|
393
|
+
setup do
|
394
|
+
@umask = File.umask umask
|
395
|
+
end
|
396
|
+
|
397
|
+
teardown do
|
398
|
+
File.umask @umask
|
399
|
+
end
|
400
|
+
|
401
|
+
should "respect the current umask" do
|
402
|
+
@dummy.avatar = @file
|
403
|
+
@dummy.save
|
404
|
+
assert_equal 0666&~umask, 0666&File.stat(@dummy.avatar.path).mode
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
386
409
|
context "that is assigned its file from another Paperclip attachment" do
|
387
410
|
setup do
|
388
411
|
@dummy2 = Dummy.new
|
data/test/storage_test.rb
CHANGED
@@ -216,6 +216,7 @@ class StorageTest < Test::Unit::TestCase
|
|
216
216
|
:production => { :bucket => "prod_bucket" },
|
217
217
|
:development => { :bucket => "dev_bucket" }
|
218
218
|
},
|
219
|
+
:s3_permissions => :private,
|
219
220
|
:s3_host_alias => "something.something.com",
|
220
221
|
:path => ":attachment/:style/:basename.:extension",
|
221
222
|
:url => ":s3_alias_url"
|
@@ -225,10 +226,10 @@ class StorageTest < Test::Unit::TestCase
|
|
225
226
|
@dummy = Dummy.new
|
226
227
|
@dummy.avatar = StringIO.new(".")
|
227
228
|
|
228
|
-
AWS::S3::S3Object.expects(:url_for).with("avatars/original/stringio.txt", "prod_bucket", { :expires_in => 3600, :use_ssl =>
|
229
|
+
AWS::S3::S3Object.expects(:url_for).with("avatars/original/stringio.txt", "prod_bucket", { :expires_in => 3600, :use_ssl => true })
|
229
230
|
@dummy.avatar.expiring_url
|
230
231
|
|
231
|
-
AWS::S3::S3Object.expects(:url_for).with("avatars/thumb/stringio.txt", "prod_bucket", { :expires_in => 1800, :use_ssl =>
|
232
|
+
AWS::S3::S3Object.expects(:url_for).with("avatars/thumb/stringio.txt", "prod_bucket", { :expires_in => 1800, :use_ssl => true })
|
232
233
|
@dummy.avatar.expiring_url(1800, :thumb)
|
233
234
|
end
|
234
235
|
|
@@ -432,6 +433,132 @@ class StorageTest < Test::Unit::TestCase
|
|
432
433
|
assert_equal 'env_secret', AWS::S3::Base.connection.options[:secret_access_key]
|
433
434
|
end
|
434
435
|
end
|
436
|
+
|
437
|
+
context "S3 Permissions" do
|
438
|
+
context "defaults to public-read" do
|
439
|
+
setup do
|
440
|
+
rebuild_model :storage => :s3,
|
441
|
+
:bucket => "testing",
|
442
|
+
:path => ":attachment/:style/:basename.:extension",
|
443
|
+
:s3_credentials => {
|
444
|
+
'access_key_id' => "12345",
|
445
|
+
'secret_access_key' => "54321"
|
446
|
+
}
|
447
|
+
end
|
448
|
+
|
449
|
+
context "when assigned" do
|
450
|
+
setup do
|
451
|
+
@file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
452
|
+
@dummy = Dummy.new
|
453
|
+
@dummy.avatar = @file
|
454
|
+
end
|
455
|
+
|
456
|
+
teardown { @file.close }
|
457
|
+
|
458
|
+
context "and saved" do
|
459
|
+
setup do
|
460
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
461
|
+
AWS::S3::S3Object.expects(:store).with(@dummy.avatar.path,
|
462
|
+
anything,
|
463
|
+
'testing',
|
464
|
+
:content_type => 'image/png',
|
465
|
+
:access => :public_read)
|
466
|
+
@dummy.save
|
467
|
+
end
|
468
|
+
|
469
|
+
should "succeed" do
|
470
|
+
assert true
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
context "string permissions set" do
|
477
|
+
setup do
|
478
|
+
rebuild_model :storage => :s3,
|
479
|
+
:bucket => "testing",
|
480
|
+
:path => ":attachment/:style/:basename.:extension",
|
481
|
+
:s3_credentials => {
|
482
|
+
'access_key_id' => "12345",
|
483
|
+
'secret_access_key' => "54321"
|
484
|
+
},
|
485
|
+
:s3_permissions => 'private'
|
486
|
+
end
|
487
|
+
|
488
|
+
context "when assigned" do
|
489
|
+
setup do
|
490
|
+
@file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
491
|
+
@dummy = Dummy.new
|
492
|
+
@dummy.avatar = @file
|
493
|
+
end
|
494
|
+
|
495
|
+
teardown { @file.close }
|
496
|
+
|
497
|
+
context "and saved" do
|
498
|
+
setup do
|
499
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
500
|
+
AWS::S3::S3Object.expects(:store).with(@dummy.avatar.path,
|
501
|
+
anything,
|
502
|
+
'testing',
|
503
|
+
:content_type => 'image/png',
|
504
|
+
:access => 'private')
|
505
|
+
@dummy.save
|
506
|
+
end
|
507
|
+
|
508
|
+
should "succeed" do
|
509
|
+
assert true
|
510
|
+
end
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
context "hash permissions set" do
|
516
|
+
setup do
|
517
|
+
rebuild_model :storage => :s3,
|
518
|
+
:bucket => "testing",
|
519
|
+
:path => ":attachment/:style/:basename.:extension",
|
520
|
+
:styles => {
|
521
|
+
:thumb => "80x80>"
|
522
|
+
},
|
523
|
+
:s3_credentials => {
|
524
|
+
'access_key_id' => "12345",
|
525
|
+
'secret_access_key' => "54321"
|
526
|
+
},
|
527
|
+
:s3_permissions => {
|
528
|
+
:original => 'private',
|
529
|
+
:thumb => 'public-read'
|
530
|
+
}
|
531
|
+
end
|
532
|
+
|
533
|
+
context "when assigned" do
|
534
|
+
setup do
|
535
|
+
@file = File.new(File.join(File.dirname(__FILE__), 'fixtures', '5k.png'), 'rb')
|
536
|
+
@dummy = Dummy.new
|
537
|
+
@dummy.avatar = @file
|
538
|
+
end
|
539
|
+
|
540
|
+
teardown { @file.close }
|
541
|
+
|
542
|
+
context "and saved" do
|
543
|
+
setup do
|
544
|
+
AWS::S3::Base.stubs(:establish_connection!)
|
545
|
+
[:thumb, :original].each do |style|
|
546
|
+
AWS::S3::S3Object.expects(:store).with("avatars/#{style}/5k.png",
|
547
|
+
anything,
|
548
|
+
'testing',
|
549
|
+
:content_type => 'image/png',
|
550
|
+
:access => style == :thumb ? 'public-read' : 'private')
|
551
|
+
end
|
552
|
+
@dummy.save
|
553
|
+
end
|
554
|
+
|
555
|
+
should "succeed" do
|
556
|
+
assert true
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|
435
562
|
|
436
563
|
unless ENV["S3_TEST_BUCKET"].blank?
|
437
564
|
context "Using S3 for real, an attachment with S3 storage" do
|
data/test/style_test.rb
CHANGED
@@ -62,12 +62,12 @@ class StyleTest < Test::Unit::TestCase
|
|
62
62
|
|
63
63
|
context "An attachment with style rules in various forms" do
|
64
64
|
setup do
|
65
|
+
styles = ActiveSupport::OrderedHash.new
|
66
|
+
styles[:aslist] = ["100x100", :png]
|
67
|
+
styles[:ashash] = {:geometry => "100x100", :format => :png}
|
68
|
+
styles[:asstring] = "100x100"
|
65
69
|
@attachment = attachment :path => ":basename.:extension",
|
66
|
-
:styles =>
|
67
|
-
:aslist => ["100x100", :png],
|
68
|
-
:ashash => {:geometry => "100x100", :format => :png},
|
69
|
-
:asstring => "100x100"
|
70
|
-
}
|
70
|
+
:styles => styles
|
71
71
|
end
|
72
72
|
should "have the right number of styles" do
|
73
73
|
assert_kind_of Hash, @attachment.styles
|
@@ -92,6 +92,9 @@ class StyleTest < Test::Unit::TestCase
|
|
92
92
|
assert_nil @attachment.styles[:asstring].format
|
93
93
|
end
|
94
94
|
|
95
|
+
should "retain order" do
|
96
|
+
assert_equal [:aslist, :ashash, :asstring], @attachment.styles.keys
|
97
|
+
end
|
95
98
|
end
|
96
99
|
|
97
100
|
context "An attachment with :convert_options" do
|
@@ -138,7 +141,7 @@ class StyleTest < Test::Unit::TestCase
|
|
138
141
|
end
|
139
142
|
|
140
143
|
end
|
141
|
-
|
144
|
+
|
142
145
|
context "A style rule with :processors supplied as procs" do
|
143
146
|
setup do
|
144
147
|
@attachment = attachment :path => ":basename.:extension",
|
data/test/thumbnail_test.rb
CHANGED
@@ -289,6 +289,10 @@ class ThumbnailTest < Test::Unit::TestCase
|
|
289
289
|
cmd = %Q[identify -format "%wx%h" "#{dst.path}"]
|
290
290
|
assert_equal "50x50"*12, `#{cmd}`.chomp
|
291
291
|
end
|
292
|
+
|
293
|
+
should "use the -coalesce option" do
|
294
|
+
assert_equal @thumb.transformation_command.first, "-coalesce"
|
295
|
+
end
|
292
296
|
end
|
293
297
|
|
294
298
|
context "with omitted output format" do
|
@@ -301,6 +305,10 @@ class ThumbnailTest < Test::Unit::TestCase
|
|
301
305
|
cmd = %Q[identify -format "%wx%h" "#{dst.path}"]
|
302
306
|
assert_equal "50x50"*12, `#{cmd}`.chomp
|
303
307
|
end
|
308
|
+
|
309
|
+
should "use the -coalesce option" do
|
310
|
+
assert_equal @thumb.transformation_command.first, "-coalesce"
|
311
|
+
end
|
304
312
|
end
|
305
313
|
end
|
306
314
|
end
|
data/test/upfile_test.rb
CHANGED
@@ -10,9 +10,9 @@ class UpfileTest < Test::Unit::TestCase
|
|
10
10
|
%w(txt) => 'text/plain',
|
11
11
|
%w(htm html) => 'text/html',
|
12
12
|
%w(csv) => 'text/csv',
|
13
|
-
%w(xml) => '
|
13
|
+
%w(xml) => 'application/xml',
|
14
14
|
%w(css) => 'text/css',
|
15
|
-
%w(js) => 'application/
|
15
|
+
%w(js) => 'application/javascript',
|
16
16
|
%w(foo) => 'application/x-foo'
|
17
17
|
}.each do |extensions, content_type|
|
18
18
|
extensions.each do |extension|
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paperclip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 27
|
5
4
|
prerelease:
|
6
|
-
|
7
|
-
- 2
|
8
|
-
- 3
|
9
|
-
- 12
|
10
|
-
version: 2.3.12
|
5
|
+
version: 2.3.15
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Jon Yurek
|
@@ -15,127 +10,108 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date: 2011-
|
13
|
+
date: 2011-07-10 00:00:00 -04:00
|
19
14
|
default_executable:
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
22
17
|
name: activerecord
|
23
|
-
prerelease: false
|
24
18
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
19
|
none: false
|
26
20
|
requirements:
|
27
21
|
- - ">="
|
28
22
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 3
|
30
|
-
segments:
|
31
|
-
- 2
|
32
|
-
- 3
|
33
|
-
- 0
|
34
23
|
version: 2.3.0
|
35
24
|
type: :runtime
|
25
|
+
prerelease: false
|
36
26
|
version_requirements: *id001
|
37
27
|
- !ruby/object:Gem::Dependency
|
38
28
|
name: activesupport
|
39
|
-
prerelease: false
|
40
29
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
30
|
none: false
|
42
31
|
requirements:
|
43
32
|
- - ">="
|
44
33
|
- !ruby/object:Gem::Version
|
45
|
-
hash: 7
|
46
|
-
segments:
|
47
|
-
- 2
|
48
|
-
- 3
|
49
|
-
- 2
|
50
34
|
version: 2.3.2
|
51
35
|
type: :runtime
|
36
|
+
prerelease: false
|
52
37
|
version_requirements: *id002
|
53
38
|
- !ruby/object:Gem::Dependency
|
54
39
|
name: cocaine
|
55
|
-
prerelease: false
|
56
40
|
requirement: &id003 !ruby/object:Gem::Requirement
|
57
41
|
none: false
|
58
42
|
requirements:
|
59
43
|
- - ">="
|
60
44
|
- !ruby/object:Gem::Version
|
61
|
-
hash: 27
|
62
|
-
segments:
|
63
|
-
- 0
|
64
|
-
- 0
|
65
|
-
- 2
|
66
45
|
version: 0.0.2
|
67
46
|
type: :runtime
|
47
|
+
prerelease: false
|
68
48
|
version_requirements: *id003
|
69
49
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
71
|
-
prerelease: false
|
50
|
+
name: mime-types
|
72
51
|
requirement: &id004 !ruby/object:Gem::Requirement
|
73
52
|
none: false
|
74
53
|
requirements:
|
75
54
|
- - ">="
|
76
55
|
- !ruby/object:Gem::Version
|
77
|
-
hash: 3
|
78
|
-
segments:
|
79
|
-
- 0
|
80
56
|
version: "0"
|
81
|
-
type: :
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
82
59
|
version_requirements: *id004
|
83
60
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
85
|
-
prerelease: false
|
61
|
+
name: shoulda
|
86
62
|
requirement: &id005 !ruby/object:Gem::Requirement
|
87
63
|
none: false
|
88
64
|
requirements:
|
89
65
|
- - ">="
|
90
66
|
- !ruby/object:Gem::Version
|
91
|
-
hash: 3
|
92
|
-
segments:
|
93
|
-
- 0
|
94
67
|
version: "0"
|
95
68
|
type: :development
|
69
|
+
prerelease: false
|
96
70
|
version_requirements: *id005
|
97
71
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
99
|
-
prerelease: false
|
72
|
+
name: appraisal
|
100
73
|
requirement: &id006 !ruby/object:Gem::Requirement
|
101
74
|
none: false
|
102
75
|
requirements:
|
103
76
|
- - ">="
|
104
77
|
- !ruby/object:Gem::Version
|
105
|
-
hash: 3
|
106
|
-
segments:
|
107
|
-
- 0
|
108
78
|
version: "0"
|
109
79
|
type: :development
|
80
|
+
prerelease: false
|
110
81
|
version_requirements: *id006
|
111
82
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
113
|
-
prerelease: false
|
83
|
+
name: mocha
|
114
84
|
requirement: &id007 !ruby/object:Gem::Requirement
|
115
85
|
none: false
|
116
86
|
requirements:
|
117
87
|
- - ">="
|
118
88
|
- !ruby/object:Gem::Version
|
119
|
-
hash: 3
|
120
|
-
segments:
|
121
|
-
- 0
|
122
89
|
version: "0"
|
123
90
|
type: :development
|
91
|
+
prerelease: false
|
124
92
|
version_requirements: *id007
|
125
93
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
127
|
-
prerelease: false
|
94
|
+
name: aws-s3
|
128
95
|
requirement: &id008 !ruby/object:Gem::Requirement
|
129
96
|
none: false
|
130
97
|
requirements:
|
131
98
|
- - ">="
|
132
99
|
- !ruby/object:Gem::Version
|
133
|
-
hash: 3
|
134
|
-
segments:
|
135
|
-
- 0
|
136
100
|
version: "0"
|
137
101
|
type: :development
|
102
|
+
prerelease: false
|
138
103
|
version_requirements: *id008
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: sqlite3-ruby
|
106
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: "0"
|
112
|
+
type: :development
|
113
|
+
prerelease: false
|
114
|
+
version_requirements: *id009
|
139
115
|
description: Easy upload management for ActiveRecord
|
140
116
|
email: jyurek@thoughtbot.com
|
141
117
|
executables: []
|
@@ -149,45 +125,33 @@ files:
|
|
149
125
|
- LICENSE
|
150
126
|
- Rakefile
|
151
127
|
- init.rb
|
152
|
-
- lib/paperclip.rb
|
128
|
+
- lib/generators/paperclip/paperclip_generator.rb
|
129
|
+
- lib/generators/paperclip/templates/paperclip_migration.rb.erb
|
130
|
+
- lib/generators/paperclip/USAGE
|
153
131
|
- lib/paperclip/attachment.rb
|
154
132
|
- lib/paperclip/callback_compatibility.rb
|
155
133
|
- lib/paperclip/geometry.rb
|
156
134
|
- lib/paperclip/interpolations.rb
|
157
135
|
- lib/paperclip/iostream.rb
|
136
|
+
- lib/paperclip/matchers/have_attached_file_matcher.rb
|
137
|
+
- lib/paperclip/matchers/validate_attachment_content_type_matcher.rb
|
138
|
+
- lib/paperclip/matchers/validate_attachment_presence_matcher.rb
|
139
|
+
- lib/paperclip/matchers/validate_attachment_size_matcher.rb
|
158
140
|
- lib/paperclip/matchers.rb
|
159
141
|
- lib/paperclip/processor.rb
|
160
142
|
- lib/paperclip/railtie.rb
|
143
|
+
- lib/paperclip/storage/filesystem.rb
|
144
|
+
- lib/paperclip/storage/fog.rb
|
145
|
+
- lib/paperclip/storage/s3.rb
|
161
146
|
- lib/paperclip/storage.rb
|
162
147
|
- lib/paperclip/style.rb
|
163
148
|
- lib/paperclip/thumbnail.rb
|
164
149
|
- lib/paperclip/upfile.rb
|
165
150
|
- lib/paperclip/version.rb
|
151
|
+
- lib/paperclip.rb
|
166
152
|
- lib/tasks/paperclip.rake
|
167
|
-
- lib/paperclip/matchers/have_attached_file_matcher.rb
|
168
|
-
- lib/paperclip/matchers/validate_attachment_content_type_matcher.rb
|
169
|
-
- lib/paperclip/matchers/validate_attachment_presence_matcher.rb
|
170
|
-
- lib/paperclip/matchers/validate_attachment_size_matcher.rb
|
171
|
-
- lib/paperclip/storage/filesystem.rb
|
172
|
-
- lib/paperclip/storage/fog.rb
|
173
|
-
- lib/paperclip/storage/s3.rb
|
174
|
-
- lib/generators/paperclip/paperclip_generator.rb
|
175
|
-
- lib/generators/paperclip/USAGE
|
176
|
-
- lib/generators/paperclip/templates/paperclip_migration.rb.erb
|
177
153
|
- test/attachment_test.rb
|
178
154
|
- test/database.yml
|
179
|
-
- test/fog_test.rb
|
180
|
-
- test/geometry_test.rb
|
181
|
-
- test/helper.rb
|
182
|
-
- test/integration_test.rb
|
183
|
-
- test/interpolations_test.rb
|
184
|
-
- test/iostream_test.rb
|
185
|
-
- test/paperclip_test.rb
|
186
|
-
- test/processor_test.rb
|
187
|
-
- test/storage_test.rb
|
188
|
-
- test/style_test.rb
|
189
|
-
- test/thumbnail_test.rb
|
190
|
-
- test/upfile_test.rb
|
191
155
|
- test/fixtures/12k.png
|
192
156
|
- test/fixtures/50x50.png
|
193
157
|
- test/fixtures/5k.png
|
@@ -197,13 +161,26 @@ files:
|
|
197
161
|
- test/fixtures/text.txt
|
198
162
|
- test/fixtures/twopage.pdf
|
199
163
|
- test/fixtures/uppercase.PNG
|
164
|
+
- test/fog_test.rb
|
165
|
+
- test/geometry_test.rb
|
166
|
+
- test/helper.rb
|
167
|
+
- test/integration_test.rb
|
168
|
+
- test/interpolations_test.rb
|
169
|
+
- test/iostream_test.rb
|
200
170
|
- test/matchers/have_attached_file_matcher_test.rb
|
201
171
|
- test/matchers/validate_attachment_content_type_matcher_test.rb
|
202
172
|
- test/matchers/validate_attachment_presence_matcher_test.rb
|
203
173
|
- test/matchers/validate_attachment_size_matcher_test.rb
|
174
|
+
- test/paperclip_test.rb
|
175
|
+
- test/processor_test.rb
|
176
|
+
- test/storage_test.rb
|
177
|
+
- test/style_test.rb
|
178
|
+
- test/thumbnail_test.rb
|
179
|
+
- test/upfile_test.rb
|
180
|
+
- rails/init.rb
|
204
181
|
- generators/paperclip/paperclip_generator.rb
|
205
|
-
- generators/paperclip/USAGE
|
206
182
|
- generators/paperclip/templates/paperclip_migration.rb.erb
|
183
|
+
- generators/paperclip/USAGE
|
207
184
|
- shoulda_macros/paperclip.rb
|
208
185
|
has_rdoc: true
|
209
186
|
homepage: https://github.com/thoughtbot/paperclip
|
@@ -220,7 +197,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
220
197
|
requirements:
|
221
198
|
- - ">="
|
222
199
|
- !ruby/object:Gem::Version
|
223
|
-
hash:
|
200
|
+
hash: 2036980330891834332
|
224
201
|
segments:
|
225
202
|
- 0
|
226
203
|
version: "0"
|
@@ -229,14 +206,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
229
206
|
requirements:
|
230
207
|
- - ">="
|
231
208
|
- !ruby/object:Gem::Version
|
232
|
-
hash: 3
|
233
|
-
segments:
|
234
|
-
- 0
|
235
209
|
version: "0"
|
236
210
|
requirements:
|
237
211
|
- ImageMagick
|
238
212
|
rubyforge_project: paperclip
|
239
|
-
rubygems_version: 1.
|
213
|
+
rubygems_version: 1.6.2
|
240
214
|
signing_key:
|
241
215
|
specification_version: 3
|
242
216
|
summary: File attachments as attributes for ActiveRecord
|