paperclip 5.2.1 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +5 -5
  2. data/.github/issue_template.md +3 -0
  3. data/MIGRATING-ES.md +317 -0
  4. data/MIGRATING.md +375 -0
  5. data/NEWS +36 -0
  6. data/README.md +52 -18
  7. data/UPGRADING +3 -3
  8. data/features/step_definitions/attachment_steps.rb +10 -10
  9. data/features/step_definitions/rails_steps.rb +1 -1
  10. data/lib/generators/paperclip/paperclip_generator.rb +9 -1
  11. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +1 -1
  12. data/lib/paperclip/attachment.rb +19 -6
  13. data/lib/paperclip/file_command_content_type_detector.rb +1 -1
  14. data/lib/paperclip/filename_cleaner.rb +0 -1
  15. data/lib/paperclip/geometry_detector_factory.rb +3 -3
  16. data/lib/paperclip/helpers.rb +3 -3
  17. data/lib/paperclip/interpolations.rb +6 -1
  18. data/lib/paperclip/io_adapters/abstract_adapter.rb +11 -6
  19. data/lib/paperclip/io_adapters/attachment_adapter.rb +7 -1
  20. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +2 -1
  21. data/lib/paperclip/io_adapters/uri_adapter.rb +8 -6
  22. data/lib/paperclip/logger.rb +1 -1
  23. data/lib/paperclip/media_type_spoof_detector.rb +11 -7
  24. data/lib/paperclip/processor.rb +10 -2
  25. data/lib/paperclip/schema.rb +1 -1
  26. data/lib/paperclip/storage/fog.rb +3 -2
  27. data/lib/paperclip/storage/s3.rb +8 -16
  28. data/lib/paperclip/style.rb +0 -1
  29. data/lib/paperclip/thumbnail.rb +8 -5
  30. data/lib/paperclip/url_generator.rb +1 -0
  31. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +4 -0
  32. data/lib/paperclip/version.rb +1 -1
  33. data/lib/paperclip.rb +2 -1
  34. data/paperclip.gemspec +2 -2
  35. data/spec/paperclip/attachment_processing_spec.rb +0 -1
  36. data/spec/paperclip/attachment_spec.rb +17 -2
  37. data/spec/paperclip/content_type_detector_spec.rb +1 -1
  38. data/spec/paperclip/file_command_content_type_detector_spec.rb +15 -1
  39. data/spec/paperclip/filename_cleaner_spec.rb +0 -1
  40. data/spec/paperclip/integration_spec.rb +41 -5
  41. data/spec/paperclip/interpolations_spec.rb +9 -0
  42. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +59 -0
  43. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +33 -16
  44. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +56 -8
  45. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +1 -1
  46. data/spec/paperclip/media_type_spoof_detector_spec.rb +41 -0
  47. data/spec/paperclip/paperclip_spec.rb +13 -13
  48. data/spec/paperclip/processor_spec.rb +4 -4
  49. data/spec/paperclip/schema_spec.rb +46 -46
  50. data/spec/paperclip/storage/fog_spec.rb +5 -0
  51. data/spec/paperclip/storage/s3_spec.rb +6 -6
  52. data/spec/paperclip/style_spec.rb +0 -1
  53. data/spec/paperclip/thumbnail_spec.rb +8 -6
  54. data/spec/paperclip/url_generator_spec.rb +0 -1
  55. data/spec/spec_helper.rb +0 -1
  56. data/spec/support/model_reconstruction.rb +2 -2
  57. metadata +120 -20
  58. data/spec/support/conditional_filter_helper.rb +0 -5
@@ -19,7 +19,7 @@ module Paperclip
19
19
  # store your files. Remember that the bucket must be unique across
20
20
  # all of Amazon S3. If the bucket does not exist, Paperclip will
21
21
  # attempt to create it.
22
- # * +fog_file*: This can be hash or lambda returning hash. The
22
+ # * +fog_file+: This can be hash or lambda returning hash. The
23
23
  # value is used as base properties for new uploaded file.
24
24
  # * +path+: This is the key under the bucket in which the file will
25
25
  # be stored. The URL will be constructed from the bucket and the
@@ -117,6 +117,7 @@ module Paperclip
117
117
  raise if retried
118
118
  retried = true
119
119
  directory.save
120
+ file.rewind
120
121
  retry
121
122
  ensure
122
123
  file.rewind
@@ -184,7 +185,7 @@ module Paperclip
184
185
  private
185
186
 
186
187
  def convert_time(time)
187
- if time.is_a?(Fixnum)
188
+ if time.is_a?(Integer)
188
189
  time = Time.now + time
189
190
  end
190
191
  time
@@ -3,8 +3,8 @@ module Paperclip
3
3
  # Amazon's S3 file hosting service is a scalable, easy place to store files for
4
4
  # distribution. You can find out more about it at http://aws.amazon.com/s3
5
5
  #
6
- # To use Paperclip with S3, include the +aws-sdk+ gem in your Gemfile:
7
- # gem 'aws-sdk'
6
+ # To use Paperclip with S3, include the +aws-sdk-s3+ gem in your Gemfile:
7
+ # gem 'aws-sdk-s3'
8
8
  # There are a few S3-specific options for has_attached_file:
9
9
  # * +s3_credentials+: Takes a path, a File, a Hash or a Proc. The path (or File) must point
10
10
  # to a YAML file containing the +access_key_id+ and +secret_access_key+ that Amazon
@@ -94,8 +94,9 @@ module Paperclip
94
94
  # to interpolate. Keys should be unique, like filenames, and despite the fact that
95
95
  # S3 (strictly speaking) does not support directories, you can still use a / to
96
96
  # separate parts of your file name.
97
- # * +s3_host_name+: If you are using your bucket in Tokyo region etc, write host_name.
98
- # * +s3_region+: For aws-sdk v2, s3_region is required.
97
+ # * +s3_host_name+: If you are using your bucket in Tokyo region
98
+ # etc, write host_name (e.g., 's3-ap-northeast-1.amazonaws.com').
99
+ # * +s3_region+: For aws-sdk-s3, s3_region is required.
99
100
  # * +s3_metadata+: These key/value pairs will be stored with the
100
101
  # object. This option works by prefixing each key with
101
102
  # "x-amz-meta-" before sending it as a header on the object
@@ -117,20 +118,16 @@ module Paperclip
117
118
  # :s3_storage_class => :REDUCED_REDUNDANCY
118
119
  #
119
120
  # Other storage classes, such as <tt>:STANDARD_IA</tt>, are also available—see the
120
- # documentation for the <tt>aws-sdk</tt> gem for the full list.
121
+ # documentation for the <tt>aws-sdk-s3</tt> gem for the full list.
121
122
 
122
123
  module S3
123
124
  def self.extended base
124
125
  begin
125
- require 'aws-sdk'
126
+ require "aws-sdk-s3"
126
127
  rescue LoadError => e
127
- e.message << " (You may need to install the aws-sdk gem)"
128
+ e.message << " (You may need to install the aws-sdk-s3 gem)"
128
129
  raise e
129
130
  end
130
- if Gem::Version.new(Aws::VERSION) >= Gem::Version.new(2) &&
131
- Gem::Version.new(Aws::VERSION) <= Gem::Version.new("2.0.33")
132
- raise LoadError, "paperclip does not support aws-sdk versions 2.0.0 - 2.0.33. Please upgrade aws-sdk to a newer version."
133
- end
134
131
 
135
132
  base.instance_eval do
136
133
  @s3_options = @options[:s3_options] || {}
@@ -158,11 +155,6 @@ module Paperclip
158
155
 
159
156
  @http_proxy = @options[:http_proxy] || nil
160
157
 
161
- if @options.has_key?(:use_accelerate_endpoint) &&
162
- Gem::Version.new(Aws::VERSION) < Gem::Version.new("2.3.0")
163
- raise LoadError, ":use_accelerate_endpoint is only available from aws-sdk version 2.3.0. Please upgrade aws-sdk to a newer version."
164
- end
165
-
166
158
  @use_accelerate_endpoint = @options[:use_accelerate_endpoint]
167
159
  end
168
160
 
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  module Paperclip
3
2
  # The Style class holds the definition of a thumbnail style, applying
4
3
  # whatever processing is required to normalize the definition and delaying
@@ -84,9 +84,12 @@ module Paperclip
84
84
  source: "#{File.expand_path(src.path)}#{frame}",
85
85
  dest: File.expand_path(dst.path),
86
86
  )
87
- rescue Cocaine::ExitStatusError => e
88
- raise Paperclip::Error, "There was an error processing the thumbnail for #{@basename}" if @whiny
89
- rescue Cocaine::CommandNotFoundError => e
87
+ rescue Terrapin::ExitStatusError => e
88
+ if @whiny
89
+ message = "There was an error processing the thumbnail for #{@basename}:\n" + e.message
90
+ raise Paperclip::Error, message
91
+ end
92
+ rescue Terrapin::CommandNotFoundError => e
90
93
  raise Paperclip::Errors::CommandNotFoundError.new("Could not run the `convert` command. Please install ImageMagick.")
91
94
  end
92
95
 
@@ -122,9 +125,9 @@ module Paperclip
122
125
  @identified_as_animated = ANIMATED_FORMATS.include? identify("-format %m :file", :file => "#{@file.path}[0]").to_s.downcase.strip
123
126
  end
124
127
  @identified_as_animated
125
- rescue Cocaine::ExitStatusError => e
128
+ rescue Terrapin::ExitStatusError => e
126
129
  raise Paperclip::Error, "There was an error running `identify` for #{@basename}" if @whiny
127
- rescue Cocaine::CommandNotFoundError => e
130
+ rescue Terrapin::CommandNotFoundError => e
128
131
  raise Paperclip::Errors::CommandNotFoundError.new("Could not run the `identify` command. Please install ImageMagick.")
129
132
  end
130
133
  end
@@ -1,4 +1,5 @@
1
1
  require 'uri'
2
+ require 'active_support/core_ext/module/delegation'
2
3
 
3
4
  module Paperclip
4
5
  class UrlGenerator
@@ -8,6 +8,10 @@ module Paperclip
8
8
  if Paperclip::MediaTypeSpoofDetector.using(adapter, value.original_filename, value.content_type).spoofed?
9
9
  record.errors.add(attribute, :spoofed_media_type)
10
10
  end
11
+
12
+ if adapter.tempfile
13
+ adapter.tempfile.close(true)
14
+ end
11
15
  end
12
16
  end
13
17
 
@@ -1,5 +1,5 @@
1
1
  module Paperclip
2
2
  unless defined?(Paperclip::VERSION)
3
- VERSION = "5.2.1".freeze
3
+ VERSION = "6.1.0".freeze
4
4
  end
5
5
  end
data/lib/paperclip.rb CHANGED
@@ -67,7 +67,7 @@ end
67
67
  require 'mimemagic'
68
68
  require 'mimemagic/overlay'
69
69
  require 'logger'
70
- require 'cocaine'
70
+ require 'terrapin'
71
71
 
72
72
  require 'paperclip/railtie' if defined?(Rails::Railtie)
73
73
 
@@ -98,6 +98,7 @@ module Paperclip
98
98
  swallow_stderr: true,
99
99
  use_exif_orientation: true,
100
100
  whiny: true,
101
+ is_windows: Gem.win_platform?
101
102
  }
102
103
  end
103
104
 
data/paperclip.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
 
27
27
  s.add_dependency('activemodel', '>= 4.2.0')
28
28
  s.add_dependency('activesupport', '>= 4.2.0')
29
- s.add_dependency('cocaine', '~> 0.5.5')
29
+ s.add_dependency('terrapin', '~> 0.6.0')
30
30
  s.add_dependency('mime-types')
31
31
  s.add_dependency('mimemagic', '~> 0.3.0')
32
32
 
@@ -35,7 +35,7 @@ Gem::Specification.new do |s|
35
35
  s.add_development_dependency('rspec', '~> 3.0')
36
36
  s.add_development_dependency('appraisal')
37
37
  s.add_development_dependency('mocha')
38
- s.add_development_dependency('aws-sdk', '>= 2.3.0', '< 3.0')
38
+ s.add_development_dependency('aws-sdk-s3')
39
39
  s.add_development_dependency('bourne')
40
40
  s.add_development_dependency('cucumber-rails')
41
41
  s.add_development_dependency('cucumber-expressions', '4.0.3') # TODO: investigate failures on 4.0.4
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe 'Attachment Processing' do
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe Paperclip::Attachment do
@@ -54,6 +53,22 @@ describe Paperclip::Attachment do
54
53
  expect(dummy.avatar.path(:original)).to exist
55
54
  end
56
55
 
56
+ it "reprocess works with virtual content_type attribute" do
57
+ rebuild_class styles: { small: "100x>" }
58
+ modify_table { |t| t.remove :avatar_content_type }
59
+ Dummy.send :attr_accessor, :avatar_content_type
60
+ Dummy.validates_attachment_content_type(
61
+ :avatar,
62
+ content_type: %w(image/jpeg image/png)
63
+ )
64
+ Dummy.create!(avatar: File.new(fixture_file("50x50.png"), "rb"))
65
+
66
+ dummy = Dummy.first
67
+ dummy.avatar.reprocess!(:small)
68
+
69
+ expect(dummy.avatar.path(:small)).to exist
70
+ end
71
+
57
72
  context "having a not empty hash as a default option" do
58
73
  before do
59
74
  @old_default_options = Paperclip::Attachment.default_options.dup
@@ -1401,7 +1416,7 @@ describe Paperclip::Attachment do
1401
1416
 
1402
1417
  context "and avatar_file_size column" do
1403
1418
  before do
1404
- ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :integer
1419
+ ActiveRecord::Base.connection.add_column :dummies, :avatar_file_size, :bigint
1405
1420
  rebuild_class
1406
1421
  @dummy = Dummy.new
1407
1422
  end
@@ -41,7 +41,7 @@ describe Paperclip::ContentTypeDetector do
41
41
  end
42
42
 
43
43
  it 'returns a sensible default when the file command is missing' do
44
- Paperclip.stubs(:run).raises(Cocaine::CommandLineError.new)
44
+ Paperclip.stubs(:run).raises(Terrapin::CommandLineError.new)
45
45
  @filename = "/path/to/something"
46
46
  assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new(@filename).detect
47
47
  end
@@ -12,7 +12,7 @@ describe Paperclip::FileCommandContentTypeDetector do
12
12
  end
13
13
 
14
14
  it 'returns a sensible default when the file command is missing' do
15
- Paperclip.stubs(:run).raises(Cocaine::CommandLineError.new)
15
+ Paperclip.stubs(:run).raises(Terrapin::CommandLineError.new)
16
16
  @filename = "/path/to/something"
17
17
  assert_equal "application/octet-stream",
18
18
  Paperclip::FileCommandContentTypeDetector.new(@filename).detect
@@ -23,4 +23,18 @@ describe Paperclip::FileCommandContentTypeDetector do
23
23
  assert_equal "application/octet-stream",
24
24
  Paperclip::FileCommandContentTypeDetector.new("windows").detect
25
25
  end
26
+
27
+ context "#type_from_file_command" do
28
+ let(:detector) { Paperclip::FileCommandContentTypeDetector.new("html") }
29
+
30
+ it "does work with the output of old versions of file" do
31
+ Paperclip.stubs(:run).returns("text/html charset=us-ascii")
32
+ expect(detector.detect).to eq("text/html")
33
+ end
34
+
35
+ it "does work with the output of new versions of file" do
36
+ Paperclip.stubs(:run).returns("text/html; charset=us-ascii")
37
+ expect(detector.detect).to eq("text/html")
38
+ end
39
+ end
26
40
  end
@@ -1,4 +1,3 @@
1
- # encoding: utf-8
2
1
  require 'spec_helper'
3
2
 
4
3
  describe Paperclip::FilenameCleaner do
@@ -1,16 +1,33 @@
1
- # encoding: utf-8
2
1
  require 'spec_helper'
3
2
  require 'open-uri'
4
3
 
5
4
  describe 'Paperclip' do
5
+ around do |example|
6
+ files_before = ObjectSpace.each_object(Tempfile).select do |file|
7
+ file.path && File.file?(file.path)
8
+ end
9
+
10
+ example.run
11
+
12
+ files_after = ObjectSpace.each_object(Tempfile).select do |file|
13
+ file.path && File.file?(file.path)
14
+ end
15
+
16
+ diff = files_after - files_before
17
+ expect(diff).to eq([]), "Leaked tempfiles: #{diff.inspect}"
18
+ end
19
+
6
20
  context "Many models at once" do
7
21
  before do
8
22
  rebuild_model
9
23
  @file = File.new(fixture_file("5k.png"), 'rb')
10
24
  # Deals with `Too many open files` error
11
- Dummy.import 100.times.map { Dummy.new avatar: @file }
12
- Dummy.import 100.times.map { Dummy.new avatar: @file }
13
- Dummy.import 100.times.map { Dummy.new avatar: @file }
25
+ dummies = Array.new(300) { Dummy.new avatar: @file }
26
+ Dummy.import dummies
27
+ # save attachment instances to run after hooks including tempfile cleanup
28
+ # since activerecord-import does not use our usually hooked-in hooks
29
+ # (such as after_save)
30
+ dummies.each { |dummy| dummy.avatar.save }
14
31
  end
15
32
 
16
33
  after { @file.close }
@@ -135,6 +152,14 @@ describe 'Paperclip' do
135
152
  end
136
153
 
137
154
  it "allows us to selectively create each thumbnail" do
155
+ skip <<-EXPLANATION
156
+ #reprocess! calls #assign which calls Paperclip.io_adapters.for
157
+ which creates the tempfile. #assign then calls #post_process_file which
158
+ calls MediaTypeSpoofDetectionValidator#validate_each which calls
159
+ Paperclip.io_adapters.for, which creates another tempfile. That first
160
+ tempfile is the one that leaks.
161
+ EXPLANATION
162
+
138
163
  assert_file_not_exists(@thumb_small_path)
139
164
  assert_file_not_exists(@thumb_large_path)
140
165
 
@@ -159,7 +184,11 @@ describe 'Paperclip' do
159
184
  assert_not_equal File.size(@file.path), @dummy.avatar.size
160
185
  end
161
186
 
162
- after { @file.close }
187
+ after do
188
+ @file.close
189
+ # save attachment instance to run after hooks (including tempfile cleanup)
190
+ @dummy.avatar.save
191
+ end
163
192
  end
164
193
 
165
194
  context "A model with attachments scoped under an id" do
@@ -347,6 +376,8 @@ describe 'Paperclip' do
347
376
  it "is not ok with bad files" do
348
377
  @dummy.avatar = @bad_file
349
378
  assert ! @dummy.valid?
379
+ # save attachment instance to run after hooks (including tempfile cleanup)
380
+ @dummy.avatar.save
350
381
  end
351
382
 
352
383
  it "knows the difference between good files, bad files, and not files when validating" do
@@ -354,8 +385,13 @@ describe 'Paperclip' do
354
385
  @d2 = Dummy.find(@dummy.id)
355
386
  @d2.avatar = @file
356
387
  assert @d2.valid?, @d2.errors.full_messages.inspect
388
+ # save attachment instance to run after hooks (including tempfile cleanup)
389
+ @d2.avatar.save
390
+
357
391
  @d2.avatar = @bad_file
358
392
  assert ! @d2.valid?
393
+ # save attachment instance to run after hooks (including tempfile cleanup)
394
+ @d2.avatar.save
359
395
  end
360
396
 
361
397
  it "is able to reload without saving and not have the file disappear" do
@@ -139,6 +139,15 @@ describe Paperclip::Interpolations do
139
139
  assert_equal "000/000/023", Paperclip::Interpolations.id_partition(attachment, :style)
140
140
  end
141
141
 
142
+ it "returns the partitioned id when the id is above 999_999_999" do
143
+ attachment = mock
144
+ attachment.expects(:id).
145
+ returns(Paperclip::Interpolations::ID_PARTITION_LIMIT)
146
+ attachment.expects(:instance).returns(attachment)
147
+ assert_equal "001/000/000/000",
148
+ Paperclip::Interpolations.id_partition(attachment, :style)
149
+ end
150
+
142
151
  it "returns the partitioned id of the attachment when the id is a string" do
143
152
  attachment = mock
144
153
  attachment.expects(:id).returns("32fnj23oio2f")
@@ -93,9 +93,68 @@ describe Paperclip::AbstractAdapter do
93
93
  end
94
94
  end
95
95
 
96
+ context "#copy_to_tempfile" do
97
+ around do |example|
98
+ FileUtils.module_eval do
99
+ class << self
100
+ alias paperclip_ln ln
101
+
102
+ def ln(*)
103
+ raise Errno::EXDEV
104
+ end
105
+ end
106
+ end
107
+
108
+ example.run
109
+
110
+ FileUtils.module_eval do
111
+ class << self
112
+ alias ln paperclip_ln
113
+ undef paperclip_ln
114
+ end
115
+ end
116
+ end
117
+
118
+ it "should return a readable file even when linking fails" do
119
+ src = open(fixture_file("5k.png"), "rb")
120
+ expect(subject.send(:copy_to_tempfile, src).read).to eq src.read
121
+ end
122
+ end
123
+
96
124
  context "#original_filename=" do
97
125
  it "should not fail with a nil original filename" do
98
126
  expect { subject.original_filename = nil }.not_to raise_error
99
127
  end
100
128
  end
129
+
130
+ context "#link_or_copy_file" do
131
+ class TestLinkOrCopyAdapter < Paperclip::AbstractAdapter
132
+ public :copy_to_tempfile, :destination
133
+ end
134
+
135
+ subject { TestLinkOrCopyAdapter.new(nil) }
136
+ let(:body) { "body" }
137
+
138
+ let(:file) do
139
+ t = Tempfile.new("destination")
140
+ t.print(body)
141
+ t.rewind
142
+ t
143
+ end
144
+
145
+ after do
146
+ file.close
147
+ file.unlink
148
+ end
149
+
150
+ it "should be able to read the file" do
151
+ expect(subject.copy_to_tempfile(file).read).to eq(body)
152
+ end
153
+
154
+ it "should be able to reopen the file after symlink has failed" do
155
+ FileUtils.expects(:ln).raises(Errno::EXDEV)
156
+
157
+ expect(subject.copy_to_tempfile(file).read).to eq(body)
158
+ end
159
+ end
101
160
  end
@@ -3,10 +3,9 @@ require 'spec_helper'
3
3
  describe Paperclip::HttpUrlProxyAdapter do
4
4
  before do
5
5
  @open_return = StringIO.new("xxx")
6
- @open_return.stubs(:content_type).returns("image/png")
7
- @open_return.stubs(:meta).returns({})
8
- Paperclip::HttpUrlProxyAdapter.any_instance.
9
- stubs(:download_content).returns(@open_return)
6
+ @open_return.stubs(:meta).returns("content-type" => "image/png")
7
+ Paperclip::HttpUrlProxyAdapter.any_instance.stubs(:download_content).
8
+ returns(@open_return)
10
9
  Paperclip::HttpUrlProxyAdapter.register
11
10
  end
12
11
 
@@ -69,17 +68,18 @@ describe Paperclip::HttpUrlProxyAdapter do
69
68
  end
70
69
 
71
70
  context "a url with query params" do
72
- before do
73
- @url = "https://github.com/thoughtbot/paperclip?file=test"
74
- @subject = Paperclip.io_adapters.for(@url)
75
- end
71
+ subject { Paperclip.io_adapters.for(url) }
76
72
 
77
- after do
78
- @subject.close
79
- end
73
+ after { subject.close }
74
+
75
+ let(:url) { "https://github.com/thoughtbot/paperclip?file=test" }
80
76
 
81
77
  it "returns a file name" do
82
- assert_equal "paperclip", @subject.original_filename
78
+ assert_equal "paperclip", subject.original_filename
79
+ end
80
+
81
+ it "preserves params" do
82
+ assert_equal url, subject.instance_variable_get(:@target).to_s
83
83
  end
84
84
  end
85
85
 
@@ -107,15 +107,32 @@ describe Paperclip::HttpUrlProxyAdapter do
107
107
  end
108
108
 
109
109
  context "a url with special characters in the filename" do
110
- it "returns a encoded filename" do
110
+ before do
111
111
  Paperclip::HttpUrlProxyAdapter.any_instance.stubs(:download_content).
112
112
  returns(@open_return)
113
- url = "https://github.com/thoughtbot/paperclip-öäü字´½♥زÈ.png"
114
- subject = Paperclip.io_adapters.for(url)
115
- filename = "paperclip-%C3%B6%C3%A4%C3%BC%E5%AD%97%C2%B4%C2%BD%E2%99%A5"\
113
+ end
114
+
115
+ let(:filename) do
116
+ "paperclip-%C3%B6%C3%A4%C3%BC%E5%AD%97%C2%B4%C2%BD%E2%99%A5"\
116
117
  "%C3%98%C2%B2%C3%88.png"
118
+ end
119
+ let(:url) { "https://github.com/thoughtbot/paperclip-öäü字´½♥زÈ.png" }
117
120
 
121
+ subject { Paperclip.io_adapters.for(url) }
122
+
123
+ it "returns a encoded filename" do
118
124
  assert_equal filename, subject.original_filename
119
125
  end
126
+
127
+ context "when already URI encoded" do
128
+ let(:url) do
129
+ "https://github.com/thoughtbot/paperclip-%C3%B6%C3%A4%C3%BC%E5%AD%97"\
130
+ "%C2%B4%C2%BD%E2%99%A5%C3%98%C2%B2%C3%88.png"
131
+ end
132
+
133
+ it "returns a encoded filename" do
134
+ assert_equal filename, subject.original_filename
135
+ end
136
+ end
120
137
  end
121
138
  end
@@ -16,6 +16,8 @@ describe Paperclip::UriAdapter do
16
16
  end
17
17
 
18
18
  context "a new instance" do
19
+ let(:meta) { { "content-type" => "image/png" } }
20
+
19
21
  before do
20
22
  Paperclip::UriAdapter.any_instance.
21
23
  stubs(:download_content).returns(@open_return)
@@ -62,7 +64,7 @@ describe Paperclip::UriAdapter do
62
64
  assert_equal 'image/png', @subject.content_type
63
65
  end
64
66
 
65
- it 'accepts an orgiginal_filename' do
67
+ it "accepts an original_filename" do
66
68
  @subject.original_filename = 'image.png'
67
69
  assert_equal 'image.png', @subject.original_filename
68
70
  end
@@ -71,6 +73,7 @@ describe Paperclip::UriAdapter do
71
73
 
72
74
  context "a directory index url" do
73
75
  let(:content_type) { "text/html" }
76
+ let(:meta) { { "content-type" => "text/html" } }
74
77
 
75
78
  before do
76
79
  Paperclip::UriAdapter.any_instance.
@@ -105,23 +108,68 @@ describe Paperclip::UriAdapter do
105
108
 
106
109
  context "a url with content disposition headers" do
107
110
  let(:file_name) { "test_document.pdf" }
108
- let(:meta) do
109
- {
110
- "content-disposition" => "attachment; filename=\"#{file_name}\";",
111
- }
112
- end
111
+ let(:filename_from_path) { "paperclip" }
113
112
 
114
113
  before do
115
114
  Paperclip::UriAdapter.any_instance.
116
115
  stubs(:download_content).returns(@open_return)
117
116
 
118
- @uri = URI.parse("https://github.com/thoughtbot/paperclip?file=test")
117
+ @uri = URI.parse(
118
+ "https://github.com/thoughtbot/#{filename_from_path}?file=test")
119
+ end
120
+
121
+ it "returns file name from path" do
122
+ meta["content-disposition"] = "inline;"
123
+
119
124
  @subject = Paperclip.io_adapters.for(@uri)
125
+
126
+ assert_equal filename_from_path, @subject.original_filename
120
127
  end
121
128
 
122
- it "returns a file name" do
129
+ it "returns a file name enclosed in double quotes" do
130
+ file_name = "john's test document.pdf"
131
+ meta["content-disposition"] = "attachment; filename=\"#{file_name}\";"
132
+
133
+ @subject = Paperclip.io_adapters.for(@uri)
134
+
135
+ assert_equal file_name, @subject.original_filename
136
+ end
137
+
138
+ it "returns a file name not enclosed in double quotes" do
139
+ meta["content-disposition"] = "ATTACHMENT; FILENAME=#{file_name};"
140
+
141
+ @subject = Paperclip.io_adapters.for(@uri)
142
+
143
+ assert_equal file_name, @subject.original_filename
144
+ end
145
+
146
+ it "does not crash when an empty filename is given" do
147
+ meta["content-disposition"] = "ATTACHMENT; FILENAME=\"\";"
148
+
149
+ @subject = Paperclip.io_adapters.for(@uri)
150
+
151
+ assert_equal "", @subject.original_filename
152
+ end
153
+
154
+ it "returns a file name ignoring RFC 5987 encoding" do
155
+ meta["content-disposition"] =
156
+ "attachment; filename=#{file_name}; filename* = utf-8''%e2%82%ac%20rates"
157
+
158
+ @subject = Paperclip.io_adapters.for(@uri)
159
+
123
160
  assert_equal file_name, @subject.original_filename
124
161
  end
162
+
163
+ context "when file name has consecutive periods" do
164
+ let(:file_name) { "test_document..pdf" }
165
+
166
+ it "returns a file name" do
167
+ @uri = URI.parse(
168
+ "https://github.com/thoughtbot/#{file_name}?file=test")
169
+ @subject = Paperclip.io_adapters.for(@uri)
170
+ assert_equal file_name, @subject.original_filename
171
+ end
172
+ end
125
173
  end
126
174
 
127
175
  context "a url with restricted characters in the filename" do
@@ -7,7 +7,7 @@ describe Paperclip::Shoulda::Matchers::ValidateAttachmentSizeMatcher do
7
7
  before do
8
8
  reset_table("dummies") do |d|
9
9
  d.string :avatar_file_name
10
- d.integer :avatar_file_size
10
+ d.bigint :avatar_file_size
11
11
  end
12
12
  reset_class "Dummy"
13
13
  Dummy.do_not_validate_attachment_file_type :avatar