kt-paperclip 5.4.0 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.github/issue_template.md +3 -0
  3. data/.hound.yml +27 -32
  4. data/.travis.yml +23 -2
  5. data/Appraisals +17 -0
  6. data/Gemfile +9 -7
  7. data/NEWS +21 -0
  8. data/README.md +27 -37
  9. data/Rakefile +29 -21
  10. data/UPGRADING +3 -3
  11. data/features/basic_integration.feature +4 -0
  12. data/features/migration.feature +10 -51
  13. data/features/step_definitions/attachment_steps.rb +12 -12
  14. data/features/step_definitions/html_steps.rb +5 -5
  15. data/features/step_definitions/rails_steps.rb +29 -9
  16. data/features/step_definitions/s3_steps.rb +3 -3
  17. data/features/step_definitions/web_steps.rb +5 -6
  18. data/features/support/env.rb +4 -4
  19. data/features/support/fakeweb.rb +3 -5
  20. data/features/support/file_helpers.rb +2 -2
  21. data/features/support/paths.rb +4 -4
  22. data/features/support/rails.rb +7 -7
  23. data/features/support/selectors.rb +1 -1
  24. data/gemfiles/4.2.gemfile +7 -4
  25. data/gemfiles/5.0.gemfile +7 -4
  26. data/gemfiles/5.1.gemfile +20 -0
  27. data/gemfiles/5.2.gemfile +20 -0
  28. data/gemfiles/6.0.gemfile +20 -0
  29. data/lib/generators/paperclip/paperclip_generator.rb +6 -8
  30. data/lib/paperclip/attachment.rb +102 -104
  31. data/lib/paperclip/attachment_registry.rb +2 -2
  32. data/lib/paperclip/file_command_content_type_detector.rb +1 -3
  33. data/lib/paperclip/filename_cleaner.rb +0 -1
  34. data/lib/paperclip/geometry.rb +18 -19
  35. data/lib/paperclip/geometry_detector_factory.rb +13 -16
  36. data/lib/paperclip/geometry_parser_factory.rb +5 -5
  37. data/lib/paperclip/glue.rb +3 -3
  38. data/lib/paperclip/has_attached_file.rb +5 -4
  39. data/lib/paperclip/helpers.rb +3 -3
  40. data/lib/paperclip/interpolations.rb +42 -38
  41. data/lib/paperclip/io_adapters/abstract_adapter.rb +16 -14
  42. data/lib/paperclip/io_adapters/attachment_adapter.rb +12 -6
  43. data/lib/paperclip/io_adapters/data_uri_adapter.rb +1 -1
  44. data/lib/paperclip/io_adapters/file_adapter.rb +1 -3
  45. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +3 -3
  46. data/lib/paperclip/io_adapters/identity_adapter.rb +1 -2
  47. data/lib/paperclip/io_adapters/registry.rb +1 -1
  48. data/lib/paperclip/io_adapters/stringio_adapter.rb +1 -1
  49. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +6 -8
  50. data/lib/paperclip/io_adapters/uri_adapter.rb +9 -7
  51. data/lib/paperclip/logger.rb +1 -1
  52. data/lib/paperclip/matchers/have_attached_file_matcher.rb +4 -4
  53. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +19 -18
  54. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +4 -4
  55. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +11 -10
  56. data/lib/paperclip/matchers.rb +4 -4
  57. data/lib/paperclip/media_type_spoof_detector.rb +13 -13
  58. data/lib/paperclip/missing_attachment_styles.rb +11 -6
  59. data/lib/paperclip/processor.rb +13 -6
  60. data/lib/paperclip/processor_helpers.rb +3 -1
  61. data/lib/paperclip/rails_environment.rb +1 -5
  62. data/lib/paperclip/railtie.rb +5 -5
  63. data/lib/paperclip/schema.rb +18 -14
  64. data/lib/paperclip/storage/filesystem.rb +5 -7
  65. data/lib/paperclip/storage/fog.rb +36 -32
  66. data/lib/paperclip/storage/s3.rb +67 -75
  67. data/lib/paperclip/style.rb +3 -6
  68. data/lib/paperclip/tempfile.rb +4 -5
  69. data/lib/paperclip/tempfile_factory.rb +0 -1
  70. data/lib/paperclip/thumbnail.rb +11 -11
  71. data/lib/paperclip/url_generator.rb +5 -12
  72. data/lib/paperclip/validators/attachment_content_type_validator.rb +3 -3
  73. data/lib/paperclip/validators/attachment_file_name_validator.rb +5 -10
  74. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +1 -2
  75. data/lib/paperclip/validators/attachment_presence_validator.rb +3 -5
  76. data/lib/paperclip/validators/attachment_size_validator.rb +8 -8
  77. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +3 -1
  78. data/lib/paperclip/validators.rb +12 -13
  79. data/lib/paperclip/version.rb +1 -3
  80. data/lib/paperclip.rb +49 -48
  81. data/lib/tasks/paperclip.rake +23 -24
  82. data/paperclip.gemspec +29 -33
  83. data/shoulda_macros/paperclip.rb +16 -16
  84. data/spec/paperclip/attachment_definitions_spec.rb +5 -5
  85. data/spec/paperclip/attachment_processing_spec.rb +22 -23
  86. data/spec/paperclip/attachment_registry_spec.rb +15 -15
  87. data/spec/paperclip/attachment_spec.rb +238 -196
  88. data/spec/paperclip/content_type_detector_spec.rb +11 -12
  89. data/spec/paperclip/file_command_content_type_detector_spec.rb +10 -10
  90. data/spec/paperclip/filename_cleaner_spec.rb +3 -4
  91. data/spec/paperclip/geometry_detector_spec.rb +7 -8
  92. data/spec/paperclip/geometry_parser_spec.rb +31 -31
  93. data/spec/paperclip/geometry_spec.rb +24 -24
  94. data/spec/paperclip/glue_spec.rb +3 -5
  95. data/spec/paperclip/has_attached_file_spec.rb +46 -126
  96. data/spec/paperclip/integration_spec.rb +111 -77
  97. data/spec/paperclip/interpolations_spec.rb +101 -93
  98. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +41 -13
  99. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +8 -10
  100. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +13 -14
  101. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +4 -4
  102. data/spec/paperclip/io_adapters/file_adapter_spec.rb +12 -12
  103. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +42 -26
  104. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +1 -1
  105. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +2 -2
  106. data/spec/paperclip/io_adapters/registry_spec.rb +4 -4
  107. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +10 -10
  108. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +6 -6
  109. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +80 -31
  110. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +3 -3
  111. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +4 -5
  112. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +4 -4
  113. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +4 -4
  114. data/spec/paperclip/media_type_spoof_detector_spec.rb +50 -24
  115. data/spec/paperclip/meta_class_spec.rb +3 -3
  116. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +28 -24
  117. data/spec/paperclip/paperclip_spec.rb +15 -11
  118. data/spec/paperclip/plural_cache_spec.rb +8 -8
  119. data/spec/paperclip/processor_helpers_spec.rb +35 -35
  120. data/spec/paperclip/processor_spec.rb +8 -8
  121. data/spec/paperclip/rails_environment_spec.rb +7 -10
  122. data/spec/paperclip/rake_spec.rb +39 -39
  123. data/spec/paperclip/schema_spec.rb +57 -53
  124. data/spec/paperclip/storage/filesystem_spec.rb +6 -6
  125. data/spec/paperclip/storage/fog_spec.rb +76 -82
  126. data/spec/paperclip/storage/s3_live_spec.rb +22 -22
  127. data/spec/paperclip/storage/s3_spec.rb +585 -583
  128. data/spec/paperclip/style_spec.rb +67 -71
  129. data/spec/paperclip/tempfile_factory_spec.rb +5 -5
  130. data/spec/paperclip/thumbnail_spec.rb +68 -67
  131. data/spec/paperclip/url_generator_spec.rb +18 -29
  132. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +27 -27
  133. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +15 -16
  134. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +5 -5
  135. data/spec/paperclip/validators/attachment_size_validator_spec.rb +21 -21
  136. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +9 -13
  137. data/spec/paperclip/validators_spec.rb +40 -40
  138. data/spec/spec_helper.rb +21 -23
  139. data/spec/support/assertions.rb +8 -6
  140. data/spec/support/fake_model.rb +1 -2
  141. data/spec/support/fake_rails.rb +1 -1
  142. data/spec/support/matchers/exist.rb +1 -1
  143. data/spec/support/matchers/have_column.rb +1 -1
  144. data/spec/support/mock_url_generator_builder.rb +2 -3
  145. data/spec/support/model_reconstruction.rb +16 -12
  146. data/spec/support/reporting.rb +1 -1
  147. data/spec/support/test_data.rb +2 -2
  148. metadata +49 -105
  149. data/lib/kt-paperclip.rb +0 -1
  150. data/spec/support/conditional_filter_helper.rb +0 -5
@@ -5,31 +5,32 @@ module Paperclip
5
5
  # Paperclip.interpolates method.
6
6
  module Interpolations
7
7
  extend self
8
+ ID_PARTITION_LIMIT = 1_000_000_000
8
9
 
9
10
  # Hash assignment of interpolations. Included only for compatibility,
10
11
  # and is not intended for normal use.
11
- def self.[]= name, block
12
+ def self.[]=(name, block)
12
13
  define_method(name, &block)
13
14
  @interpolators_cache = nil
14
15
  end
15
16
 
16
17
  # Hash access of interpolations. Included only for compatibility,
17
18
  # and is not intended for normal use.
18
- def self.[] name
19
+ def self.[](name)
19
20
  method(name)
20
21
  end
21
22
 
22
23
  # Returns a sorted list of all interpolations.
23
24
  def self.all
24
- self.instance_methods(false).sort!
25
+ instance_methods(false).sort!
25
26
  end
26
27
 
27
28
  # Perform the actual interpolation. Takes the pattern to interpolate
28
29
  # and the arguments to pass, which are the attachment and style name.
29
30
  # You can pass a method name on your record as a symbol, which should turn
30
31
  # an interpolation pattern for Paperclip to use.
31
- def self.interpolate pattern, *args
32
- pattern = args.first.instance.send(pattern) if pattern.kind_of? Symbol
32
+ def self.interpolate(pattern, *args)
33
+ pattern = args.first.instance.send(pattern) if pattern.is_a? Symbol
33
34
  result = pattern.dup
34
35
  interpolators_cache.each do |method, token|
35
36
  result.gsub!(token) { send(method, *args) } if result.include?(token)
@@ -46,17 +47,17 @@ module Paperclip
46
47
  end
47
48
 
48
49
  # Returns the filename, the same way as ":basename.:extension" would.
49
- def filename attachment, style_name
50
- [ basename(attachment, style_name), extension(attachment, style_name) ].delete_if(&:empty?).join(".".freeze)
50
+ def filename(attachment, style_name)
51
+ [basename(attachment, style_name), extension(attachment, style_name)].delete_if(&:empty?).join(".")
51
52
  end
52
53
 
53
54
  # Returns the interpolated URL. Will raise an error if the url itself
54
55
  # contains ":url" to prevent infinite recursion. This interpolation
55
56
  # is used in the default :path to ease default specifications.
56
- RIGHT_HERE = "#{__FILE__.gsub(%r{\A\./}, "")}:#{__LINE__ + 3}"
57
- def url attachment, style_name
58
- raise Errors::InfiniteInterpolationError if caller.any?{|b| b.index(RIGHT_HERE) }
59
- attachment.url(style_name, :timestamp => false, :escape => false)
57
+ RIGHT_HERE = "#{__FILE__.gsub(%r{\A\./}, '')}:#{__LINE__ + 3}"
58
+ def url(attachment, style_name)
59
+ raise Errors::InfiniteInterpolationError if caller.any? { |b| b.index(RIGHT_HERE) }
60
+ attachment.url(style_name, timestamp: false, escape: false)
60
61
  end
61
62
 
62
63
  # Returns the timestamp as defined by the <attachment>_updated_at field
@@ -64,23 +65,23 @@ module Paperclip
64
65
  # to false. Note that a Rails.config.time_zone change will still
65
66
  # invalidate any path or URL that uses :timestamp. For a
66
67
  # time_zone-agnostic timestamp, use #updated_at.
67
- def timestamp attachment, style_name
68
+ def timestamp(attachment, _style_name)
68
69
  attachment.instance_read(:updated_at).in_time_zone(attachment.time_zone).to_s
69
70
  end
70
71
 
71
72
  # Returns an integer timestamp that is time zone-neutral, so that paths
72
73
  # remain valid even if a server's time zone changes.
73
- def updated_at attachment, style_name
74
+ def updated_at(attachment, _style_name)
74
75
  attachment.updated_at
75
76
  end
76
77
 
77
78
  # Returns the Rails.root constant.
78
- def rails_root attachment, style_name
79
+ def rails_root(_attachment, _style_name)
79
80
  Rails.root
80
81
  end
81
82
 
82
83
  # Returns the Rails.env constant.
83
- def rails_env attachment, style_name
84
+ def rails_env(_attachment, _style_name)
84
85
  Rails.env
85
86
  end
86
87
 
@@ -88,28 +89,29 @@ module Paperclip
88
89
  # e.g. "users" for the User class.
89
90
  # NOTE: The arguments need to be optional, because some tools fetch
90
91
  # all class names. Calling #class will return the expected class.
91
- def class attachment = nil, style_name = nil
92
+ def class(attachment = nil, style_name = nil)
92
93
  return super() if attachment.nil? && style_name.nil?
94
+
93
95
  plural_cache.underscore_and_pluralize_class(attachment.instance.class)
94
96
  end
95
97
 
96
98
  # Returns the basename of the file. e.g. "file" for "file.jpg"
97
- def basename attachment, style_name
98
- File.basename(attachment.original_filename, ".*".freeze)
99
+ def basename(attachment, _style_name)
100
+ File.basename(attachment.original_filename, ".*")
99
101
  end
100
102
 
101
103
  # Returns the extension of the file. e.g. "jpg" for "file.jpg"
102
104
  # If the style has a format defined, it will return the format instead
103
105
  # of the actual extension.
104
- def extension attachment, style_name
106
+ def extension(attachment, style_name)
105
107
  ((style = attachment.styles[style_name.to_s.to_sym]) && style[:format]) ||
106
- File.extname(attachment.original_filename).sub(/\A\.+/, "".freeze)
108
+ File.extname(attachment.original_filename).sub(/\A\.+/, "")
107
109
  end
108
110
 
109
111
  # Returns the dot+extension of the file. e.g. ".jpg" for "file.jpg"
110
112
  # If the style has a format defined, it will return the format instead
111
113
  # of the actual extension. If the extension is empty, no dot is added.
112
- def dotextension attachment, style_name
114
+ def dotextension(attachment, style_name)
113
115
  ext = extension(attachment, style_name)
114
116
  ext.empty? ? ext : ".#{ext}"
115
117
  end
@@ -121,13 +123,13 @@ module Paperclip
121
123
  # Each mime type generally has multiple extensions associated with it, so
122
124
  # if the extension from the original filename is one of these extensions,
123
125
  # that extension is used, otherwise, the first in the list is used.
124
- def content_type_extension attachment, style_name
126
+ def content_type_extension(attachment, style_name)
125
127
  mime_type = MIME::Types[attachment.content_type]
126
- extensions_for_mime_type = unless mime_type.empty?
127
- mime_type.first.extensions
128
- else
129
- []
130
- end
128
+ extensions_for_mime_type = if mime_type.empty?
129
+ []
130
+ else
131
+ mime_type.first.extensions
132
+ end
131
133
 
132
134
  original_extension = extension(attachment, style_name)
133
135
  style = attachment.styles[style_name.to_s.to_sym]
@@ -146,23 +148,23 @@ module Paperclip
146
148
  end
147
149
 
148
150
  # Returns the id of the instance.
149
- def id attachment, style_name
151
+ def id(attachment, _style_name)
150
152
  attachment.instance.id
151
153
  end
152
154
 
153
155
  # Returns the #to_param of the instance.
154
- def param attachment, style_name
156
+ def param(attachment, _style_name)
155
157
  attachment.instance.to_param
156
158
  end
157
159
 
158
160
  # Returns the fingerprint of the instance.
159
- def fingerprint attachment, style_name
161
+ def fingerprint(attachment, _style_name)
160
162
  attachment.fingerprint
161
163
  end
162
164
 
163
165
  # Returns a the attachment hash. See Paperclip::Attachment#hash_key for
164
166
  # more details.
165
- def hash attachment=nil, style_name=nil
167
+ def hash(attachment = nil, style_name = nil)
166
168
  if attachment && style_name
167
169
  attachment.hash_key(style_name)
168
170
  else
@@ -172,25 +174,27 @@ module Paperclip
172
174
 
173
175
  # Returns the id of the instance in a split path form. e.g. returns
174
176
  # 000/001/234 for an id of 1234.
175
- def id_partition attachment, style_name
177
+ def id_partition(attachment, _style_name)
176
178
  case id = attachment.instance.id
177
179
  when Integer
178
- ("%09d".freeze % id).scan(/\d{3}/).join("/".freeze)
180
+ if id < ID_PARTITION_LIMIT
181
+ ("%09d" % id).scan(/\d{3}/).join("/")
182
+ else
183
+ ("%012d" % id).scan(/\d{3}/).join("/")
184
+ end
179
185
  when String
180
- id.scan(/.{3}/).first(3).join("/".freeze)
181
- else
182
- nil
186
+ id.scan(/.{3}/).first(3).join("/")
183
187
  end
184
188
  end
185
189
 
186
190
  # Returns the pluralized form of the attachment name. e.g.
187
191
  # "avatars" for an attachment of :avatar
188
- def attachment attachment, style_name
192
+ def attachment(attachment, _style_name)
189
193
  plural_cache.pluralize_symbol(attachment.name)
190
194
  end
191
195
 
192
196
  # Returns the style, or the default style if nil is supplied.
193
- def style attachment, style_name
197
+ def style(attachment, style_name)
194
198
  style_name || attachment.default_style
195
199
  end
196
200
  end
@@ -1,11 +1,11 @@
1
- require 'active_support/core_ext/module/delegation'
1
+ require "active_support/core_ext/module/delegation"
2
2
 
3
3
  module Paperclip
4
4
  class AbstractAdapter
5
- OS_RESTRICTED_CHARACTERS = %r{[/:]}
5
+ OS_RESTRICTED_CHARACTERS = %r{[/:]}.freeze
6
6
 
7
- attr_reader :content_type, :original_filename, :size
8
- delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :readbyte, :rewind, :unlink, :to => :@tempfile
7
+ attr_reader :content_type, :original_filename, :size, :tempfile
8
+ delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :readbyte, :rewind, :unlink, to: :@tempfile
9
9
  alias :length :size
10
10
 
11
11
  def initialize(target, options = {})
@@ -29,11 +29,12 @@ module Paperclip
29
29
  end
30
30
 
31
31
  def inspect
32
- "#{self.class}: #{self.original_filename}"
32
+ "#{self.class}: #{original_filename}"
33
33
  end
34
34
 
35
35
  def original_filename=(new_filename)
36
36
  return unless new_filename
37
+
37
38
  @original_filename = new_filename.gsub(OS_RESTRICTED_CHARACTERS, "_")
38
39
  end
39
40
 
@@ -57,15 +58,16 @@ module Paperclip
57
58
  end
58
59
 
59
60
  def link_or_copy_file(src, dest)
60
- Paperclip.log("Trying to link #{src} to #{dest}")
61
- FileUtils.ln(src, dest, force: true) # overwrite existing
62
- @destination.close
63
- @destination.open.binmode
64
- rescue Errno::EXDEV, Errno::EPERM, Errno::ENOENT, Errno::EEXIST => e
65
- Paperclip.log(
66
- "Link failed with #{e.message}; copying link #{src} to #{dest}"
67
- )
68
- FileUtils.cp(src, dest)
61
+ begin
62
+ Paperclip.log("Trying to link #{src} to #{dest}")
63
+ FileUtils.ln(src, dest, force: true) # overwrite existing
64
+ rescue Errno::EXDEV, Errno::EPERM, Errno::ENOENT, Errno::EEXIST => e
65
+ Paperclip.log(
66
+ "Link failed with #{e.message}; copying link #{src} to #{dest}"
67
+ )
68
+ FileUtils.cp(src, dest)
69
+ end
70
+
69
71
  @destination.close
70
72
  @destination.open.binmode
71
73
  end
@@ -9,11 +9,11 @@ module Paperclip
9
9
  def initialize(target, options = {})
10
10
  super
11
11
  @target, @style = case target
12
- when Paperclip::Attachment
13
- [target, :original]
14
- when Paperclip::Style
15
- [target.attachment, target.name]
16
- end
12
+ when Paperclip::Attachment
13
+ [target, :original]
14
+ when Paperclip::Style
15
+ [target.attachment, target.name]
16
+ end
17
17
 
18
18
  cache_current_values
19
19
  end
@@ -31,7 +31,13 @@ module Paperclip
31
31
  if source.staged?
32
32
  link_or_copy_file(source.staged_path(@style), destination.path)
33
33
  else
34
- source.copy_to_local_file(@style, destination.path)
34
+ begin
35
+ source.copy_to_local_file(@style, destination.path)
36
+ rescue Errno::EACCES
37
+ # clean up lingering tempfile if we cannot access source file
38
+ destination.close(true)
39
+ raise
40
+ end
35
41
  end
36
42
  destination
37
43
  end
@@ -6,7 +6,7 @@ module Paperclip
6
6
  end
7
7
  end
8
8
 
9
- REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m
9
+ REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m.freeze
10
10
 
11
11
  def initialize(target_uri, options = {})
12
12
  super(extract_target(target_uri), options)
@@ -14,9 +14,7 @@ module Paperclip
14
14
  private
15
15
 
16
16
  def cache_current_values
17
- if @target.respond_to?(:original_filename)
18
- self.original_filename = @target.original_filename
19
- end
17
+ self.original_filename = @target.original_filename if @target.respond_to?(:original_filename)
20
18
  self.original_filename ||= File.basename(@target.path)
21
19
  @tempfile = copy_to_tempfile(@target)
22
20
  @content_type = ContentTypeDetector.new(@target.path).detect
@@ -6,11 +6,11 @@ module Paperclip
6
6
  end
7
7
  end
8
8
 
9
- REGEXP = /\Ahttps?:\/\//
9
+ REGEXP = /\Ahttps?:\/\//.freeze
10
10
 
11
11
  def initialize(target, options = {})
12
- escaped = Paperclip::UrlGenerator.escape(target)
13
- super(URI(target == Paperclip::UrlGenerator.unescape(target) ? escaped : target), options)
12
+ escaped = URI.escape(target)
13
+ super(URI(target == URI.unescape(target) ? escaped : target), options)
14
14
  end
15
15
  end
16
16
  end
@@ -6,8 +6,7 @@ module Paperclip
6
6
  end
7
7
  end
8
8
 
9
- def initialize
10
- end
9
+ def initialize; end
11
10
 
12
11
  def new(target, _)
13
12
  target
@@ -24,7 +24,7 @@ module Paperclip
24
24
  end
25
25
 
26
26
  def registered?(target)
27
- @registered_handlers.any? do |tester, handler|
27
+ @registered_handlers.any? do |_tester, handler|
28
28
  handler === target
29
29
  end
30
30
  end
@@ -24,7 +24,7 @@ module Paperclip
24
24
  end
25
25
 
26
26
  def copy_to_tempfile(source)
27
- while data = source.read(16*1024)
27
+ while data = source.read(16 * 1024)
28
28
  destination.write(data)
29
29
  end
30
30
  destination.rewind
@@ -10,11 +10,11 @@ module Paperclip
10
10
  super
11
11
  cache_current_values
12
12
 
13
- if @target.respond_to?(:tempfile)
14
- @tempfile = copy_to_tempfile(@target.tempfile)
15
- else
16
- @tempfile = copy_to_tempfile(@target)
17
- end
13
+ @tempfile = if @target.respond_to?(:tempfile)
14
+ copy_to_tempfile(@target.tempfile)
15
+ else
16
+ copy_to_tempfile(@target)
17
+ end
18
18
  end
19
19
 
20
20
  class << self
@@ -35,9 +35,7 @@ module Paperclip
35
35
 
36
36
  def determine_content_type
37
37
  content_type = @target.content_type.to_s.strip
38
- if content_type_detector
39
- content_type = content_type_detector.new(@target.path).detect
40
- end
38
+ content_type = content_type_detector.new(@target.path).detect if content_type_detector
41
39
  content_type
42
40
  end
43
41
  end
@@ -28,15 +28,17 @@ module Paperclip
28
28
  end
29
29
 
30
30
  def content_type_from_content
31
- if @content.respond_to?(:content_type)
32
- @content.content_type
33
- end
31
+ @content.meta["content-type"].presence
34
32
  end
35
33
 
36
34
  def filename_from_content_disposition
37
- if @content.meta.key?("content-disposition")
38
- matches = @content.meta["content-disposition"].match(/filename="([^"]*)"/)
39
- matches[1] if matches
35
+ if @content.meta.key?("content-disposition") && @content.meta["content-disposition"].match(/filename/i)
36
+ # can include both filename and filename* values according to RCF6266. filename should come first
37
+ _, filename = @content.meta["content-disposition"].split(/filename\*?\s*=\s*/i)
38
+
39
+ # filename can be enclosed in quotes or not
40
+ matches = filename.match(/"(.*)"/)
41
+ matches ? matches[1] : filename.split(";")[0]
40
42
  end
41
43
  end
42
44
 
@@ -51,7 +53,7 @@ module Paperclip
51
53
  def download_content
52
54
  options = { read_timeout: Paperclip.options[:read_timeout] }.compact
53
55
 
54
- self.open(@target, options)
56
+ open(@target, **options)
55
57
  end
56
58
 
57
59
  def copy_to_tempfile(src)
@@ -2,7 +2,7 @@ module Paperclip
2
2
  module Logger
3
3
  # Log a paperclip-specific line. This will log to STDOUT
4
4
  # by default. Set Paperclip.options[:log] to false to turn off.
5
- def log message
5
+ def log(message)
6
6
  logger.info("[paperclip] #{message}") if logging?
7
7
  end
8
8
 
@@ -8,16 +8,16 @@ module Paperclip
8
8
  # describe User do
9
9
  # it { should have_attached_file(:avatar) }
10
10
  # end
11
- def have_attached_file name
11
+ def have_attached_file(name)
12
12
  HaveAttachedFileMatcher.new(name)
13
13
  end
14
14
 
15
15
  class HaveAttachedFileMatcher
16
- def initialize attachment_name
16
+ def initialize(attachment_name)
17
17
  @attachment_name = attachment_name
18
18
  end
19
19
 
20
- def matches? subject
20
+ def matches?(subject)
21
21
  @subject = subject
22
22
  @subject = @subject.class unless Class === @subject
23
23
  responds? && has_column?
@@ -40,7 +40,7 @@ module Paperclip
40
40
 
41
41
  def responds?
42
42
  methods = @subject.instance_methods.map(&:to_s)
43
- methods.include?("#{@attachment_name}") &&
43
+ methods.include?(@attachment_name.to_s) &&
44
44
  methods.include?("#{@attachment_name}=") &&
45
45
  methods.include?("#{@attachment_name}?")
46
46
  end
@@ -10,32 +10,32 @@ module Paperclip
10
10
  # allowing('image/png', 'image/gif').
11
11
  # rejecting('text/plain', 'text/xml') }
12
12
  # end
13
- def validate_attachment_content_type name
13
+ def validate_attachment_content_type(name)
14
14
  ValidateAttachmentContentTypeMatcher.new(name)
15
15
  end
16
16
 
17
17
  class ValidateAttachmentContentTypeMatcher
18
- def initialize attachment_name
18
+ def initialize(attachment_name)
19
19
  @attachment_name = attachment_name
20
20
  @allowed_types = []
21
21
  @rejected_types = []
22
22
  end
23
23
 
24
- def allowing *types
24
+ def allowing(*types)
25
25
  @allowed_types = types.flatten
26
26
  self
27
27
  end
28
28
 
29
- def rejecting *types
29
+ def rejecting(*types)
30
30
  @rejected_types = types.flatten
31
31
  self
32
32
  end
33
33
 
34
- def matches? subject
34
+ def matches?(subject)
35
35
  @subject = subject
36
36
  @subject = @subject.new if @subject.class == Class
37
37
  @allowed_types && @rejected_types &&
38
- allowed_types_allowed? && rejected_types_rejected?
38
+ allowed_types_allowed? && rejected_types_rejected?
39
39
  end
40
40
 
41
41
  def failure_message
@@ -54,23 +54,24 @@ module Paperclip
54
54
 
55
55
  def accepted_types_and_failures
56
56
  if @allowed_types.present?
57
- "Accept content types: #{@allowed_types.join(", ")}\n".tap do |message|
58
- if @missing_allowed_types.present?
59
- message << " #{@missing_allowed_types.join(", ")} were rejected."
60
- else
61
- message << " All were accepted successfully."
62
- end
57
+ "Accept content types: #{@allowed_types.join(', ')}\n".tap do |message|
58
+ message << if @missing_allowed_types.present?
59
+ " #{@missing_allowed_types.join(', ')} were rejected."
60
+ else
61
+ " All were accepted successfully."
62
+ end
63
63
  end
64
64
  end
65
65
  end
66
+
66
67
  def rejected_types_and_failures
67
68
  if @rejected_types.present?
68
- "Reject content types: #{@rejected_types.join(", ")}\n".tap do |message|
69
- if @missing_rejected_types.present?
70
- message << " #{@missing_rejected_types.join(", ")} were accepted."
71
- else
72
- message << " All were rejected successfully."
73
- end
69
+ "Reject content types: #{@rejected_types.join(', ')}\n".tap do |message|
70
+ message << if @missing_rejected_types.present?
71
+ " #{@missing_rejected_types.join(', ')} were accepted."
72
+ else
73
+ " All were rejected successfully."
74
+ end
74
75
  end
75
76
  end
76
77
  end
@@ -7,16 +7,16 @@ module Paperclip
7
7
  # describe User do
8
8
  # it { should validate_attachment_presence(:avatar) }
9
9
  # end
10
- def validate_attachment_presence name
10
+ def validate_attachment_presence(name)
11
11
  ValidateAttachmentPresenceMatcher.new(name)
12
12
  end
13
13
 
14
14
  class ValidateAttachmentPresenceMatcher
15
- def initialize attachment_name
15
+ def initialize(attachment_name)
16
16
  @attachment_name = attachment_name
17
17
  end
18
18
 
19
- def matches? subject
19
+ def matches?(subject)
20
20
  @subject = subject
21
21
  @subject = subject.new if subject.class == Class
22
22
  error_when_not_valid? && no_error_when_valid?
@@ -50,7 +50,7 @@ module Paperclip
50
50
  expected_message = [
51
51
  @attachment_name.to_s.titleize,
52
52
  I18n.t(:blank, scope: [:errors, :messages])
53
- ].join(' ')
53
+ ].join(" ")
54
54
  @subject.errors.full_messages.exclude?(expected_message)
55
55
  end
56
56
  end
@@ -11,31 +11,32 @@ module Paperclip
11
11
  # greater_than(1024) }
12
12
  # it { should validate_attachment_size(:icon).
13
13
  # in(0..100) }
14
- def validate_attachment_size name
14
+ def validate_attachment_size(name)
15
15
  ValidateAttachmentSizeMatcher.new(name)
16
16
  end
17
17
 
18
18
  class ValidateAttachmentSizeMatcher
19
- def initialize attachment_name
19
+ def initialize(attachment_name)
20
20
  @attachment_name = attachment_name
21
21
  end
22
22
 
23
- def less_than size
23
+ def less_than(size)
24
24
  @high = size
25
25
  self
26
26
  end
27
27
 
28
- def greater_than size
28
+ def greater_than(size)
29
29
  @low = size
30
30
  self
31
31
  end
32
32
 
33
- def in range
34
- @low, @high = range.first, range.last
33
+ def in(range)
34
+ @low = range.first
35
+ @high = range.last
35
36
  self
36
37
  end
37
38
 
38
- def matches? subject
39
+ def matches?(subject)
39
40
  @subject = subject
40
41
  @subject = @subject.new if @subject.class == Class
41
42
  lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high?
@@ -56,7 +57,7 @@ module Paperclip
56
57
 
57
58
  protected
58
59
 
59
- def override_method object, method, &replacement
60
+ def override_method(object, method, &replacement)
60
61
  (class << object; self; end).class_eval do
61
62
  define_method(method, &replacement)
62
63
  end
@@ -64,8 +65,8 @@ module Paperclip
64
65
 
65
66
  def passes_validation_with_size(new_size)
66
67
  file = StringIO.new(".")
67
- override_method(file, :size){ new_size }
68
- override_method(file, :to_tempfile){ file }
68
+ override_method(file, :size) { new_size }
69
+ override_method(file, :to_tempfile) { file }
69
70
 
70
71
  @subject.send(@attachment_name).post_processing = false
71
72
  @subject.send(@attachment_name).assign(file)
@@ -1,7 +1,7 @@
1
- require 'paperclip/matchers/have_attached_file_matcher'
2
- require 'paperclip/matchers/validate_attachment_presence_matcher'
3
- require 'paperclip/matchers/validate_attachment_content_type_matcher'
4
- require 'paperclip/matchers/validate_attachment_size_matcher'
1
+ require "paperclip/matchers/have_attached_file_matcher"
2
+ require "paperclip/matchers/validate_attachment_presence_matcher"
3
+ require "paperclip/matchers/validate_attachment_content_type_matcher"
4
+ require "paperclip/matchers/validate_attachment_size_matcher"
5
5
 
6
6
  module Paperclip
7
7
  module Shoulda