paperclip 3.0.3 → 3.5.1
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.
- checksums.yaml +15 -0
- data/.gitignore +2 -1
- data/.travis.yml +3 -0
- data/Appraisals +8 -3
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/NEWS +198 -35
- data/README.md +332 -113
- data/features/basic_integration.feature +24 -12
- data/features/migration.feature +94 -0
- data/features/rake_tasks.feature +2 -3
- data/features/step_definitions/attachment_steps.rb +28 -0
- data/features/step_definitions/rails_steps.rb +94 -8
- data/features/step_definitions/s3_steps.rb +1 -1
- data/features/step_definitions/web_steps.rb +3 -3
- data/features/support/fakeweb.rb +4 -1
- data/features/support/file_helpers.rb +10 -0
- data/features/support/rails.rb +18 -2
- data/gemfiles/3.0.gemfile +2 -2
- data/gemfiles/3.1.gemfile +2 -2
- data/gemfiles/3.2.gemfile +2 -2
- data/gemfiles/4.0.gemfile +11 -0
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +4 -8
- data/lib/paperclip/attachment.rb +96 -43
- data/lib/paperclip/attachment_registry.rb +57 -0
- data/lib/paperclip/callbacks.rb +2 -2
- data/lib/paperclip/content_type_detector.rb +78 -0
- data/lib/paperclip/file_command_content_type_detector.rb +32 -0
- data/lib/paperclip/filename_cleaner.rb +16 -0
- data/lib/paperclip/geometry.rb +66 -30
- data/lib/paperclip/geometry_detector_factory.rb +41 -0
- data/lib/paperclip/geometry_parser_factory.rb +31 -0
- data/lib/paperclip/glue.rb +2 -8
- data/lib/paperclip/has_attached_file.rb +99 -0
- data/lib/paperclip/helpers.rb +12 -15
- data/lib/paperclip/interpolations/plural_cache.rb +17 -0
- data/lib/paperclip/interpolations.rb +15 -5
- data/lib/paperclip/io_adapters/abstract_adapter.rb +45 -0
- data/lib/paperclip/io_adapters/attachment_adapter.rb +14 -49
- data/lib/paperclip/io_adapters/data_uri_adapter.rb +27 -0
- data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
- data/lib/paperclip/io_adapters/file_adapter.rb +8 -69
- data/lib/paperclip/io_adapters/identity_adapter.rb +1 -1
- data/lib/paperclip/io_adapters/nil_adapter.rb +2 -2
- data/lib/paperclip/io_adapters/stringio_adapter.rb +16 -45
- data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +17 -40
- data/lib/paperclip/io_adapters/uri_adapter.rb +44 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +1 -5
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +36 -17
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +5 -1
- data/lib/paperclip/matchers.rb +3 -3
- data/lib/paperclip/missing_attachment_styles.rb +11 -16
- data/lib/paperclip/processor.rb +12 -0
- data/lib/paperclip/railtie.rb +5 -1
- data/lib/paperclip/schema.rb +59 -23
- data/lib/paperclip/storage/filesystem.rb +23 -5
- data/lib/paperclip/storage/fog.rb +64 -25
- data/lib/paperclip/storage/s3.rb +93 -52
- data/lib/paperclip/style.rb +2 -2
- data/lib/paperclip/tempfile_factory.rb +21 -0
- data/lib/paperclip/thumbnail.rb +18 -3
- data/lib/paperclip/validators/attachment_content_type_validator.rb +38 -10
- data/lib/paperclip/validators/attachment_presence_validator.rb +8 -8
- data/lib/paperclip/validators/attachment_size_validator.rb +12 -7
- data/lib/paperclip/validators.rb +21 -2
- data/lib/paperclip/version.rb +1 -1
- data/lib/paperclip.rb +15 -44
- data/lib/tasks/paperclip.rake +26 -7
- data/paperclip.gemspec +11 -7
- data/test/attachment_definitions_test.rb +12 -0
- data/test/attachment_processing_test.rb +83 -0
- data/test/attachment_registry_test.rb +77 -0
- data/test/attachment_test.rb +253 -44
- data/test/content_type_detector_test.rb +50 -0
- data/test/file_command_content_type_detector_test.rb +25 -0
- data/test/filename_cleaner_test.rb +14 -0
- data/test/fixtures/animated +0 -0
- data/test/fixtures/animated.unknown +0 -0
- data/test/fixtures/rotated.jpg +0 -0
- data/test/generator_test.rb +26 -24
- data/test/geometry_detector_test.rb +24 -0
- data/test/geometry_parser_test.rb +73 -0
- data/test/geometry_test.rb +55 -4
- data/test/has_attached_file_test.rb +125 -0
- data/test/helper.rb +38 -7
- data/test/integration_test.rb +105 -89
- data/test/interpolations_test.rb +12 -0
- data/test/io_adapters/abstract_adapter_test.rb +58 -0
- data/test/io_adapters/attachment_adapter_test.rb +120 -33
- data/test/io_adapters/data_uri_adapter_test.rb +60 -0
- data/test/io_adapters/empty_string_adapter_test.rb +17 -0
- data/test/io_adapters/file_adapter_test.rb +32 -1
- data/test/io_adapters/stringio_adapter_test.rb +29 -10
- data/test/io_adapters/uploaded_file_adapter_test.rb +53 -5
- data/test/io_adapters/uri_adapter_test.rb +102 -0
- data/test/matchers/validate_attachment_presence_matcher_test.rb +22 -0
- data/test/meta_class_test.rb +32 -0
- data/test/paperclip_missing_attachment_styles_test.rb +4 -8
- data/test/paperclip_test.rb +27 -51
- data/test/plural_cache_test.rb +36 -0
- data/test/processor_test.rb +16 -0
- data/test/rake_test.rb +103 -0
- data/test/schema_test.rb +179 -77
- data/test/storage/filesystem_test.rb +26 -3
- data/test/storage/fog_test.rb +181 -3
- data/test/storage/s3_test.rb +239 -4
- data/test/style_test.rb +18 -14
- data/test/tempfile_factory_test.rb +13 -0
- data/test/thumbnail_test.rb +96 -16
- data/test/validators/attachment_content_type_validator_test.rb +181 -55
- data/test/validators/attachment_size_validator_test.rb +10 -0
- data/test/validators_test.rb +8 -1
- metadata +126 -92
- data/Gemfile.lock +0 -157
- data/features/support/fixtures/.boot_config.rb.swo +0 -0
- data/images.rake +0 -21
- data/lib/.DS_Store +0 -0
- data/lib/paperclip/.DS_Store +0 -0
- data/lib/paperclip/attachment_options.rb +0 -9
- data/lib/paperclip/instance_methods.rb +0 -35
- data/test/attachment_options_test.rb +0 -27
@@ -0,0 +1,73 @@
|
|
1
|
+
require './test/helper'
|
2
|
+
|
3
|
+
class GeometryParserTest < Test::Unit::TestCase
|
4
|
+
should 'identify an image and extract its dimensions with no orientation' do
|
5
|
+
Paperclip::Geometry.stubs(:new).with(
|
6
|
+
:height => '73',
|
7
|
+
:width => '434',
|
8
|
+
:modifier => nil,
|
9
|
+
:orientation => nil
|
10
|
+
).returns(:correct)
|
11
|
+
factory = Paperclip::GeometryParser.new("434x73")
|
12
|
+
|
13
|
+
output = factory.make
|
14
|
+
|
15
|
+
assert_equal :correct, output
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'identify an image and extract its dimensions with an empty orientation' do
|
19
|
+
Paperclip::Geometry.stubs(:new).with(
|
20
|
+
:height => '73',
|
21
|
+
:width => '434',
|
22
|
+
:modifier => nil,
|
23
|
+
:orientation => ''
|
24
|
+
).returns(:correct)
|
25
|
+
factory = Paperclip::GeometryParser.new("434x73,")
|
26
|
+
|
27
|
+
output = factory.make
|
28
|
+
|
29
|
+
assert_equal :correct, output
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'identify an image and extract its dimensions and orientation' do
|
33
|
+
Paperclip::Geometry.stubs(:new).with(
|
34
|
+
:height => '200',
|
35
|
+
:width => '300',
|
36
|
+
:modifier => nil,
|
37
|
+
:orientation => '6'
|
38
|
+
).returns(:correct)
|
39
|
+
factory = Paperclip::GeometryParser.new("300x200,6")
|
40
|
+
|
41
|
+
output = factory.make
|
42
|
+
|
43
|
+
assert_equal :correct, output
|
44
|
+
end
|
45
|
+
|
46
|
+
should 'identify an image and extract its dimensions and modifier' do
|
47
|
+
Paperclip::Geometry.stubs(:new).with(
|
48
|
+
:height => '64',
|
49
|
+
:width => '64',
|
50
|
+
:modifier => '#',
|
51
|
+
:orientation => nil
|
52
|
+
).returns(:correct)
|
53
|
+
factory = Paperclip::GeometryParser.new("64x64#")
|
54
|
+
|
55
|
+
output = factory.make
|
56
|
+
|
57
|
+
assert_equal :correct, output
|
58
|
+
end
|
59
|
+
|
60
|
+
should 'identify an image and extract its dimensions, orientation, and modifier' do
|
61
|
+
Paperclip::Geometry.stubs(:new).with(
|
62
|
+
:height => '50',
|
63
|
+
:width => '100',
|
64
|
+
:modifier => '>',
|
65
|
+
:orientation => '7'
|
66
|
+
).returns(:correct)
|
67
|
+
factory = Paperclip::GeometryParser.new("100x50,7>")
|
68
|
+
|
69
|
+
output = factory.make
|
70
|
+
|
71
|
+
assert_equal :correct, output
|
72
|
+
end
|
73
|
+
end
|
data/test/geometry_test.rb
CHANGED
@@ -49,6 +49,30 @@ class GeometryTest < Test::Unit::TestCase
|
|
49
49
|
assert_nil @geo.modifier
|
50
50
|
end
|
51
51
|
|
52
|
+
should "recognize an EXIF orientation and not rotate with auto_orient if not necessary" do
|
53
|
+
geo = Paperclip::Geometry.new(:width => 1024, :height => 768, :orientation => 1)
|
54
|
+
assert geo
|
55
|
+
assert_equal 1024, geo.width
|
56
|
+
assert_equal 768, geo.height
|
57
|
+
|
58
|
+
geo.auto_orient
|
59
|
+
|
60
|
+
assert_equal 1024, geo.width
|
61
|
+
assert_equal 768, geo.height
|
62
|
+
end
|
63
|
+
|
64
|
+
should "recognize an EXIF orientation and rotate with auto_orient if necessary" do
|
65
|
+
geo = Paperclip::Geometry.new(:width => 1024, :height => 768, :orientation => 6)
|
66
|
+
assert geo
|
67
|
+
assert_equal 1024, geo.width
|
68
|
+
assert_equal 768, geo.height
|
69
|
+
|
70
|
+
geo.auto_orient
|
71
|
+
|
72
|
+
assert_equal 768, geo.width
|
73
|
+
assert_equal 1024, geo.height
|
74
|
+
end
|
75
|
+
|
52
76
|
should "treat x and X the same in geometries" do
|
53
77
|
@lower = Paperclip::Geometry.parse("123x456")
|
54
78
|
@upper = Paperclip::Geometry.parse("123X456")
|
@@ -104,15 +128,23 @@ class GeometryTest < Test::Unit::TestCase
|
|
104
128
|
file = fixture_file("5k.png")
|
105
129
|
file = File.new(file, 'rb')
|
106
130
|
assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
|
107
|
-
|
108
|
-
|
131
|
+
assert_equal 66, @geo.height
|
132
|
+
assert_equal 434, @geo.width
|
109
133
|
end
|
110
134
|
|
111
135
|
should "be generated from a file path" do
|
112
136
|
file = fixture_file("5k.png")
|
113
137
|
assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
|
114
|
-
|
115
|
-
|
138
|
+
assert_equal 66, @geo.height
|
139
|
+
assert_equal 434, @geo.width
|
140
|
+
end
|
141
|
+
|
142
|
+
should 'calculate an EXIF-rotated image dimensions from a path' do
|
143
|
+
file = fixture_file("rotated.jpg")
|
144
|
+
assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
|
145
|
+
@geo.auto_orient
|
146
|
+
assert_equal 300, @geo.height
|
147
|
+
assert_equal 200, @geo.width
|
116
148
|
end
|
117
149
|
|
118
150
|
should "not generate from a bad file" do
|
@@ -202,5 +234,24 @@ class GeometryTest < Test::Unit::TestCase
|
|
202
234
|
end
|
203
235
|
end
|
204
236
|
end
|
237
|
+
|
238
|
+
[['256x256', {'150x150!' => [150, 150], '150x150#' => [150, 150], '150x150>' => [150, 150], '150x150<' => [256, 256], '150x150' => [150, 150]}],
|
239
|
+
['256x256', {'512x512!' => [512, 512], '512x512#' => [512, 512], '512x512>' => [256, 256], '512x512<' => [512, 512], '512x512' => [512, 512]}],
|
240
|
+
['600x400', {'512x512!' => [512, 512], '512x512#' => [512, 512], '512x512>' => [512, 341], '512x512<' => [600, 400], '512x512' => [512, 341]}]].each do |original_size, options|
|
241
|
+
options.each_pair do |size, dimensions|
|
242
|
+
context "#{original_size} resize_to #{size}" do
|
243
|
+
setup do
|
244
|
+
@source = Paperclip::Geometry.parse original_size
|
245
|
+
@new_geometry = @source.resize_to size
|
246
|
+
end
|
247
|
+
should "have #{dimensions.first} width" do
|
248
|
+
assert_equal dimensions.first, @new_geometry.width
|
249
|
+
end
|
250
|
+
should "have #{dimensions.last} height" do
|
251
|
+
assert_equal dimensions.last, @new_geometry.height
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
205
256
|
end
|
206
257
|
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require './test/helper'
|
2
|
+
require 'paperclip/has_attached_file'
|
3
|
+
|
4
|
+
class HasAttachedFileTest < Test::Unit::TestCase
|
5
|
+
context '#define_on' do
|
6
|
+
should 'define a setter on the class object' do
|
7
|
+
assert_adding_attachment('avatar').defines_method('avatar=')
|
8
|
+
end
|
9
|
+
|
10
|
+
should 'define a getter on the class object' do
|
11
|
+
assert_adding_attachment('avatar').defines_method('avatar')
|
12
|
+
end
|
13
|
+
|
14
|
+
should 'define a query on the class object' do
|
15
|
+
assert_adding_attachment('avatar').defines_method('avatar?')
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'define a method on the class to get all of its attachments' do
|
19
|
+
assert_adding_attachment('avatar').defines_class_method('attachment_definitions')
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'flush errors as part of validations' do
|
23
|
+
assert_adding_attachment('avatar').defines_validation
|
24
|
+
end
|
25
|
+
|
26
|
+
should 'register the attachment with Paperclip::AttachmentRegistry' do
|
27
|
+
assert_adding_attachment('avatar').registers_attachment
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'define an after_save callback' do
|
31
|
+
assert_adding_attachment('avatar').defines_callback('after_save')
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'define a before_destroy callback' do
|
35
|
+
assert_adding_attachment('avatar').defines_callback('before_destroy')
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'define an after_destroy callback' do
|
39
|
+
assert_adding_attachment('avatar').defines_callback('after_destroy')
|
40
|
+
end
|
41
|
+
|
42
|
+
should 'define the Paperclip-specific callbacks' do
|
43
|
+
assert_adding_attachment('avatar').defines_callback('define_paperclip_callbacks')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def assert_adding_attachment(attachment_name)
|
50
|
+
AttachmentAdder.new(attachment_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
class AttachmentAdder
|
54
|
+
include Mocha::API
|
55
|
+
include Test::Unit::Assertions
|
56
|
+
|
57
|
+
def initialize(attachment_name)
|
58
|
+
@attachment_name = attachment_name
|
59
|
+
end
|
60
|
+
|
61
|
+
def defines_method(method_name)
|
62
|
+
a_class = stub_class
|
63
|
+
|
64
|
+
Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
|
65
|
+
|
66
|
+
assert_received(a_class, :define_method) do |expect|
|
67
|
+
expect.with(method_name)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def defines_class_method(method_name)
|
72
|
+
a_class = stub_class
|
73
|
+
a_class.class.stubs(:define_method)
|
74
|
+
|
75
|
+
Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
|
76
|
+
|
77
|
+
assert_received(a_class, :extend) do |expect|
|
78
|
+
expect.with(Paperclip::HasAttachedFile::ClassMethods)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def defines_validation
|
83
|
+
a_class = stub_class
|
84
|
+
|
85
|
+
Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
|
86
|
+
|
87
|
+
assert_received(a_class, :validates_each) do |expect|
|
88
|
+
expect.with(@attachment_name)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def registers_attachment
|
93
|
+
a_class = stub_class
|
94
|
+
Paperclip::AttachmentRegistry.stubs(:register)
|
95
|
+
|
96
|
+
Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {size: 1})
|
97
|
+
|
98
|
+
assert_received(Paperclip::AttachmentRegistry, :register) do |expect|
|
99
|
+
expect.with(a_class, @attachment_name, {size: 1})
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def defines_callback(callback_name)
|
104
|
+
a_class = stub_class
|
105
|
+
|
106
|
+
Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
|
107
|
+
|
108
|
+
assert_received(a_class, callback_name.to_sym)
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def stub_class
|
114
|
+
stub('class',
|
115
|
+
validates_each: nil,
|
116
|
+
define_method: nil,
|
117
|
+
after_save: nil,
|
118
|
+
before_destroy: nil,
|
119
|
+
after_destroy: nil,
|
120
|
+
define_paperclip_callbacks: nil,
|
121
|
+
extend: nil,
|
122
|
+
name: 'Billy')
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/test/helper.rb
CHANGED
@@ -2,18 +2,18 @@ require 'rubygems'
|
|
2
2
|
require 'tempfile'
|
3
3
|
require 'pathname'
|
4
4
|
require 'test/unit'
|
5
|
-
|
6
|
-
require 'shoulda'
|
7
|
-
require 'mocha'
|
8
|
-
require 'bourne'
|
9
|
-
|
10
5
|
require 'active_record'
|
11
6
|
require 'active_record/version'
|
12
7
|
require 'active_support'
|
13
8
|
require 'active_support/core_ext'
|
9
|
+
require 'shoulda'
|
10
|
+
require 'mocha/setup'
|
11
|
+
require 'bourne'
|
12
|
+
require 'shoulda/context'
|
14
13
|
require 'mime/types'
|
15
14
|
require 'pathname'
|
16
15
|
require 'ostruct'
|
16
|
+
require 'pry'
|
17
17
|
|
18
18
|
puts "Testing against version #{ActiveRecord::VERSION::STRING}"
|
19
19
|
|
@@ -47,10 +47,14 @@ require './shoulda_macros/paperclip'
|
|
47
47
|
|
48
48
|
FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
|
49
49
|
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
50
|
-
ActiveRecord::Base.logger =
|
50
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
51
51
|
ActiveRecord::Base.establish_connection(config['test'])
|
52
52
|
Paperclip.options[:logger] = ActiveRecord::Base.logger
|
53
53
|
|
54
|
+
def using_protected_attributes?
|
55
|
+
ActiveRecord::VERSION::MAJOR < 4
|
56
|
+
end
|
57
|
+
|
54
58
|
def require_everything_in_directory(directory_name)
|
55
59
|
Dir[File.join(File.dirname(__FILE__), directory_name, '*')].each do |f|
|
56
60
|
require f
|
@@ -103,6 +107,13 @@ def rebuild_class options = {}
|
|
103
107
|
end
|
104
108
|
end
|
105
109
|
|
110
|
+
def rebuild_meta_class_of obj, options = {}
|
111
|
+
(class << obj; self; end).tap do |metaklass|
|
112
|
+
metaklass.has_attached_file :avatar, options
|
113
|
+
Paperclip.reset_duplicate_clash_check!
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
106
117
|
class FakeModel
|
107
118
|
attr_accessor :avatar_file_name,
|
108
119
|
:avatar_file_size,
|
@@ -117,6 +128,10 @@ class FakeModel
|
|
117
128
|
|
118
129
|
def run_paperclip_callbacks name, *args
|
119
130
|
end
|
131
|
+
|
132
|
+
def valid?
|
133
|
+
errors.empty?
|
134
|
+
end
|
120
135
|
end
|
121
136
|
|
122
137
|
def attachment(options={})
|
@@ -161,7 +176,7 @@ def with_exitstatus_returning(code)
|
|
161
176
|
end
|
162
177
|
|
163
178
|
def fixture_file(filename)
|
164
|
-
|
179
|
+
File.join(File.dirname(__FILE__), 'fixtures', filename)
|
165
180
|
end
|
166
181
|
|
167
182
|
def assert_success_response(url)
|
@@ -177,3 +192,19 @@ def assert_not_found_response(url)
|
|
177
192
|
"Expected HTTP response code 404, got #{response.code}"
|
178
193
|
end
|
179
194
|
end
|
195
|
+
|
196
|
+
def assert_file_exists(path)
|
197
|
+
assert File.exists?(path), %(Expect "#{path}" to be exists.)
|
198
|
+
end
|
199
|
+
|
200
|
+
def assert_file_not_exists(path)
|
201
|
+
assert !File.exists?(path), %(Expect "#{path}" to not exists.)
|
202
|
+
end
|
203
|
+
|
204
|
+
def assert_frame_dimensions(range, frames)
|
205
|
+
frames.each_with_index do |frame, frame_index|
|
206
|
+
frame.split('x').each_with_index do |dimension, dimension_index |
|
207
|
+
assert range.include?(dimension.to_i), "Frame #{frame_index}[#{dimension_index}] should have been within #{range.inspect}, but was #{dimension}"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|