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.

Files changed (121) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +2 -1
  3. data/.travis.yml +3 -0
  4. data/Appraisals +8 -3
  5. data/Gemfile +1 -1
  6. data/LICENSE +1 -1
  7. data/NEWS +198 -35
  8. data/README.md +332 -113
  9. data/features/basic_integration.feature +24 -12
  10. data/features/migration.feature +94 -0
  11. data/features/rake_tasks.feature +2 -3
  12. data/features/step_definitions/attachment_steps.rb +28 -0
  13. data/features/step_definitions/rails_steps.rb +94 -8
  14. data/features/step_definitions/s3_steps.rb +1 -1
  15. data/features/step_definitions/web_steps.rb +3 -3
  16. data/features/support/fakeweb.rb +4 -1
  17. data/features/support/file_helpers.rb +10 -0
  18. data/features/support/rails.rb +18 -2
  19. data/gemfiles/3.0.gemfile +2 -2
  20. data/gemfiles/3.1.gemfile +2 -2
  21. data/gemfiles/3.2.gemfile +2 -2
  22. data/gemfiles/4.0.gemfile +11 -0
  23. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +4 -8
  24. data/lib/paperclip/attachment.rb +96 -43
  25. data/lib/paperclip/attachment_registry.rb +57 -0
  26. data/lib/paperclip/callbacks.rb +2 -2
  27. data/lib/paperclip/content_type_detector.rb +78 -0
  28. data/lib/paperclip/file_command_content_type_detector.rb +32 -0
  29. data/lib/paperclip/filename_cleaner.rb +16 -0
  30. data/lib/paperclip/geometry.rb +66 -30
  31. data/lib/paperclip/geometry_detector_factory.rb +41 -0
  32. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  33. data/lib/paperclip/glue.rb +2 -8
  34. data/lib/paperclip/has_attached_file.rb +99 -0
  35. data/lib/paperclip/helpers.rb +12 -15
  36. data/lib/paperclip/interpolations/plural_cache.rb +17 -0
  37. data/lib/paperclip/interpolations.rb +15 -5
  38. data/lib/paperclip/io_adapters/abstract_adapter.rb +45 -0
  39. data/lib/paperclip/io_adapters/attachment_adapter.rb +14 -49
  40. data/lib/paperclip/io_adapters/data_uri_adapter.rb +27 -0
  41. data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
  42. data/lib/paperclip/io_adapters/file_adapter.rb +8 -69
  43. data/lib/paperclip/io_adapters/identity_adapter.rb +1 -1
  44. data/lib/paperclip/io_adapters/nil_adapter.rb +2 -2
  45. data/lib/paperclip/io_adapters/stringio_adapter.rb +16 -45
  46. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +17 -40
  47. data/lib/paperclip/io_adapters/uri_adapter.rb +44 -0
  48. data/lib/paperclip/matchers/have_attached_file_matcher.rb +1 -5
  49. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +36 -17
  50. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +5 -1
  51. data/lib/paperclip/matchers.rb +3 -3
  52. data/lib/paperclip/missing_attachment_styles.rb +11 -16
  53. data/lib/paperclip/processor.rb +12 -0
  54. data/lib/paperclip/railtie.rb +5 -1
  55. data/lib/paperclip/schema.rb +59 -23
  56. data/lib/paperclip/storage/filesystem.rb +23 -5
  57. data/lib/paperclip/storage/fog.rb +64 -25
  58. data/lib/paperclip/storage/s3.rb +93 -52
  59. data/lib/paperclip/style.rb +2 -2
  60. data/lib/paperclip/tempfile_factory.rb +21 -0
  61. data/lib/paperclip/thumbnail.rb +18 -3
  62. data/lib/paperclip/validators/attachment_content_type_validator.rb +38 -10
  63. data/lib/paperclip/validators/attachment_presence_validator.rb +8 -8
  64. data/lib/paperclip/validators/attachment_size_validator.rb +12 -7
  65. data/lib/paperclip/validators.rb +21 -2
  66. data/lib/paperclip/version.rb +1 -1
  67. data/lib/paperclip.rb +15 -44
  68. data/lib/tasks/paperclip.rake +26 -7
  69. data/paperclip.gemspec +11 -7
  70. data/test/attachment_definitions_test.rb +12 -0
  71. data/test/attachment_processing_test.rb +83 -0
  72. data/test/attachment_registry_test.rb +77 -0
  73. data/test/attachment_test.rb +253 -44
  74. data/test/content_type_detector_test.rb +50 -0
  75. data/test/file_command_content_type_detector_test.rb +25 -0
  76. data/test/filename_cleaner_test.rb +14 -0
  77. data/test/fixtures/animated +0 -0
  78. data/test/fixtures/animated.unknown +0 -0
  79. data/test/fixtures/rotated.jpg +0 -0
  80. data/test/generator_test.rb +26 -24
  81. data/test/geometry_detector_test.rb +24 -0
  82. data/test/geometry_parser_test.rb +73 -0
  83. data/test/geometry_test.rb +55 -4
  84. data/test/has_attached_file_test.rb +125 -0
  85. data/test/helper.rb +38 -7
  86. data/test/integration_test.rb +105 -89
  87. data/test/interpolations_test.rb +12 -0
  88. data/test/io_adapters/abstract_adapter_test.rb +58 -0
  89. data/test/io_adapters/attachment_adapter_test.rb +120 -33
  90. data/test/io_adapters/data_uri_adapter_test.rb +60 -0
  91. data/test/io_adapters/empty_string_adapter_test.rb +17 -0
  92. data/test/io_adapters/file_adapter_test.rb +32 -1
  93. data/test/io_adapters/stringio_adapter_test.rb +29 -10
  94. data/test/io_adapters/uploaded_file_adapter_test.rb +53 -5
  95. data/test/io_adapters/uri_adapter_test.rb +102 -0
  96. data/test/matchers/validate_attachment_presence_matcher_test.rb +22 -0
  97. data/test/meta_class_test.rb +32 -0
  98. data/test/paperclip_missing_attachment_styles_test.rb +4 -8
  99. data/test/paperclip_test.rb +27 -51
  100. data/test/plural_cache_test.rb +36 -0
  101. data/test/processor_test.rb +16 -0
  102. data/test/rake_test.rb +103 -0
  103. data/test/schema_test.rb +179 -77
  104. data/test/storage/filesystem_test.rb +26 -3
  105. data/test/storage/fog_test.rb +181 -3
  106. data/test/storage/s3_test.rb +239 -4
  107. data/test/style_test.rb +18 -14
  108. data/test/tempfile_factory_test.rb +13 -0
  109. data/test/thumbnail_test.rb +96 -16
  110. data/test/validators/attachment_content_type_validator_test.rb +181 -55
  111. data/test/validators/attachment_size_validator_test.rb +10 -0
  112. data/test/validators_test.rb +8 -1
  113. metadata +126 -92
  114. data/Gemfile.lock +0 -157
  115. data/features/support/fixtures/.boot_config.rb.swo +0 -0
  116. data/images.rake +0 -21
  117. data/lib/.DS_Store +0 -0
  118. data/lib/paperclip/.DS_Store +0 -0
  119. data/lib/paperclip/attachment_options.rb +0 -9
  120. data/lib/paperclip/instance_methods.rb +0 -35
  121. 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
@@ -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
- assert @geo.height > 0
108
- assert @geo.width > 0
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
- assert @geo.height > 0
115
- assert @geo.width > 0
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 = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
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
- File.join(File.dirname(__FILE__), 'fixtures', filename)
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