paperclip 5.1.0 → 5.2.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -0
  3. data/.hound.yml +5 -16
  4. data/.travis.yml +14 -15
  5. data/Appraisals +3 -23
  6. data/Gemfile +1 -0
  7. data/NEWS +36 -1
  8. data/README.md +58 -10
  9. data/Rakefile +1 -1
  10. data/UPGRADING +1 -1
  11. data/features/step_definitions/attachment_steps.rb +6 -6
  12. data/features/step_definitions/rails_steps.rb +29 -22
  13. data/features/step_definitions/s3_steps.rb +1 -1
  14. data/features/support/env.rb +1 -0
  15. data/features/support/paths.rb +1 -1
  16. data/features/support/rails.rb +0 -24
  17. data/gemfiles/{4.2.awsv2.0.gemfile → 4.2.gemfile} +1 -1
  18. data/gemfiles/{5.0.awsv2.1.gemfile → 5.0.gemfile} +2 -2
  19. data/lib/paperclip.rb +12 -10
  20. data/lib/paperclip/attachment.rb +10 -4
  21. data/lib/paperclip/io_adapters/abstract_adapter.rb +24 -2
  22. data/lib/paperclip/io_adapters/attachment_adapter.rb +10 -5
  23. data/lib/paperclip/io_adapters/data_uri_adapter.rb +8 -8
  24. data/lib/paperclip/io_adapters/empty_string_adapter.rb +5 -4
  25. data/lib/paperclip/io_adapters/file_adapter.rb +12 -6
  26. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +7 -7
  27. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -6
  28. data/lib/paperclip/io_adapters/nil_adapter.rb +8 -5
  29. data/lib/paperclip/io_adapters/registry.rb +6 -2
  30. data/lib/paperclip/io_adapters/stringio_adapter.rb +9 -6
  31. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +9 -5
  32. data/lib/paperclip/io_adapters/uri_adapter.rb +13 -11
  33. data/lib/paperclip/storage/filesystem.rb +13 -2
  34. data/lib/paperclip/storage/fog.rb +7 -4
  35. data/lib/paperclip/storage/s3.rb +31 -3
  36. data/lib/paperclip/thumbnail.rb +14 -4
  37. data/lib/paperclip/version.rb +1 -1
  38. data/lib/tasks/paperclip.rake +17 -3
  39. data/paperclip.gemspec +3 -3
  40. data/spec/paperclip/attachment_spec.rb +39 -8
  41. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +44 -21
  42. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +6 -3
  43. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +7 -1
  44. data/spec/paperclip/io_adapters/file_adapter_spec.rb +2 -2
  45. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +6 -1
  46. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +1 -1
  47. data/spec/paperclip/io_adapters/registry_spec.rb +2 -2
  48. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +1 -1
  49. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +3 -3
  50. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +6 -1
  51. data/spec/paperclip/storage/fog_spec.rb +16 -0
  52. data/spec/paperclip/storage/s3_live_spec.rb +12 -10
  53. data/spec/paperclip/storage/s3_spec.rb +85 -4
  54. data/spec/paperclip/tempfile_spec.rb +35 -0
  55. data/spec/paperclip/thumbnail_spec.rb +35 -32
  56. data/spec/spec_helper.rb +3 -1
  57. data/spec/support/assertions.rb +5 -1
  58. data/spec/support/conditional_filter_helper.rb +5 -0
  59. metadata +31 -135
  60. data/gemfiles/4.2.awsv2.1.gemfile +0 -17
  61. data/gemfiles/4.2.awsv2.gemfile +0 -20
  62. data/gemfiles/5.0.awsv2.0.gemfile +0 -17
  63. data/gemfiles/5.0.awsv2.gemfile +0 -20
@@ -1,7 +1,13 @@
1
1
  module Paperclip
2
2
  class UploadedFileAdapter < AbstractAdapter
3
- def initialize(target)
4
- @target = target
3
+ def self.register
4
+ Paperclip.io_adapters.register self do |target|
5
+ target.class.name.include?("UploadedFile")
6
+ end
7
+ end
8
+
9
+ def initialize(target, options = {})
10
+ super
5
11
  cache_current_values
6
12
 
7
13
  if @target.respond_to?(:tempfile)
@@ -37,6 +43,4 @@ module Paperclip
37
43
  end
38
44
  end
39
45
 
40
- Paperclip.io_adapters.register Paperclip::UploadedFileAdapter do |target|
41
- target.class.name.include?("UploadedFile")
42
- end
46
+ Paperclip::UploadedFileAdapter.register
@@ -1,11 +1,17 @@
1
- require 'open-uri'
1
+ require "open-uri"
2
2
 
3
3
  module Paperclip
4
4
  class UriAdapter < AbstractAdapter
5
5
  attr_writer :content_type
6
6
 
7
- def initialize(target)
8
- @target = target
7
+ def self.register
8
+ Paperclip.io_adapters.register self do |target|
9
+ target.is_a?(URI)
10
+ end
11
+ end
12
+
13
+ def initialize(target, options = {})
14
+ super
9
15
  @content = download_content
10
16
  cache_current_values
11
17
  @tempfile = copy_to_tempfile(@content)
@@ -28,9 +34,9 @@ module Paperclip
28
34
  end
29
35
 
30
36
  def filename_from_content_disposition
31
- if @content.meta.has_key?("content-disposition")
32
- @content.meta["content-disposition"].
33
- match(/filename="([^"]*)"/)[1]
37
+ if @content.meta.key?("content-disposition")
38
+ matches = @content.meta["content-disposition"].match(/filename="([^"]*)"/)
39
+ matches[1] if matches
34
40
  end
35
41
  end
36
42
 
@@ -49,7 +55,7 @@ module Paperclip
49
55
  end
50
56
 
51
57
  def copy_to_tempfile(src)
52
- while data = src.read(16*1024)
58
+ while data = src.read(16 * 1024)
53
59
  destination.write(data)
54
60
  end
55
61
  src.close
@@ -58,7 +64,3 @@ module Paperclip
58
64
  end
59
65
  end
60
66
  end
61
-
62
- Paperclip.io_adapters.register Paperclip::UriAdapter do |target|
63
- target.kind_of?(URI)
64
- end
@@ -37,7 +37,7 @@ module Paperclip
37
37
  @queued_for_write.each do |style_name, file|
38
38
  FileUtils.mkdir_p(File.dirname(path(style_name)))
39
39
  begin
40
- FileUtils.mv(file.path, path(style_name))
40
+ move_file(file.path, path(style_name))
41
41
  rescue SystemCallError
42
42
  File.open(path(style_name), "wb") do |new_file|
43
43
  while chunk = file.read(16 * 1024)
@@ -46,7 +46,7 @@ module Paperclip
46
46
  end
47
47
  end
48
48
  unless @options[:override_file_permissions] == false
49
- resolved_chmod = (@options[:override_file_permissions] &~ 0111) || (0666 &~ File.umask)
49
+ resolved_chmod = (@options[:override_file_permissions] & ~0111) || (0666 & ~File.umask)
50
50
  FileUtils.chmod( resolved_chmod, path(style_name) )
51
51
  end
52
52
  file.rewind
@@ -84,6 +84,17 @@ module Paperclip
84
84
  def copy_to_local_file(style, local_dest_path)
85
85
  FileUtils.cp(path(style), local_dest_path)
86
86
  end
87
+
88
+ private
89
+
90
+ def move_file(src, dest)
91
+ # Support hardlinked files
92
+ if File.identical?(src, dest)
93
+ File.unlink(src)
94
+ else
95
+ FileUtils.mv(src, dest)
96
+ end
97
+ end
87
98
  end
88
99
 
89
100
  end
@@ -86,11 +86,14 @@ module Paperclip
86
86
  end
87
87
 
88
88
  def fog_public(style = default_style)
89
- if @options.has_key?(:fog_public)
90
- if @options[:fog_public].respond_to?(:has_key?) && @options[:fog_public].has_key?(style)
91
- @options[:fog_public][style]
89
+ if @options.key?(:fog_public)
90
+ value = @options[:fog_public]
91
+ if value.respond_to?(:key?) && value.key?(style)
92
+ value[style]
93
+ elsif value.respond_to?(:call)
94
+ value.call(self)
92
95
  else
93
- @options[:fog_public]
96
+ value
94
97
  end
95
98
  else
96
99
  true
@@ -45,10 +45,10 @@ module Paperclip
45
45
  #
46
46
  # You can set permission on a per style bases by doing the following:
47
47
  # :s3_permissions => {
48
- # :original => :private
48
+ # :original => "private"
49
49
  # }
50
50
  # Or globally:
51
- # :s3_permissions => :private
51
+ # :s3_permissions => "private"
52
52
  #
53
53
  # * +s3_protocol+: The protocol for the URLs generated to your S3 assets.
54
54
  # Can be either 'http', 'https', or an empty string to generate
@@ -65,6 +65,9 @@ module Paperclip
65
65
  # * +s3_host_alias+: The fully-qualified domain name (FQDN) that is the alias to the
66
66
  # S3 domain of your bucket. Used with the :s3_alias_url url interpolation. See the
67
67
  # link in the +url+ entry for more information about S3 domains and buckets.
68
+ # * +s3_prefixes_in_alias+: The number of prefixes that is prepended by
69
+ # s3_host_alias. This will remove the prefixes from the path in
70
+ # :s3_alias_url url interpolation
68
71
  # * +url+: There are four options for the S3 url. You can choose to have the bucket's name
69
72
  # placed domain-style (bucket.s3.amazonaws.com) or path-style (s3.amazonaws.com/bucket).
70
73
  # You can also specify a CNAME (which requires the CNAME to be specified as
@@ -102,6 +105,8 @@ module Paperclip
102
105
  # Redundancy Storage. RRS enables customers to reduce their
103
106
  # costs by storing non-critical, reproducible data at lower
104
107
  # levels of redundancy than Amazon S3's standard storage.
108
+ # * +use_accelerate_endpoint+: Use accelerate endpoint
109
+ # http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html
105
110
  #
106
111
  # You can set storage class on a per style bases by doing the following:
107
112
  # :s3_storage_class => {
@@ -152,10 +157,23 @@ module Paperclip
152
157
  @options[:url] = @options[:url].inspect if @options[:url].is_a?(Symbol)
153
158
 
154
159
  @http_proxy = @options[:http_proxy] || nil
160
+
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
+ @use_accelerate_endpoint = @options[:use_accelerate_endpoint]
155
167
  end
156
168
 
157
169
  Paperclip.interpolates(:s3_alias_url) do |attachment, style|
158
- "#{attachment.s3_protocol(style, true)}//#{attachment.s3_host_alias}/#{attachment.path(style).sub(%r{\A/}, "".freeze)}"
170
+ protocol = attachment.s3_protocol(style, true)
171
+ host = attachment.s3_host_alias
172
+ path = attachment.path(style).
173
+ split("/")[attachment.s3_prefixes_in_alias..-1].
174
+ join("/").
175
+ sub(%r{\A/}, "".freeze)
176
+ "#{protocol}//#{host}/#{path}"
159
177
  end unless Paperclip::Interpolations.respond_to? :s3_alias_url
160
178
  Paperclip.interpolates(:s3_path_url) do |attachment, style|
161
179
  "#{attachment.s3_protocol(style, true)}//#{attachment.s3_host_name}/#{attachment.bucket_name}/#{attachment.path(style).sub(%r{\A/}, "".freeze)}"
@@ -204,6 +222,10 @@ module Paperclip
204
222
  @s3_host_alias
205
223
  end
206
224
 
225
+ def s3_prefixes_in_alias
226
+ @s3_prefixes_in_alias ||= @options[:s3_prefixes_in_alias].to_i
227
+ end
228
+
207
229
  def s3_url_options
208
230
  s3_url_options = @options[:s3_url_options] || {}
209
231
  s3_url_options = s3_url_options.call(instance) if s3_url_options.respond_to?(:call)
@@ -232,6 +254,8 @@ module Paperclip
232
254
  config[:proxy_uri] = URI::HTTP.build(proxy_opts)
233
255
  end
234
256
 
257
+ config[:use_accelerate_endpoint] = use_accelerate_endpoint?
258
+
235
259
  [:access_key_id, :secret_access_key, :credential_provider, :credentials].each do |opt|
236
260
  config[opt] = s3_credentials[opt] if s3_credentials[opt]
237
261
  end
@@ -257,6 +281,10 @@ module Paperclip
257
281
  s3_bucket.object style_name_as_path(style_name)
258
282
  end
259
283
 
284
+ def use_accelerate_endpoint?
285
+ !!@use_accelerate_endpoint
286
+ end
287
+
260
288
  def using_http_proxy?
261
289
  !!@http_proxy
262
290
  end
@@ -3,10 +3,11 @@ module Paperclip
3
3
  class Thumbnail < Processor
4
4
 
5
5
  attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options,
6
- :source_file_options, :animated, :auto_orient
6
+ :source_file_options, :animated, :auto_orient, :frame_index
7
7
 
8
8
  # List of formats that we need to preserve animation
9
9
  ANIMATED_FORMATS = %w(gif)
10
+ MULTI_FRAME_FORMATS = %w(.mkv .avi .mp4 .mov .mpg .mpeg .gif)
10
11
 
11
12
  # Creates a Thumbnail object set to work on the +file+ given. It
12
13
  # will attempt to transform the image into one defined by +target_geometry+
@@ -25,6 +26,7 @@ module Paperclip
25
26
  # +whiny+ - whether to raise an error when processing fails. Defaults to true
26
27
  # +format+ - the desired filename extension
27
28
  # +animated+ - whether to merge all the layers in the image. Defaults to true
29
+ # +frame_index+ - the frame index of the source file to render as the thumbnail
28
30
  def initialize(file, options = {}, attachment = nil)
29
31
  super
30
32
 
@@ -41,12 +43,12 @@ module Paperclip
41
43
  if @auto_orient && @current_geometry.respond_to?(:auto_orient)
42
44
  @current_geometry.auto_orient
43
45
  end
44
-
45
46
  @source_file_options = @source_file_options.split(/\s+/) if @source_file_options.respond_to?(:split)
46
47
  @convert_options = @convert_options.split(/\s+/) if @convert_options.respond_to?(:split)
47
48
 
48
49
  @current_format = File.extname(@file.path)
49
50
  @basename = File.basename(@file.path, @current_format)
51
+ @frame_index = multi_frame_format? ? options.fetch(:frame_index, 0) : 0
50
52
  end
51
53
 
52
54
  # Returns true if the +target_geometry+ is meant to crop.
@@ -76,7 +78,12 @@ module Paperclip
76
78
 
77
79
  parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
78
80
 
79
- success = convert(parameters, :source => "#{File.expand_path(src.path)}#{'[0]' unless animated?}", :dest => File.expand_path(dst.path))
81
+ frame = animated? ? "" : "[#{@frame_index}]"
82
+ convert(
83
+ parameters,
84
+ source: "#{File.expand_path(src.path)}#{frame}",
85
+ dest: File.expand_path(dst.path),
86
+ )
80
87
  rescue Cocaine::ExitStatusError => e
81
88
  raise Paperclip::Error, "There was an error processing the thumbnail for #{@basename}" if @whiny
82
89
  rescue Cocaine::CommandNotFoundError => e
@@ -101,7 +108,10 @@ module Paperclip
101
108
 
102
109
  protected
103
110
 
104
- # Return true if the format is animated
111
+ def multi_frame_format?
112
+ MULTI_FRAME_FORMATS.include? @current_format
113
+ end
114
+
105
115
  def animated?
106
116
  @animated && (ANIMATED_FORMATS.include?(@format.to_s) || @format.blank?) && identified_as_animated?
107
117
  end
@@ -1,5 +1,5 @@
1
1
  module Paperclip
2
2
  unless defined?(Paperclip::VERSION)
3
- VERSION = "5.1.0".freeze
3
+ VERSION = "5.2.0".freeze
4
4
  end
5
5
  end
@@ -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)
@@ -35,9 +35,10 @@ 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.0.34', '< 3.0')
38
+ s.add_development_dependency('aws-sdk', '>= 2.3.0', '< 3.0')
39
39
  s.add_development_dependency('bourne')
40
- 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
41
42
  s.add_development_dependency('aruba', '~> 0.9.0')
42
43
  s.add_development_dependency('nokogiri')
43
44
  s.add_development_dependency('capybara')
@@ -48,7 +49,6 @@ Gem::Specification.new do |s|
48
49
  s.add_development_dependency('rake')
49
50
  s.add_development_dependency('fakeweb')
50
51
  s.add_development_dependency('railties')
51
- s.add_development_dependency('actionmailer', '>= 4.2.0')
52
52
  s.add_development_dependency('generator_spec')
53
53
  s.add_development_dependency('timecop')
54
54
  end
@@ -500,6 +500,7 @@ describe Paperclip::Attachment do
500
500
  @attachment.expects(:post_process).with(:thumb)
501
501
  @attachment.expects(:post_process).with(:large).never
502
502
  @attachment.assign(@file)
503
+ @attachment.save
503
504
  end
504
505
  end
505
506
 
@@ -1433,16 +1434,46 @@ describe Paperclip::Attachment do
1433
1434
  assert_nothing_raised { @dummy.avatar = @file }
1434
1435
  end
1435
1436
 
1436
- it "returns the right value when sent #avatar_fingerprint" do
1437
- @dummy.avatar = @file
1438
- 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
1439
1456
  end
1440
1457
 
1441
- it "returns the right value when saved, reloaded, and sent #avatar_fingerprint" do
1442
- @dummy.avatar = @file
1443
- @dummy.save
1444
- @dummy = Dummy.find(@dummy.id)
1445
- 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
1446
1477
  end
1447
1478
  end
1448
1479
  end
@@ -9,70 +9,93 @@ 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
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
76
99
  end
77
100
  end
78
101
  end