kt-paperclip 4.4.0 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -0
  3. data/.hound.yml +5 -16
  4. data/.travis.yml +15 -12
  5. data/Appraisals +4 -8
  6. data/CONTRIBUTING.md +16 -5
  7. data/Gemfile +3 -8
  8. data/LICENSE +1 -1
  9. data/NEWS +105 -31
  10. data/README.md +239 -153
  11. data/Rakefile +1 -1
  12. data/UPGRADING +12 -9
  13. data/features/basic_integration.feature +3 -2
  14. data/features/migration.feature +0 -24
  15. data/features/step_definitions/attachment_steps.rb +6 -6
  16. data/features/step_definitions/rails_steps.rb +29 -28
  17. data/features/step_definitions/s3_steps.rb +2 -2
  18. data/features/support/env.rb +1 -0
  19. data/features/support/paths.rb +1 -1
  20. data/features/support/rails.rb +0 -24
  21. data/gemfiles/4.2.gemfile +3 -5
  22. data/gemfiles/{3.2.gemfile → 5.0.gemfile} +4 -6
  23. data/lib/generators/paperclip/paperclip_generator.rb +9 -1
  24. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +1 -1
  25. data/lib/paperclip/attachment.rb +25 -14
  26. data/lib/paperclip/attachment_registry.rb +2 -1
  27. data/lib/paperclip/callbacks.rb +8 -6
  28. data/lib/paperclip/content_type_detector.rb +3 -2
  29. data/lib/paperclip/errors.rb +3 -1
  30. data/lib/paperclip/file_command_content_type_detector.rb +1 -1
  31. data/lib/paperclip/geometry_detector_factory.rb +2 -2
  32. data/lib/paperclip/glue.rb +1 -1
  33. data/lib/paperclip/has_attached_file.rb +7 -1
  34. data/lib/paperclip/helpers.rb +15 -11
  35. data/lib/paperclip/interpolations.rb +1 -1
  36. data/lib/paperclip/io_adapters/abstract_adapter.rb +29 -3
  37. data/lib/paperclip/io_adapters/attachment_adapter.rb +10 -5
  38. data/lib/paperclip/io_adapters/data_uri_adapter.rb +8 -8
  39. data/lib/paperclip/io_adapters/empty_string_adapter.rb +5 -4
  40. data/lib/paperclip/io_adapters/file_adapter.rb +12 -6
  41. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +7 -7
  42. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -6
  43. data/lib/paperclip/io_adapters/nil_adapter.rb +8 -5
  44. data/lib/paperclip/io_adapters/registry.rb +6 -2
  45. data/lib/paperclip/io_adapters/stringio_adapter.rb +9 -6
  46. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +10 -6
  47. data/lib/paperclip/io_adapters/uri_adapter.rb +17 -14
  48. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +4 -4
  49. data/lib/paperclip/media_type_spoof_detector.rb +3 -2
  50. data/lib/paperclip/processor.rb +5 -4
  51. data/lib/paperclip/schema.rb +4 -10
  52. data/lib/paperclip/storage/filesystem.rb +13 -2
  53. data/lib/paperclip/storage/fog.rb +19 -13
  54. data/lib/paperclip/storage/s3.rb +87 -58
  55. data/lib/paperclip/thumbnail.rb +18 -8
  56. data/lib/paperclip/url_generator.rb +18 -14
  57. data/lib/paperclip/validators/attachment_size_validator.rb +1 -7
  58. data/lib/paperclip/validators.rb +1 -1
  59. data/lib/paperclip/version.rb +3 -1
  60. data/lib/paperclip.rb +13 -12
  61. data/lib/tasks/paperclip.rake +18 -4
  62. data/paperclip.gemspec +13 -11
  63. data/spec/paperclip/attachment_processing_spec.rb +2 -4
  64. data/spec/paperclip/attachment_registry_spec.rb +28 -0
  65. data/spec/paperclip/attachment_spec.rb +72 -18
  66. data/spec/paperclip/content_type_detector_spec.rb +1 -1
  67. data/spec/paperclip/file_command_content_type_detector_spec.rb +15 -1
  68. data/spec/paperclip/has_attached_file_spec.rb +24 -8
  69. data/spec/paperclip/integration_spec.rb +4 -3
  70. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +76 -22
  71. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +6 -3
  72. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +7 -1
  73. data/spec/paperclip/io_adapters/file_adapter_spec.rb +2 -2
  74. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +18 -1
  75. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +1 -1
  76. data/spec/paperclip/io_adapters/registry_spec.rb +2 -2
  77. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +1 -1
  78. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +5 -5
  79. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +48 -3
  80. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +10 -0
  81. data/spec/paperclip/media_type_spoof_detector_spec.rb +15 -0
  82. data/spec/paperclip/paperclip_spec.rb +15 -45
  83. data/spec/paperclip/processor_spec.rb +4 -4
  84. data/spec/paperclip/storage/fog_spec.rb +26 -0
  85. data/spec/paperclip/storage/s3_live_spec.rb +20 -14
  86. data/spec/paperclip/storage/s3_spec.rb +357 -190
  87. data/spec/paperclip/tempfile_spec.rb +35 -0
  88. data/spec/paperclip/thumbnail_spec.rb +38 -35
  89. data/spec/paperclip/url_generator_spec.rb +53 -42
  90. data/spec/paperclip/validators/attachment_size_validator_spec.rb +26 -20
  91. data/spec/paperclip/validators_spec.rb +5 -5
  92. data/spec/spec_helper.rb +6 -2
  93. data/spec/support/assertions.rb +12 -1
  94. data/spec/support/conditional_filter_helper.rb +5 -0
  95. data/spec/support/mock_attachment.rb +2 -0
  96. data/spec/support/mock_url_generator_builder.rb +2 -2
  97. data/spec/support/model_reconstruction.rb +10 -2
  98. data/spec/support/reporting.rb +11 -0
  99. metadata +69 -75
  100. data/cucumber/paperclip_steps.rb +0 -6
  101. data/gemfiles/4.1.gemfile +0 -19
  102. data/lib/paperclip/deprecations.rb +0 -42
  103. data/lib/paperclip/locales/de.yml +0 -18
  104. data/lib/paperclip/locales/es.yml +0 -18
  105. data/lib/paperclip/locales/ja.yml +0 -18
  106. data/lib/paperclip/locales/pt-BR.yml +0 -18
  107. data/lib/paperclip/locales/zh-CN.yml +0 -18
  108. data/lib/paperclip/locales/zh-HK.yml +0 -18
  109. data/lib/paperclip/locales/zh-TW.yml +0 -18
  110. data/spec/paperclip/deprecations_spec.rb +0 -65
  111. data/spec/support/deprecations.rb +0 -9
  112. data/spec/support/rails_helpers.rb +0 -7
@@ -18,7 +18,7 @@ module Paperclip
18
18
  raise "Class #{klass.name} has no attachments specified"
19
19
  end
20
20
 
21
- if !name.blank? && attachment_names.map(&:to_s).include?(name.to_s)
21
+ if name.present? && attachment_names.map(&:to_s).include?(name.to_s)
22
22
  [ name ]
23
23
  else
24
24
  attachment_names
@@ -46,7 +46,7 @@ namespace :paperclip do
46
46
  attachment = instance.send(name)
47
47
  begin
48
48
  attachment.reprocess!(*styles)
49
- rescue Exception => e
49
+ rescue StandardError => e
50
50
  Paperclip::Task.log_error("exception while processing #{klass} ID #{instance.id}:")
51
51
  Paperclip::Task.log_error(" " + e.message + "\n")
52
52
  end
@@ -64,7 +64,8 @@ namespace :paperclip do
64
64
  names = Paperclip::Task.obtain_attachments(klass)
65
65
  names.each do |name|
66
66
  Paperclip.each_instance_with_attachment(klass, name) do |instance|
67
- if file = Paperclip.io_adapters.for(instance.send(name))
67
+ attachment = instance.send(name)
68
+ if file = Paperclip.io_adapters.for(attachment, attachment.options[:adapter_options])
68
69
  instance.send("#{name}_file_name=", instance.send("#{name}_file_name").strip)
69
70
  instance.send("#{name}_content_type=", file.content_type.to_s.strip)
70
71
  instance.send("#{name}_file_size=", file.size) if instance.respond_to?("#{name}_file_size")
@@ -90,6 +91,19 @@ namespace :paperclip do
90
91
  end
91
92
  Paperclip.save_current_attachments_styles!
92
93
  end
94
+
95
+ desc "Regenerates fingerprints for a given CLASS (and optional ATTACHMENT). Useful when changing digest."
96
+ task :fingerprints => :environment do
97
+ klass = Paperclip::Task.obtain_class
98
+ names = Paperclip::Task.obtain_attachments(klass)
99
+ names.each do |name|
100
+ Paperclip.each_instance_with_attachment(klass, name) do |instance|
101
+ attachment = instance.send(name)
102
+ attachment.assign(attachment)
103
+ instance.save(:validate => false)
104
+ end
105
+ end
106
+ end
93
107
  end
94
108
 
95
109
  desc "Cleans out invalid attachments. Useful after you've added new validations."
@@ -109,7 +123,7 @@ namespace :paperclip do
109
123
  end
110
124
  end
111
125
 
112
- desc "find missing attachments. Useful to know which attachments are broken"
126
+ desc "find missing attachments. Useful to know which attachments are broken"
113
127
  task :find_broken_attachments => :environment do
114
128
  klass = Paperclip::Task.obtain_class
115
129
  names = Paperclip::Task.obtain_attachments(klass)
data/paperclip.gemspec CHANGED
@@ -17,27 +17,30 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
19
 
20
+ if File.exist?('UPGRADING')
21
+ s.post_install_message = File.read("UPGRADING")
22
+ end
23
+
20
24
  s.requirements << "ImageMagick"
21
- s.required_ruby_version = ">= 1.9.2"
25
+ s.required_ruby_version = ">= 2.1.0"
22
26
 
23
- s.add_dependency('activemodel', '>= 3.2.0', '< 5.0')
24
- s.add_dependency('activesupport', '>= 3.2.0', '< 5.0')
25
- s.add_dependency('cocaine', '~> 0.5.5')
27
+ s.add_dependency('activemodel', '>= 4.2.0', '< 6.0')
28
+ s.add_dependency('activesupport', '>= 4.2.0', '< 6.0')
29
+ s.add_dependency('terrapin', '~> 0.6.0')
26
30
  s.add_dependency('mime-types')
27
31
  s.add_dependency('mimemagic', '~> 0.3.8')
28
- s.add_dependency('bigdecimal', '1.3.5')
29
32
 
30
- s.add_development_dependency('activerecord', '>= 3.2.0', '< 5.0')
33
+ s.add_development_dependency('activerecord', '>= 4.2.0', '< 6.0')
31
34
  s.add_development_dependency('shoulda')
32
35
  s.add_development_dependency('rspec', '~> 3.0')
33
36
  s.add_development_dependency('appraisal')
34
37
  s.add_development_dependency('mocha')
35
- s.add_development_dependency('aws-sdk', '>= 1.5.7', "<= 2.0")
38
+ s.add_development_dependency('aws-sdk', '>= 2.3.0', '< 3.0')
36
39
  s.add_development_dependency('bourne', '< 1.6')
37
- s.add_development_dependency('cucumber', '~> 1.3.18')
40
+ s.add_development_dependency('cucumber-rails')
41
+ s.add_development_dependency('cucumber-expressions', '4.0.3') # TODO: investigate failures on 4.0.4
38
42
  s.add_development_dependency('aruba', '~> 0.9.0')
39
43
  s.add_development_dependency('nokogiri')
40
- # Ruby version < 1.9.3 can't install capybara > 2.0.3.
41
44
  s.add_development_dependency('capybara')
42
45
  s.add_development_dependency('bundler')
43
46
  s.add_development_dependency('fog-aws')
@@ -45,8 +48,7 @@ Gem::Specification.new do |s|
45
48
  s.add_development_dependency('launchy')
46
49
  s.add_development_dependency('rake')
47
50
  s.add_development_dependency('fakeweb')
48
- s.add_development_dependency('railties')
49
- s.add_development_dependency('actionmailer', '>= 3.2.0', '< 5.0')
51
+ s.add_development_dependency('railties', '>= 4.2.0', '< 6.0')
50
52
  s.add_development_dependency('generator_spec')
51
53
  s.add_development_dependency('timecop')
52
54
  end
@@ -2,11 +2,9 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe 'Attachment Processing' do
5
- context 'using validates_attachment_content_type' do
6
- before do
7
- rebuild_class
8
- end
5
+ before { rebuild_class }
9
6
 
7
+ context 'using validates_attachment_content_type' do
10
8
  it 'processes attachments given a valid assignment' do
11
9
  file = File.new(fixture_file("5k.png"))
12
10
  Dummy.validates_attachment_content_type :avatar, content_type: "image/png"
@@ -111,6 +111,34 @@ describe 'Attachment Registry' do
111
111
 
112
112
  assert_equal expected_definitions, definitions
113
113
  end
114
+
115
+ it 'allows subclasses to override attachment defitions' do
116
+ foo_definitions = { avatar: { yo: "greeting" } }
117
+ bar_definitions = { avatar: { yo: "hello" } }
118
+
119
+ expected_definitions = {
120
+ avatar: {
121
+ yo: "hello"
122
+ }
123
+ }
124
+
125
+ foo = Class.new
126
+ bar = Class.new(foo)
127
+ Paperclip::AttachmentRegistry.register(
128
+ foo,
129
+ :avatar,
130
+ foo_definitions[:avatar]
131
+ )
132
+ Paperclip::AttachmentRegistry.register(
133
+ bar,
134
+ :avatar,
135
+ bar_definitions[:avatar]
136
+ )
137
+
138
+ definitions = Paperclip::AttachmentRegistry.definitions_for(bar)
139
+
140
+ assert_equal expected_definitions, definitions
141
+ end
114
142
  end
115
143
 
116
144
  context '.clear' do
@@ -222,9 +222,6 @@ describe Paperclip::Attachment do
222
222
  dummy.avatar_file_name = "fake.jpg"
223
223
  dummy.stubs(:new_record?).returns(false)
224
224
  expected_string = '{"avatar":"/system/dummies/avatars/000/001/234/original/fake.jpg"}'
225
- if ActiveRecord::Base.include_root_in_json # This is true by default in Rails 3, and false in 4
226
- expected_string = %({"dummy":#{expected_string}})
227
- end
228
225
  # active_model pre-3.2 checks only by calling any? on it, thus it doesn't work if it is empty
229
226
  assert_equal expected_string, dummy.to_json(only: [:dummy_key_for_old_active_model], methods: [:avatar])
230
227
  end
@@ -503,6 +500,7 @@ describe Paperclip::Attachment do
503
500
  @attachment.expects(:post_process).with(:thumb)
504
501
  @attachment.expects(:post_process).with(:large).never
505
502
  @attachment.assign(@file)
503
+ @attachment.save
506
504
  end
507
505
  end
508
506
 
@@ -700,9 +698,6 @@ describe Paperclip::Attachment do
700
698
 
701
699
  context "when assigned" do
702
700
  it "calls #make on all specified processors" do
703
- Paperclip::Thumbnail.stubs(:make).with(any_parameters).returns(@file)
704
- Paperclip::Test.stubs(:make).with(any_parameters).returns(@file)
705
-
706
701
  @dummy.avatar = @file
707
702
 
708
703
  expect(Paperclip::Thumbnail).to have_received(:make)
@@ -717,7 +712,6 @@ describe Paperclip::Attachment do
717
712
  convert_options: "",
718
713
  source_file_options: ""
719
714
  })
720
- Paperclip::Thumbnail.stubs(:make).returns(@file)
721
715
 
722
716
  @dummy.avatar = @file
723
717
 
@@ -725,12 +719,36 @@ describe Paperclip::Attachment do
725
719
  end
726
720
 
727
721
  it "calls #make with attachment passed as third argument" do
728
- Paperclip::Test.expects(:make).returns(@file)
729
-
730
722
  @dummy.avatar = @file
731
723
 
732
724
  expect(Paperclip::Test).to have_received(:make).with(anything, anything, @dummy.avatar)
733
725
  end
726
+
727
+ it "calls #make and unlinks intermediary files afterward" do
728
+ @dummy.avatar.expects(:unlink_files).with([@file, @file])
729
+
730
+ @dummy.avatar = @file
731
+ end
732
+ end
733
+ end
734
+
735
+ context "An attachment with a processor that returns original file" do
736
+ before do
737
+ class Paperclip::Test < Paperclip::Processor
738
+ def make; @file; end
739
+ end
740
+ rebuild_model processors: [:test], styles: { once: "100x100" }
741
+ @file = StringIO.new("...")
742
+ @file.stubs(:close)
743
+ @dummy = Dummy.new
744
+ end
745
+
746
+ context "when assigned" do
747
+ it "#calls #make and doesn't unlink the original file" do
748
+ @dummy.avatar.expects(:unlink_files).with([])
749
+
750
+ @dummy.avatar = @file
751
+ end
734
752
  end
735
753
  end
736
754
 
@@ -1104,7 +1122,7 @@ describe Paperclip::Attachment do
1104
1122
  context "with a file assigned but not saved yet" do
1105
1123
  it "clears out any attached files" do
1106
1124
  @attachment.assign(@file)
1107
- assert !@attachment.queued_for_write.blank?
1125
+ assert @attachment.queued_for_write.present?
1108
1126
  @attachment.clear
1109
1127
  assert @attachment.queued_for_write.blank?
1110
1128
  end
@@ -1354,6 +1372,12 @@ describe Paperclip::Attachment do
1354
1372
  end
1355
1373
 
1356
1374
  it "does not calculate fingerprint" do
1375
+ Digest::MD5.stubs(:file)
1376
+ @dummy.avatar = @file
1377
+ expect(Digest::MD5).to have_received(:file).never
1378
+ end
1379
+
1380
+ it "does not assign fingerprint" do
1357
1381
  @dummy.avatar = @file
1358
1382
  assert_nil @dummy.avatar.fingerprint
1359
1383
  end
@@ -1410,16 +1434,46 @@ describe Paperclip::Attachment do
1410
1434
  assert_nothing_raised { @dummy.avatar = @file }
1411
1435
  end
1412
1436
 
1413
- it "returns the right value when sent #avatar_fingerprint" do
1414
- @dummy.avatar = @file
1415
- assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
1437
+ context "with explicitly set digest" do
1438
+ before do
1439
+ rebuild_class adapter_options: { hash_digest: Digest::SHA256 }
1440
+ @dummy = Dummy.new
1441
+ end
1442
+
1443
+ it "returns the right value when sent #avatar_fingerprint" do
1444
+ @dummy.avatar = @file
1445
+ assert_equal "734016d801a497f5579cdd4ef2ae1d020088c1db754dc434482d76dd5486520a",
1446
+ @dummy.avatar_fingerprint
1447
+ end
1448
+
1449
+ it "returns the right value when saved, reloaded, and sent #avatar_fingerprint" do
1450
+ @dummy.avatar = @file
1451
+ @dummy.save
1452
+ @dummy = Dummy.find(@dummy.id)
1453
+ assert_equal "734016d801a497f5579cdd4ef2ae1d020088c1db754dc434482d76dd5486520a",
1454
+ @dummy.avatar_fingerprint
1455
+ end
1416
1456
  end
1417
1457
 
1418
- it "returns the right value when saved, reloaded, and sent #avatar_fingerprint" do
1419
- @dummy.avatar = @file
1420
- @dummy.save
1421
- @dummy = Dummy.find(@dummy.id)
1422
- assert_equal 'aec488126c3b33c08a10c3fa303acf27', @dummy.avatar_fingerprint
1458
+ context "with the default digest" do
1459
+ before do
1460
+ rebuild_class # MD5 is the default
1461
+ @dummy = Dummy.new
1462
+ end
1463
+
1464
+ it "returns the right value when sent #avatar_fingerprint" do
1465
+ @dummy.avatar = @file
1466
+ assert_equal "aec488126c3b33c08a10c3fa303acf27",
1467
+ @dummy.avatar_fingerprint
1468
+ end
1469
+
1470
+ it "returns the right value when saved, reloaded, and sent #avatar_fingerprint" do
1471
+ @dummy.avatar = @file
1472
+ @dummy.save
1473
+ @dummy = Dummy.find(@dummy.id)
1474
+ assert_equal "aec488126c3b33c08a10c3fa303acf27",
1475
+ @dummy.avatar_fingerprint
1476
+ end
1423
1477
  end
1424
1478
  end
1425
1479
  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
@@ -38,6 +38,15 @@ describe Paperclip::HasAttachedFile do
38
38
  assert_adding_attachment('avatar').defines_callback('after_commit')
39
39
  end
40
40
 
41
+ context 'when the class does not allow after_commit callbacks' do
42
+ it 'defines an after_destroy callback' do
43
+ assert_adding_attachment(
44
+ 'avatar',
45
+ unstub_methods: [:after_commit]
46
+ ).defines_callback('after_destroy')
47
+ end
48
+ end
49
+
41
50
  it 'defines the Paperclip-specific callbacks' do
42
51
  assert_adding_attachment('avatar').defines_callback('define_paperclip_callbacks')
43
52
  end
@@ -53,20 +62,26 @@ describe Paperclip::HasAttachedFile do
53
62
 
54
63
  private
55
64
 
56
- def assert_adding_attachment(attachment_name)
57
- AttachmentAdder.new(attachment_name)
65
+ def assert_adding_attachment(attachment_name, options={})
66
+ AttachmentAdder.new(attachment_name, options)
58
67
  end
59
68
 
60
69
  class AttachmentAdder
61
70
  include Mocha::API
62
71
  include RSpec::Matchers
63
72
 
64
- def initialize(attachment_name)
73
+ def initialize(attachment_name, options = {})
65
74
  @attachment_name = attachment_name
75
+ @stubbed_class = stub_class
76
+ if options.present?
77
+ options[:unstub_methods].each do |method|
78
+ @stubbed_class.unstub(method)
79
+ end
80
+ end
66
81
  end
67
82
 
68
83
  def defines_method(method_name)
69
- a_class = stub_class
84
+ a_class = @stubbed_class
70
85
 
71
86
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
72
87
 
@@ -74,7 +89,7 @@ describe Paperclip::HasAttachedFile do
74
89
  end
75
90
 
76
91
  def defines_class_method(method_name)
77
- a_class = stub_class
92
+ a_class = @stubbed_class
78
93
  a_class.class.stubs(:define_method)
79
94
 
80
95
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
@@ -83,7 +98,7 @@ describe Paperclip::HasAttachedFile do
83
98
  end
84
99
 
85
100
  def defines_validation
86
- a_class = stub_class
101
+ a_class = @stubbed_class
87
102
 
88
103
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
89
104
 
@@ -91,7 +106,7 @@ describe Paperclip::HasAttachedFile do
91
106
  end
92
107
 
93
108
  def registers_attachment
94
- a_class = stub_class
109
+ a_class = @stubbed_class
95
110
  Paperclip::AttachmentRegistry.stubs(:register)
96
111
 
97
112
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {size: 1})
@@ -100,7 +115,7 @@ describe Paperclip::HasAttachedFile do
100
115
  end
101
116
 
102
117
  def defines_callback(callback_name)
103
- a_class = stub_class
118
+ a_class = @stubbed_class
104
119
 
105
120
  Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
106
121
 
@@ -132,6 +147,7 @@ describe Paperclip::HasAttachedFile do
132
147
  after_save: nil,
133
148
  before_destroy: nil,
134
149
  after_commit: nil,
150
+ after_destroy: nil,
135
151
  define_paperclip_callbacks: nil,
136
152
  extend: nil,
137
153
  name: 'Billy',
@@ -7,9 +7,10 @@ describe 'Paperclip' do
7
7
  before do
8
8
  rebuild_model
9
9
  @file = File.new(fixture_file("5k.png"), 'rb')
10
- 300.times do |i|
11
- Dummy.create! avatar: @file
12
- end
10
+ # 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 }
13
14
  end
14
15
 
15
16
  after { @file.close }
@@ -9,70 +9,124 @@ describe Paperclip::AbstractAdapter do
9
9
  end
10
10
  end
11
11
 
12
+ subject { TestAdapter.new(nil) }
13
+
12
14
  context "content type from file contents" do
13
15
  before do
14
- @adapter = TestAdapter.new
15
- @adapter.stubs(:path).returns("image.png")
16
+ subject.stubs(:path).returns("image.png")
16
17
  Paperclip.stubs(:run).returns("image/png\n")
17
18
  Paperclip::ContentTypeDetector.any_instance.stubs(:type_from_mime_magic).returns("image/png")
18
19
  end
19
20
 
20
21
  it "returns the content type without newline" do
21
- assert_equal "image/png", @adapter.content_type
22
+ assert_equal "image/png", subject.content_type
22
23
  end
23
24
  end
24
25
 
25
26
  context "nil?" do
26
27
  it "returns false" do
27
- assert !TestAdapter.new.nil?
28
+ assert !subject.nil?
28
29
  end
29
30
  end
30
31
 
31
32
  context "delegation" do
32
33
  before do
33
- @adapter = TestAdapter.new
34
- @adapter.tempfile = stub("Tempfile")
34
+ subject.tempfile = stub("Tempfile")
35
35
  end
36
36
 
37
- [:binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink].each do |method|
37
+ [:binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :readbyte, :rewind, :unlink].each do |method|
38
38
  it "delegates #{method} to @tempfile" do
39
- @adapter.tempfile.stubs(method)
40
- @adapter.public_send(method)
41
- assert_received @adapter.tempfile, method
39
+ subject.tempfile.stubs(method)
40
+ subject.public_send(method)
41
+ assert_received subject.tempfile, method
42
42
  end
43
43
  end
44
44
  end
45
45
 
46
46
  it 'gets rid of slashes and colons in filenames' do
47
- @adapter = TestAdapter.new
48
- @adapter.original_filename = "awesome/file:name.png"
47
+ subject.original_filename = "awesome/file:name.png"
49
48
 
50
- assert_equal "awesome_file_name.png", @adapter.original_filename
49
+ assert_equal "awesome_file_name.png", subject.original_filename
51
50
  end
52
51
 
53
52
  it 'is an assignment' do
54
- assert TestAdapter.new.assignment?
53
+ assert subject.assignment?
55
54
  end
56
55
 
57
56
  it 'is not nil' do
58
- assert !TestAdapter.new.nil?
57
+ assert !subject.nil?
59
58
  end
60
59
 
61
60
  it "generates a destination filename with no original filename" do
62
- @adapter = TestAdapter.new
63
- expect(@adapter.send(:destination).path).to_not be_nil
61
+ expect(subject.send(:destination).path).to_not be_nil
64
62
  end
65
63
 
66
64
  it 'uses the original filename to generate the tempfile' do
67
- @adapter = TestAdapter.new
68
- @adapter.original_filename = "file.png"
69
- expect(@adapter.send(:destination).path).to end_with(".png")
65
+ subject.original_filename = "file.png"
66
+ expect(subject.send(:destination).path).to end_with(".png")
67
+ end
68
+
69
+ context "generates a fingerprint" do
70
+ subject { TestAdapter.new(nil, options) }
71
+
72
+ before do
73
+ subject.stubs(:path).returns(fixture_file("50x50.png"))
74
+ end
75
+
76
+ context "MD5" do
77
+ let(:options) { { hash_digest: Digest::MD5 } }
78
+
79
+ it "returns a fingerprint" do
80
+ expect(subject.fingerprint).to be_a String
81
+ expect(subject.fingerprint).to eq "a790b00c9b5d58a8fd17a1ec5a187129"
82
+ end
83
+ end
84
+
85
+ context "SHA256" do
86
+ let(:options) { { hash_digest: Digest::SHA256 } }
87
+
88
+ it "returns a fingerprint" do
89
+ expect(subject.fingerprint).to be_a String
90
+ expect(subject.fingerprint).
91
+ to eq "243d7ce1099719df25f600f1c369c629fb979f88d5a01dbe7d0d48c8e6715bb1"
92
+ end
93
+ end
70
94
  end
71
95
 
72
96
  context "#original_filename=" do
73
97
  it "should not fail with a nil original filename" do
74
- adapter = TestAdapter.new
75
- expect{ adapter.original_filename = nil }.not_to raise_error
98
+ expect { subject.original_filename = nil }.not_to raise_error
99
+ end
100
+ end
101
+
102
+ context "#link_or_copy_file" do
103
+ class TestLinkOrCopyAdapter < Paperclip::AbstractAdapter
104
+ public :copy_to_tempfile, :destination
105
+ end
106
+
107
+ subject { TestLinkOrCopyAdapter.new(nil) }
108
+ let(:body) { "body" }
109
+
110
+ let(:file) do
111
+ t = Tempfile.new("destination")
112
+ t.print(body)
113
+ t.rewind
114
+ t
115
+ end
116
+
117
+ after do
118
+ file.close
119
+ file.unlink
120
+ end
121
+
122
+ it "should be able to read the file" do
123
+ expect(subject.copy_to_tempfile(file).read).to eq(body)
124
+ end
125
+
126
+ it "should be able to reopen the file after symlink has failed" do
127
+ FileUtils.expects(:ln).raises(Errno::EXDEV)
128
+
129
+ expect(subject.copy_to_tempfile(file).read).to eq(body)
76
130
  end
77
131
  end
78
132
  end
@@ -13,7 +13,8 @@ describe Paperclip::AttachmentAdapter do
13
13
 
14
14
  @attachment.assign(@file)
15
15
  @attachment.save
16
- @subject = Paperclip.io_adapters.for(@attachment)
16
+ @subject = Paperclip.io_adapters.for(@attachment,
17
+ hash_digest: Digest::MD5)
17
18
  end
18
19
 
19
20
  after do
@@ -65,7 +66,8 @@ describe Paperclip::AttachmentAdapter do
65
66
 
66
67
  @attachment.assign(@file)
67
68
  @attachment.save
68
- @subject = Paperclip.io_adapters.for(@attachment)
69
+ @subject = Paperclip.io_adapters.for(@attachment,
70
+ hash_digest: Digest::MD5)
69
71
  end
70
72
 
71
73
  after do
@@ -92,7 +94,8 @@ describe Paperclip::AttachmentAdapter do
92
94
  FileUtils.cp @attachment.queued_for_write[:thumb].path, @thumb.path
93
95
 
94
96
  @attachment.save
95
- @subject = Paperclip.io_adapters.for(@attachment.styles[:thumb])
97
+ @subject = Paperclip.io_adapters.for(@attachment.styles[:thumb],
98
+ hash_digest: Digest::MD5)
96
99
  end
97
100
 
98
101
  after do
@@ -1,7 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Paperclip::DataUriAdapter do
4
+ before do
5
+ Paperclip::DataUriAdapter.register
6
+ end
7
+
4
8
  after do
9
+ Paperclip.io_adapters.unregister(described_class)
10
+
5
11
  if @subject
6
12
  @subject.close
7
13
  end
@@ -20,7 +26,7 @@ describe Paperclip::DataUriAdapter do
20
26
  context "a new instance" do
21
27
  before do
22
28
  @contents = "data:image/png;base64,#{original_base64_content}"
23
- @subject = Paperclip.io_adapters.for(@contents)
29
+ @subject = Paperclip.io_adapters.for(@contents, hash_digest: Digest::MD5)
24
30
  end
25
31
 
26
32
  it "returns a nondescript file name" do
@@ -15,7 +15,7 @@ describe Paperclip::FileAdapter do
15
15
 
16
16
  context 'doing normal things' do
17
17
  before do
18
- @subject = Paperclip.io_adapters.for(@file)
18
+ @subject = Paperclip.io_adapters.for(@file, hash_digest: Digest::MD5)
19
19
  end
20
20
 
21
21
  it 'uses the original filename to generate the tempfile' do
@@ -61,7 +61,7 @@ describe Paperclip::FileAdapter do
61
61
  context "file with multiple possible content type" do
62
62
  before do
63
63
  MIME::Types.stubs(:type_for).returns([MIME::Type.new('image/x-png'), MIME::Type.new('image/png')])
64
- @subject = Paperclip.io_adapters.for(@file)
64
+ @subject = Paperclip.io_adapters.for(@file, hash_digest: Digest::MD5)
65
65
  end
66
66
 
67
67
  it "prefers officially registered mime type" do