paperclip-fix 4.3.7

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 (197) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.hound.yml +1066 -0
  4. data/.rubocop.yml +1 -0
  5. data/.travis.yml +22 -0
  6. data/Appraisals +11 -0
  7. data/CONTRIBUTING.md +75 -0
  8. data/Gemfile +21 -0
  9. data/LICENSE +24 -0
  10. data/NEWS +420 -0
  11. data/README.md +979 -0
  12. data/RELEASING.md +17 -0
  13. data/Rakefile +44 -0
  14. data/UPGRADING +14 -0
  15. data/cucumber/paperclip_steps.rb +6 -0
  16. data/features/basic_integration.feature +80 -0
  17. data/features/migration.feature +94 -0
  18. data/features/rake_tasks.feature +62 -0
  19. data/features/step_definitions/attachment_steps.rb +110 -0
  20. data/features/step_definitions/html_steps.rb +15 -0
  21. data/features/step_definitions/rails_steps.rb +236 -0
  22. data/features/step_definitions/s3_steps.rb +14 -0
  23. data/features/step_definitions/web_steps.rb +107 -0
  24. data/features/support/env.rb +11 -0
  25. data/features/support/fakeweb.rb +13 -0
  26. data/features/support/file_helpers.rb +34 -0
  27. data/features/support/fixtures/boot_config.txt +15 -0
  28. data/features/support/fixtures/gemfile.txt +5 -0
  29. data/features/support/fixtures/preinitializer.txt +20 -0
  30. data/features/support/paths.rb +28 -0
  31. data/features/support/rails.rb +63 -0
  32. data/features/support/selectors.rb +19 -0
  33. data/gemfiles/3.2.gemfile +19 -0
  34. data/gemfiles/4.1.gemfile +19 -0
  35. data/gemfiles/4.2.gemfile +19 -0
  36. data/lib/generators/paperclip/USAGE +8 -0
  37. data/lib/generators/paperclip/paperclip_generator.rb +30 -0
  38. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
  39. data/lib/paperclip/attachment.rb +608 -0
  40. data/lib/paperclip/attachment_registry.rb +59 -0
  41. data/lib/paperclip/callbacks.rb +40 -0
  42. data/lib/paperclip/content_type_detector.rb +79 -0
  43. data/lib/paperclip/deprecations.rb +42 -0
  44. data/lib/paperclip/errors.rb +32 -0
  45. data/lib/paperclip/file_command_content_type_detector.rb +30 -0
  46. data/lib/paperclip/filename_cleaner.rb +16 -0
  47. data/lib/paperclip/geometry.rb +158 -0
  48. data/lib/paperclip/geometry_detector_factory.rb +48 -0
  49. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  50. data/lib/paperclip/glue.rb +17 -0
  51. data/lib/paperclip/has_attached_file.rb +109 -0
  52. data/lib/paperclip/helpers.rb +56 -0
  53. data/lib/paperclip/interpolations/plural_cache.rb +18 -0
  54. data/lib/paperclip/interpolations.rb +197 -0
  55. data/lib/paperclip/io_adapters/abstract_adapter.rb +47 -0
  56. data/lib/paperclip/io_adapters/attachment_adapter.rb +36 -0
  57. data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
  58. data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
  59. data/lib/paperclip/io_adapters/file_adapter.rb +22 -0
  60. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +15 -0
  61. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -0
  62. data/lib/paperclip/io_adapters/nil_adapter.rb +34 -0
  63. data/lib/paperclip/io_adapters/registry.rb +32 -0
  64. data/lib/paperclip/io_adapters/stringio_adapter.rb +33 -0
  65. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +42 -0
  66. data/lib/paperclip/io_adapters/uri_adapter.rb +63 -0
  67. data/lib/paperclip/locales/de.yml +18 -0
  68. data/lib/paperclip/locales/en.yml +18 -0
  69. data/lib/paperclip/locales/es.yml +18 -0
  70. data/lib/paperclip/locales/ja.yml +18 -0
  71. data/lib/paperclip/locales/pt-BR.yml +18 -0
  72. data/lib/paperclip/locales/zh-CN.yml +18 -0
  73. data/lib/paperclip/locales/zh-HK.yml +18 -0
  74. data/lib/paperclip/locales/zh-TW.yml +18 -0
  75. data/lib/paperclip/logger.rb +21 -0
  76. data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
  77. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +100 -0
  78. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
  79. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +96 -0
  80. data/lib/paperclip/matchers.rb +64 -0
  81. data/lib/paperclip/media_type_spoof_detector.rb +89 -0
  82. data/lib/paperclip/missing_attachment_styles.rb +79 -0
  83. data/lib/paperclip/processor.rb +48 -0
  84. data/lib/paperclip/processor_helpers.rb +50 -0
  85. data/lib/paperclip/rails_environment.rb +25 -0
  86. data/lib/paperclip/railtie.rb +31 -0
  87. data/lib/paperclip/schema.rb +83 -0
  88. data/lib/paperclip/storage/filesystem.rb +90 -0
  89. data/lib/paperclip/storage/fog.rb +241 -0
  90. data/lib/paperclip/storage/s3.rb +440 -0
  91. data/lib/paperclip/storage.rb +3 -0
  92. data/lib/paperclip/style.rb +109 -0
  93. data/lib/paperclip/tempfile.rb +43 -0
  94. data/lib/paperclip/tempfile_factory.rb +23 -0
  95. data/lib/paperclip/thumbnail.rb +121 -0
  96. data/lib/paperclip/url_generator.rb +72 -0
  97. data/lib/paperclip/validators/attachment_content_type_validator.rb +88 -0
  98. data/lib/paperclip/validators/attachment_file_name_validator.rb +80 -0
  99. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +29 -0
  100. data/lib/paperclip/validators/attachment_presence_validator.rb +30 -0
  101. data/lib/paperclip/validators/attachment_size_validator.rb +115 -0
  102. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +27 -0
  103. data/lib/paperclip/validators.rb +74 -0
  104. data/lib/paperclip/version.rb +3 -0
  105. data/lib/paperclip.rb +213 -0
  106. data/lib/tasks/paperclip.rake +127 -0
  107. data/paperclip.gemspec +51 -0
  108. data/shoulda_macros/paperclip.rb +134 -0
  109. data/spec/database.yml +4 -0
  110. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  111. data/spec/paperclip/attachment_processing_spec.rb +82 -0
  112. data/spec/paperclip/attachment_registry_spec.rb +130 -0
  113. data/spec/paperclip/attachment_spec.rb +1494 -0
  114. data/spec/paperclip/content_type_detector_spec.rb +48 -0
  115. data/spec/paperclip/deprecations_spec.rb +65 -0
  116. data/spec/paperclip/file_command_content_type_detector_spec.rb +26 -0
  117. data/spec/paperclip/filename_cleaner_spec.rb +14 -0
  118. data/spec/paperclip/geometry_detector_spec.rb +39 -0
  119. data/spec/paperclip/geometry_parser_spec.rb +73 -0
  120. data/spec/paperclip/geometry_spec.rb +255 -0
  121. data/spec/paperclip/glue_spec.rb +44 -0
  122. data/spec/paperclip/has_attached_file_spec.rb +142 -0
  123. data/spec/paperclip/integration_spec.rb +667 -0
  124. data/spec/paperclip/interpolations_spec.rb +262 -0
  125. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +78 -0
  126. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +139 -0
  127. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +83 -0
  128. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  129. data/spec/paperclip/io_adapters/file_adapter_spec.rb +131 -0
  130. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +104 -0
  131. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  132. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
  133. data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
  134. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
  135. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
  136. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +127 -0
  137. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  138. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +99 -0
  139. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  140. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  141. data/spec/paperclip/media_type_spoof_detector_spec.rb +79 -0
  142. data/spec/paperclip/meta_class_spec.rb +30 -0
  143. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +84 -0
  144. data/spec/paperclip/paperclip_spec.rb +222 -0
  145. data/spec/paperclip/plural_cache_spec.rb +37 -0
  146. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  147. data/spec/paperclip/processor_spec.rb +26 -0
  148. data/spec/paperclip/rails_environment_spec.rb +33 -0
  149. data/spec/paperclip/rake_spec.rb +103 -0
  150. data/spec/paperclip/schema_spec.rb +248 -0
  151. data/spec/paperclip/storage/filesystem_spec.rb +79 -0
  152. data/spec/paperclip/storage/fog_spec.rb +535 -0
  153. data/spec/paperclip/storage/s3_live_spec.rb +182 -0
  154. data/spec/paperclip/storage/s3_spec.rb +1526 -0
  155. data/spec/paperclip/style_spec.rb +255 -0
  156. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  157. data/spec/paperclip/thumbnail_spec.rb +500 -0
  158. data/spec/paperclip/url_generator_spec.rb +211 -0
  159. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
  160. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +160 -0
  161. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
  162. data/spec/paperclip/validators/attachment_size_validator_spec.rb +229 -0
  163. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +52 -0
  164. data/spec/paperclip/validators_spec.rb +164 -0
  165. data/spec/spec_helper.rb +43 -0
  166. data/spec/support/assertions.rb +71 -0
  167. data/spec/support/deprecations.rb +9 -0
  168. data/spec/support/fake_model.rb +25 -0
  169. data/spec/support/fake_rails.rb +12 -0
  170. data/spec/support/fixtures/12k.png +0 -0
  171. data/spec/support/fixtures/50x50.png +0 -0
  172. data/spec/support/fixtures/5k.png +0 -0
  173. data/spec/support/fixtures/animated +0 -0
  174. data/spec/support/fixtures/animated.gif +0 -0
  175. data/spec/support/fixtures/animated.unknown +0 -0
  176. data/spec/support/fixtures/bad.png +1 -0
  177. data/spec/support/fixtures/empty.html +1 -0
  178. data/spec/support/fixtures/empty.xlsx +0 -0
  179. data/spec/support/fixtures/fog.yml +8 -0
  180. data/spec/support/fixtures/rotated.jpg +0 -0
  181. data/spec/support/fixtures/s3.yml +8 -0
  182. data/spec/support/fixtures/spaced file.jpg +0 -0
  183. data/spec/support/fixtures/spaced file.png +0 -0
  184. data/spec/support/fixtures/text.txt +1 -0
  185. data/spec/support/fixtures/twopage.pdf +0 -0
  186. data/spec/support/fixtures/uppercase.PNG +0 -0
  187. data/spec/support/matchers/accept.rb +5 -0
  188. data/spec/support/matchers/exist.rb +5 -0
  189. data/spec/support/matchers/have_column.rb +23 -0
  190. data/spec/support/mock_attachment.rb +22 -0
  191. data/spec/support/mock_interpolator.rb +24 -0
  192. data/spec/support/mock_url_generator_builder.rb +27 -0
  193. data/spec/support/model_reconstruction.rb +60 -0
  194. data/spec/support/rails_helpers.rb +7 -0
  195. data/spec/support/test_data.rb +13 -0
  196. data/spec/support/version_helper.rb +9 -0
  197. metadata +606 -0
@@ -0,0 +1,197 @@
1
+ module Paperclip
2
+ # This module contains all the methods that are available for interpolation
3
+ # in paths and urls. To add your own (or override an existing one), you
4
+ # can either open this module and define it, or call the
5
+ # Paperclip.interpolates method.
6
+ module Interpolations
7
+ extend self
8
+
9
+ # Hash assignment of interpolations. Included only for compatibility,
10
+ # and is not intended for normal use.
11
+ def self.[]= name, block
12
+ define_method(name, &block)
13
+ @interpolators_cache = nil
14
+ end
15
+
16
+ # Hash access of interpolations. Included only for compatibility,
17
+ # and is not intended for normal use.
18
+ def self.[] name
19
+ method(name)
20
+ end
21
+
22
+ # Returns a sorted list of all interpolations.
23
+ def self.all
24
+ self.instance_methods(false).sort!
25
+ end
26
+
27
+ # Perform the actual interpolation. Takes the pattern to interpolate
28
+ # and the arguments to pass, which are the attachment and style name.
29
+ # You can pass a method name on your record as a symbol, which should turn
30
+ # 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
33
+ result = pattern.dup
34
+ interpolators_cache.each do |method, token|
35
+ result.gsub!(token) { send(method, *args) } if result.include?(token)
36
+ end
37
+ result
38
+ end
39
+
40
+ def self.interpolators_cache
41
+ @interpolators_cache ||= all.reverse!.map! { |method| [method, ":#{method}"] }
42
+ end
43
+
44
+ def self.plural_cache
45
+ @plural_cache ||= PluralCache.new
46
+ end
47
+
48
+ # 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)
51
+ end
52
+
53
+ # Returns the interpolated URL. Will raise an error if the url itself
54
+ # contains ":url" to prevent infinite recursion. This interpolation
55
+ # 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)
60
+ end
61
+
62
+ # Returns the timestamp as defined by the <attachment>_updated_at field
63
+ # in the server default time zone unless :use_global_time_zone is set
64
+ # to false. Note that a Rails.config.time_zone change will still
65
+ # invalidate any path or URL that uses :timestamp. For a
66
+ # time_zone-agnostic timestamp, use #updated_at.
67
+ def timestamp attachment, style_name
68
+ attachment.instance_read(:updated_at).in_time_zone(attachment.time_zone).to_s
69
+ end
70
+
71
+ # Returns an integer timestamp that is time zone-neutral, so that paths
72
+ # remain valid even if a server's time zone changes.
73
+ def updated_at attachment, style_name
74
+ attachment.updated_at
75
+ end
76
+
77
+ # Returns the Rails.root constant.
78
+ def rails_root attachment, style_name
79
+ Rails.root
80
+ end
81
+
82
+ # Returns the Rails.env constant.
83
+ def rails_env attachment, style_name
84
+ Rails.env
85
+ end
86
+
87
+ # Returns the underscored, pluralized version of the class name.
88
+ # e.g. "users" for the User class.
89
+ # NOTE: The arguments need to be optional, because some tools fetch
90
+ # all class names. Calling #class will return the expected class.
91
+ def class attachment = nil, style_name = nil
92
+ return super() if attachment.nil? && style_name.nil?
93
+ plural_cache.underscore_and_pluralize_class(attachment.instance.class)
94
+ end
95
+
96
+ # 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
+ end
100
+
101
+ # Returns the extension of the file. e.g. "jpg" for "file.jpg"
102
+ # If the style has a format defined, it will return the format instead
103
+ # of the actual extension.
104
+ def extension attachment, style_name
105
+ ((style = attachment.styles[style_name.to_s.to_sym]) && style[:format]) ||
106
+ File.extname(attachment.original_filename).sub(/\A\.+/, "".freeze)
107
+ end
108
+
109
+ # Returns the dot+extension of the file. e.g. ".jpg" for "file.jpg"
110
+ # If the style has a format defined, it will return the format instead
111
+ # of the actual extension. If the extension is empty, no dot is added.
112
+ def dotextension attachment, style_name
113
+ ext = extension(attachment, style_name)
114
+ ext.empty? ? ext : ".#{ext}"
115
+ end
116
+
117
+ # Returns an extension based on the content type. e.g. "jpeg" for
118
+ # "image/jpeg". If the style has a specified format, it will override the
119
+ # content-type detection.
120
+ #
121
+ # Each mime type generally has multiple extensions associated with it, so
122
+ # if the extension from the original filename is one of these extensions,
123
+ # that extension is used, otherwise, the first in the list is used.
124
+ def content_type_extension attachment, style_name
125
+ 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
131
+
132
+ original_extension = extension(attachment, style_name)
133
+ style = attachment.styles[style_name.to_s.to_sym]
134
+ if style && style[:format]
135
+ style[:format].to_s
136
+ elsif extensions_for_mime_type.include? original_extension
137
+ original_extension
138
+ elsif !extensions_for_mime_type.empty?
139
+ extensions_for_mime_type.first
140
+ else
141
+ # It's possible, though unlikely, that the mime type is not in the
142
+ # database, so just use the part after the '/' in the mime type as the
143
+ # extension.
144
+ %r{/([^/]*)\Z}.match(attachment.content_type)[1]
145
+ end
146
+ end
147
+
148
+ # Returns the id of the instance.
149
+ def id attachment, style_name
150
+ attachment.instance.id
151
+ end
152
+
153
+ # Returns the #to_param of the instance.
154
+ def param attachment, style_name
155
+ attachment.instance.to_param
156
+ end
157
+
158
+ # Returns the fingerprint of the instance.
159
+ def fingerprint attachment, style_name
160
+ attachment.fingerprint
161
+ end
162
+
163
+ # Returns a the attachment hash. See Paperclip::Attachment#hash_key for
164
+ # more details.
165
+ def hash attachment=nil, style_name=nil
166
+ if attachment && style_name
167
+ attachment.hash_key(style_name)
168
+ else
169
+ super()
170
+ end
171
+ end
172
+
173
+ # Returns the id of the instance in a split path form. e.g. returns
174
+ # 000/001/234 for an id of 1234.
175
+ def id_partition attachment, style_name
176
+ case id = attachment.instance.id
177
+ when Integer
178
+ ("%09d".freeze % id).scan(/\d{3}/).join("/".freeze)
179
+ when String
180
+ id.scan(/.{3}/).first(3).join("/".freeze)
181
+ else
182
+ nil
183
+ end
184
+ end
185
+
186
+ # Returns the pluralized form of the attachment name. e.g.
187
+ # "avatars" for an attachment of :avatar
188
+ def attachment attachment, style_name
189
+ plural_cache.pluralize_symbol(attachment.name)
190
+ end
191
+
192
+ # Returns the style, or the default style if nil is supplied.
193
+ def style attachment, style_name
194
+ style_name || attachment.default_style
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,47 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module Paperclip
4
+ class AbstractAdapter
5
+ OS_RESTRICTED_CHARACTERS = %r{[/:]}
6
+
7
+ attr_reader :content_type, :original_filename, :size
8
+ delegate :binmode, :binmode?, :close, :close!, :closed?, :eof?, :path, :rewind, :unlink, :to => :@tempfile
9
+ alias :length :size
10
+
11
+ def fingerprint
12
+ @fingerprint ||= Digest::MD5.file(path).to_s
13
+ end
14
+
15
+ def read(length = nil, buffer = nil)
16
+ @tempfile.read(length, buffer)
17
+ end
18
+
19
+ def inspect
20
+ "#{self.class}: #{self.original_filename}"
21
+ end
22
+
23
+ def original_filename=(new_filename)
24
+ return unless new_filename
25
+ @original_filename = new_filename.gsub(OS_RESTRICTED_CHARACTERS, "_")
26
+ end
27
+
28
+ def nil?
29
+ false
30
+ end
31
+
32
+ def assignment?
33
+ true
34
+ end
35
+
36
+ private
37
+
38
+ def destination
39
+ @destination ||= TempfileFactory.new.generate(@original_filename.to_s)
40
+ end
41
+
42
+ def copy_to_tempfile(src)
43
+ FileUtils.cp(src.path, destination.path)
44
+ destination
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,36 @@
1
+ module Paperclip
2
+ class AttachmentAdapter < AbstractAdapter
3
+ def initialize(target)
4
+ @target, @style = case target
5
+ when Paperclip::Attachment
6
+ [target, :original]
7
+ when Paperclip::Style
8
+ [target.attachment, target.name]
9
+ end
10
+
11
+ cache_current_values
12
+ end
13
+
14
+ private
15
+
16
+ def cache_current_values
17
+ self.original_filename = @target.original_filename
18
+ @content_type = @target.content_type
19
+ @tempfile = copy_to_tempfile(@target)
20
+ @size = @tempfile.size || @target.size
21
+ end
22
+
23
+ def copy_to_tempfile(source)
24
+ if source.staged?
25
+ FileUtils.cp(source.staged_path(@style), destination.path)
26
+ else
27
+ source.copy_to_local_file(@style, destination.path)
28
+ end
29
+ destination
30
+ end
31
+ end
32
+ end
33
+
34
+ Paperclip.io_adapters.register Paperclip::AttachmentAdapter do |target|
35
+ Paperclip::Attachment === target || Paperclip::Style === target
36
+ end
@@ -0,0 +1,22 @@
1
+ module Paperclip
2
+ class DataUriAdapter < StringioAdapter
3
+
4
+ REGEXP = /\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)/m
5
+
6
+ def initialize(target_uri)
7
+ super(extract_target(target_uri))
8
+ end
9
+
10
+ private
11
+
12
+ def extract_target(uri)
13
+ data_uri_parts = uri.match(REGEXP) || []
14
+ StringIO.new(Base64.decode64(data_uri_parts[2] || ''))
15
+ end
16
+
17
+ end
18
+ end
19
+
20
+ Paperclip.io_adapters.register Paperclip::DataUriAdapter do |target|
21
+ String === target && target =~ Paperclip::DataUriAdapter::REGEXP
22
+ end
@@ -0,0 +1,18 @@
1
+ module Paperclip
2
+ class EmptyStringAdapter < AbstractAdapter
3
+ def initialize(target)
4
+ end
5
+
6
+ def nil?
7
+ false
8
+ end
9
+
10
+ def assignment?
11
+ false
12
+ end
13
+ end
14
+ end
15
+
16
+ Paperclip.io_adapters.register Paperclip::EmptyStringAdapter do |target|
17
+ target.is_a?(String) && target.empty?
18
+ end
@@ -0,0 +1,22 @@
1
+ module Paperclip
2
+ class FileAdapter < AbstractAdapter
3
+ def initialize(target)
4
+ @target = target
5
+ cache_current_values
6
+ end
7
+
8
+ private
9
+
10
+ def cache_current_values
11
+ self.original_filename = @target.original_filename if @target.respond_to?(:original_filename)
12
+ self.original_filename ||= File.basename(@target.path)
13
+ @tempfile = copy_to_tempfile(@target)
14
+ @content_type = ContentTypeDetector.new(@target.path).detect
15
+ @size = File.size(@target)
16
+ end
17
+ end
18
+ end
19
+
20
+ Paperclip.io_adapters.register Paperclip::FileAdapter do |target|
21
+ File === target || Tempfile === target
22
+ end
@@ -0,0 +1,15 @@
1
+ module Paperclip
2
+ class HttpUrlProxyAdapter < UriAdapter
3
+
4
+ REGEXP = /\Ahttps?:\/\//
5
+
6
+ def initialize(target)
7
+ super(URI(target))
8
+ end
9
+
10
+ end
11
+ end
12
+
13
+ Paperclip.io_adapters.register Paperclip::HttpUrlProxyAdapter do |target|
14
+ String === target && target =~ Paperclip::HttpUrlProxyAdapter::REGEXP
15
+ end
@@ -0,0 +1,12 @@
1
+ module Paperclip
2
+ class IdentityAdapter < AbstractAdapter
3
+ def new(adapter)
4
+ adapter
5
+ end
6
+ end
7
+ end
8
+
9
+ Paperclip.io_adapters.register Paperclip::IdentityAdapter.new do |target|
10
+ Paperclip.io_adapters.registered?(target)
11
+ end
12
+
@@ -0,0 +1,34 @@
1
+ module Paperclip
2
+ class NilAdapter < AbstractAdapter
3
+ def initialize(target)
4
+ end
5
+
6
+ def original_filename
7
+ ""
8
+ end
9
+
10
+ def content_type
11
+ ""
12
+ end
13
+
14
+ def size
15
+ 0
16
+ end
17
+
18
+ def nil?
19
+ true
20
+ end
21
+
22
+ def read(*args)
23
+ nil
24
+ end
25
+
26
+ def eof?
27
+ true
28
+ end
29
+ end
30
+ end
31
+
32
+ Paperclip.io_adapters.register Paperclip::NilAdapter do |target|
33
+ target.nil? || ( (Paperclip::Attachment === target) && !target.present? )
34
+ end
@@ -0,0 +1,32 @@
1
+ module Paperclip
2
+ class AdapterRegistry
3
+ class NoHandlerError < Paperclip::Error; end
4
+
5
+ attr_reader :registered_handlers
6
+
7
+ def initialize
8
+ @registered_handlers = []
9
+ end
10
+
11
+ def register(handler_class, &block)
12
+ @registered_handlers << [block, handler_class]
13
+ end
14
+
15
+ def handler_for(target)
16
+ @registered_handlers.each do |tester, handler|
17
+ return handler if tester.call(target)
18
+ end
19
+ raise NoHandlerError.new("No handler found for #{target.inspect}")
20
+ end
21
+
22
+ def registered?(target)
23
+ @registered_handlers.any? do |tester, handler|
24
+ handler === target
25
+ end
26
+ end
27
+
28
+ def for(target)
29
+ handler_for(target).new(target)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ module Paperclip
2
+ class StringioAdapter < AbstractAdapter
3
+ def initialize(target)
4
+ @target = target
5
+ cache_current_values
6
+ end
7
+
8
+ attr_writer :content_type
9
+
10
+ private
11
+
12
+ def cache_current_values
13
+ self.original_filename = @target.original_filename if @target.respond_to?(:original_filename)
14
+ self.original_filename ||= "data"
15
+ @tempfile = copy_to_tempfile(@target)
16
+ @content_type = ContentTypeDetector.new(@tempfile.path).detect
17
+ @size = @target.size
18
+ end
19
+
20
+ def copy_to_tempfile(source)
21
+ while data = source.read(16*1024)
22
+ destination.write(data)
23
+ end
24
+ destination.rewind
25
+ destination
26
+ end
27
+
28
+ end
29
+ end
30
+
31
+ Paperclip.io_adapters.register Paperclip::StringioAdapter do |target|
32
+ StringIO === target
33
+ end
@@ -0,0 +1,42 @@
1
+ module Paperclip
2
+ class UploadedFileAdapter < AbstractAdapter
3
+ def initialize(target)
4
+ @target = target
5
+ cache_current_values
6
+
7
+ if @target.respond_to?(:tempfile)
8
+ @tempfile = copy_to_tempfile(@target.tempfile)
9
+ else
10
+ @tempfile = copy_to_tempfile(@target)
11
+ end
12
+ end
13
+
14
+ class << self
15
+ attr_accessor :content_type_detector
16
+ end
17
+
18
+ private
19
+
20
+ def cache_current_values
21
+ self.original_filename = @target.original_filename
22
+ @content_type = determine_content_type
23
+ @size = File.size(@target.path)
24
+ end
25
+
26
+ def content_type_detector
27
+ self.class.content_type_detector
28
+ end
29
+
30
+ def determine_content_type
31
+ content_type = @target.content_type.to_s.strip
32
+ if content_type_detector
33
+ content_type = content_type_detector.new(@target.path).detect
34
+ end
35
+ content_type
36
+ end
37
+ end
38
+ end
39
+
40
+ Paperclip.io_adapters.register Paperclip::UploadedFileAdapter do |target|
41
+ target.class.name.include?("UploadedFile")
42
+ end
@@ -0,0 +1,63 @@
1
+ require 'open-uri'
2
+
3
+ module Paperclip
4
+ class UriAdapter < AbstractAdapter
5
+ attr_writer :content_type
6
+
7
+ def initialize(target)
8
+ @target = target
9
+ @content = download_content
10
+ cache_current_values
11
+ @tempfile = copy_to_tempfile(@content)
12
+ end
13
+
14
+ private
15
+
16
+ def cache_current_values
17
+ self.content_type = content_type_from_content || "text/html"
18
+
19
+ self.original_filename = filename_from_content_disposition ||
20
+ filename_from_path ||
21
+ default_filename
22
+ @size = @content.size
23
+ end
24
+
25
+ def content_type_from_content
26
+ if @content.respond_to?(:content_type)
27
+ @content.content_type
28
+ end
29
+ end
30
+
31
+ def filename_from_content_disposition
32
+ if @content.meta.has_key?("content-disposition")
33
+ @content.meta["content-disposition"].
34
+ match(/filename="([^"]*)"/)[1]
35
+ end
36
+ end
37
+
38
+ def filename_from_path
39
+ @target.path.split("/").last
40
+ end
41
+
42
+ def default_filename
43
+ "index.html"
44
+ end
45
+
46
+ def download_content
47
+ open(@target)
48
+ end
49
+
50
+ def copy_to_tempfile(src)
51
+ while data = src.read(16*1024)
52
+ destination.write(data)
53
+ end
54
+ src.close
55
+ destination.rewind
56
+ destination
57
+ end
58
+ end
59
+ end
60
+
61
+ Paperclip.io_adapters.register Paperclip::UriAdapter do |target|
62
+ target.kind_of?(URI)
63
+ end
@@ -0,0 +1,18 @@
1
+ de:
2
+ errors:
3
+ messages:
4
+ in_between: "muss zwischen %{min} und %{max} sein"
5
+ spoofed_media_type: "trägt eine Dateiendung, die nicht mit dem Inhalt der Datei übereinstimmt"
6
+
7
+ number:
8
+ human:
9
+ storage_units:
10
+ format: "%n %u"
11
+ units:
12
+ byte:
13
+ one: "Byte"
14
+ other: "Bytes"
15
+ kb: "KB"
16
+ mb: "MB"
17
+ gb: "GB"
18
+ tb: "TB"
@@ -0,0 +1,18 @@
1
+ en:
2
+ errors:
3
+ messages:
4
+ in_between: "must be in between %{min} and %{max}"
5
+ spoofed_media_type: "has contents that are not what they are reported to be"
6
+
7
+ number:
8
+ human:
9
+ storage_units:
10
+ format: "%n %u"
11
+ units:
12
+ byte:
13
+ one: "Byte"
14
+ other: "Bytes"
15
+ kb: "KB"
16
+ mb: "MB"
17
+ gb: "GB"
18
+ tb: "TB"
@@ -0,0 +1,18 @@
1
+ es:
2
+ errors:
3
+ messages:
4
+ in_between: "debe estar entre %{min} y %{max}"
5
+ spoofed_media_type: "tiene una extensión que no coincide con su contenido"
6
+
7
+ number:
8
+ human:
9
+ storage_units:
10
+ format: "%n %u"
11
+ units:
12
+ byte:
13
+ one: "Byte"
14
+ other: "Bytes"
15
+ kb: "KB"
16
+ mb: "MB"
17
+ gb: "GB"
18
+ tb: "TB"
@@ -0,0 +1,18 @@
1
+ ja:
2
+ errors:
3
+ messages:
4
+ in_between: "の容量は%{min}以上%{max}以下にしてください。"
5
+ spoofed_media_type: "の拡張子と内容が一致していません。"
6
+
7
+ number:
8
+ human:
9
+ storage_units:
10
+ format: "%n %u"
11
+ units:
12
+ byte:
13
+ one: "Byte"
14
+ other: "Bytes"
15
+ kb: "KB"
16
+ mb: "MB"
17
+ gb: "GB"
18
+ tb: "TB"
@@ -0,0 +1,18 @@
1
+ pt-BR:
2
+ errors:
3
+ messages:
4
+ in_between: "deve ter entre %{min} e %{max}"
5
+ spoofed_media_type: "tem uma extensão que não corresponde ao seu conteúdo"
6
+
7
+ number:
8
+ human:
9
+ storage_units:
10
+ format: "%n %u"
11
+ units:
12
+ byte:
13
+ one: "Byte"
14
+ other: "Bytes"
15
+ kb: "KB"
16
+ mb: "MB"
17
+ gb: "GB"
18
+ tb: "TB"