paperclip_jk 5.0.0.beta2

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 (190) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +21 -0
  3. data/.hound.yml +1066 -0
  4. data/.rubocop.yml +1 -0
  5. data/.travis.yml +26 -0
  6. data/Appraisals +27 -0
  7. data/CONTRIBUTING.md +86 -0
  8. data/Gemfile +15 -0
  9. data/LICENSE +24 -0
  10. data/NEWS +424 -0
  11. data/README.md +999 -0
  12. data/RELEASING.md +17 -0
  13. data/Rakefile +44 -0
  14. data/UPGRADING +17 -0
  15. data/features/basic_integration.feature +81 -0
  16. data/features/migration.feature +70 -0
  17. data/features/rake_tasks.feature +62 -0
  18. data/features/step_definitions/attachment_steps.rb +110 -0
  19. data/features/step_definitions/html_steps.rb +15 -0
  20. data/features/step_definitions/rails_steps.rb +230 -0
  21. data/features/step_definitions/s3_steps.rb +14 -0
  22. data/features/step_definitions/web_steps.rb +107 -0
  23. data/features/support/env.rb +11 -0
  24. data/features/support/fakeweb.rb +13 -0
  25. data/features/support/file_helpers.rb +34 -0
  26. data/features/support/fixtures/boot_config.txt +15 -0
  27. data/features/support/fixtures/gemfile.txt +5 -0
  28. data/features/support/fixtures/preinitializer.txt +20 -0
  29. data/features/support/paths.rb +28 -0
  30. data/features/support/rails.rb +63 -0
  31. data/features/support/selectors.rb +19 -0
  32. data/gemfiles/4.2.awsv2.0.gemfile +17 -0
  33. data/gemfiles/4.2.awsv2.1.gemfile +17 -0
  34. data/gemfiles/4.2.awsv2.gemfile +20 -0
  35. data/gemfiles/5.0.awsv2.0.gemfile +17 -0
  36. data/gemfiles/5.0.awsv2.1.gemfile +17 -0
  37. data/gemfiles/5.0.awsv2.gemfile +25 -0
  38. data/lib/generators/paperclip/USAGE +8 -0
  39. data/lib/generators/paperclip/paperclip_generator.rb +30 -0
  40. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +15 -0
  41. data/lib/paperclip.rb +211 -0
  42. data/lib/paperclip/attachment.rb +610 -0
  43. data/lib/paperclip/attachment_registry.rb +60 -0
  44. data/lib/paperclip/callbacks.rb +42 -0
  45. data/lib/paperclip/content_type_detector.rb +80 -0
  46. data/lib/paperclip/errors.rb +34 -0
  47. data/lib/paperclip/file_command_content_type_detector.rb +30 -0
  48. data/lib/paperclip/filename_cleaner.rb +16 -0
  49. data/lib/paperclip/geometry.rb +158 -0
  50. data/lib/paperclip/geometry_detector_factory.rb +48 -0
  51. data/lib/paperclip/geometry_parser_factory.rb +31 -0
  52. data/lib/paperclip/glue.rb +17 -0
  53. data/lib/paperclip/has_attached_file.rb +115 -0
  54. data/lib/paperclip/helpers.rb +60 -0
  55. data/lib/paperclip/interpolations.rb +197 -0
  56. data/lib/paperclip/interpolations/plural_cache.rb +18 -0
  57. data/lib/paperclip/io_adapters/abstract_adapter.rb +47 -0
  58. data/lib/paperclip/io_adapters/attachment_adapter.rb +36 -0
  59. data/lib/paperclip/io_adapters/data_uri_adapter.rb +22 -0
  60. data/lib/paperclip/io_adapters/empty_string_adapter.rb +18 -0
  61. data/lib/paperclip/io_adapters/file_adapter.rb +22 -0
  62. data/lib/paperclip/io_adapters/http_url_proxy_adapter.rb +15 -0
  63. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -0
  64. data/lib/paperclip/io_adapters/nil_adapter.rb +34 -0
  65. data/lib/paperclip/io_adapters/registry.rb +32 -0
  66. data/lib/paperclip/io_adapters/stringio_adapter.rb +33 -0
  67. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +42 -0
  68. data/lib/paperclip/io_adapters/uri_adapter.rb +44 -0
  69. data/lib/paperclip/locales/en.yml +18 -0
  70. data/lib/paperclip/logger.rb +21 -0
  71. data/lib/paperclip/matchers.rb +64 -0
  72. data/lib/paperclip/matchers/have_attached_file_matcher.rb +54 -0
  73. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +100 -0
  74. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +59 -0
  75. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +96 -0
  76. data/lib/paperclip/media_type_spoof_detector.rb +89 -0
  77. data/lib/paperclip/missing_attachment_styles.rb +79 -0
  78. data/lib/paperclip/processor.rb +48 -0
  79. data/lib/paperclip/processor_helpers.rb +50 -0
  80. data/lib/paperclip/rails_environment.rb +25 -0
  81. data/lib/paperclip/railtie.rb +31 -0
  82. data/lib/paperclip/schema.rb +77 -0
  83. data/lib/paperclip/storage.rb +4 -0
  84. data/lib/paperclip/storage/database.rb +140 -0
  85. data/lib/paperclip/storage/filesystem.rb +90 -0
  86. data/lib/paperclip/storage/fog.rb +244 -0
  87. data/lib/paperclip/storage/s3.rb +442 -0
  88. data/lib/paperclip/style.rb +109 -0
  89. data/lib/paperclip/tempfile.rb +43 -0
  90. data/lib/paperclip/tempfile_factory.rb +23 -0
  91. data/lib/paperclip/thumbnail.rb +121 -0
  92. data/lib/paperclip/url_generator.rb +72 -0
  93. data/lib/paperclip/validators.rb +74 -0
  94. data/lib/paperclip/validators/attachment_content_type_validator.rb +88 -0
  95. data/lib/paperclip/validators/attachment_file_name_validator.rb +80 -0
  96. data/lib/paperclip/validators/attachment_file_type_ignorance_validator.rb +29 -0
  97. data/lib/paperclip/validators/attachment_presence_validator.rb +30 -0
  98. data/lib/paperclip/validators/attachment_size_validator.rb +109 -0
  99. data/lib/paperclip/validators/media_type_spoof_detection_validator.rb +27 -0
  100. data/lib/paperclip/version.rb +3 -0
  101. data/lib/tasks/paperclip.rake +127 -0
  102. data/paperclip.gemspec +54 -0
  103. data/shoulda_macros/paperclip.rb +134 -0
  104. data/spec/database.yml +4 -0
  105. data/spec/paperclip/attachment_definitions_spec.rb +13 -0
  106. data/spec/paperclip/attachment_processing_spec.rb +80 -0
  107. data/spec/paperclip/attachment_registry_spec.rb +158 -0
  108. data/spec/paperclip/attachment_spec.rb +1517 -0
  109. data/spec/paperclip/content_type_detector_spec.rb +48 -0
  110. data/spec/paperclip/file_command_content_type_detector_spec.rb +26 -0
  111. data/spec/paperclip/filename_cleaner_spec.rb +14 -0
  112. data/spec/paperclip/geometry_detector_spec.rb +39 -0
  113. data/spec/paperclip/geometry_parser_spec.rb +73 -0
  114. data/spec/paperclip/geometry_spec.rb +255 -0
  115. data/spec/paperclip/glue_spec.rb +44 -0
  116. data/spec/paperclip/has_attached_file_spec.rb +158 -0
  117. data/spec/paperclip/integration_spec.rb +668 -0
  118. data/spec/paperclip/interpolations_spec.rb +262 -0
  119. data/spec/paperclip/io_adapters/abstract_adapter_spec.rb +78 -0
  120. data/spec/paperclip/io_adapters/attachment_adapter_spec.rb +139 -0
  121. data/spec/paperclip/io_adapters/data_uri_adapter_spec.rb +83 -0
  122. data/spec/paperclip/io_adapters/empty_string_adapter_spec.rb +17 -0
  123. data/spec/paperclip/io_adapters/file_adapter_spec.rb +131 -0
  124. data/spec/paperclip/io_adapters/http_url_proxy_adapter_spec.rb +113 -0
  125. data/spec/paperclip/io_adapters/identity_adapter_spec.rb +8 -0
  126. data/spec/paperclip/io_adapters/nil_adapter_spec.rb +25 -0
  127. data/spec/paperclip/io_adapters/registry_spec.rb +35 -0
  128. data/spec/paperclip/io_adapters/stringio_adapter_spec.rb +64 -0
  129. data/spec/paperclip/io_adapters/uploaded_file_adapter_spec.rb +146 -0
  130. data/spec/paperclip/io_adapters/uri_adapter_spec.rb +102 -0
  131. data/spec/paperclip/matchers/have_attached_file_matcher_spec.rb +19 -0
  132. data/spec/paperclip/matchers/validate_attachment_content_type_matcher_spec.rb +109 -0
  133. data/spec/paperclip/matchers/validate_attachment_presence_matcher_spec.rb +69 -0
  134. data/spec/paperclip/matchers/validate_attachment_size_matcher_spec.rb +88 -0
  135. data/spec/paperclip/media_type_spoof_detector_spec.rb +70 -0
  136. data/spec/paperclip/meta_class_spec.rb +30 -0
  137. data/spec/paperclip/paperclip_missing_attachment_styles_spec.rb +84 -0
  138. data/spec/paperclip/paperclip_spec.rb +192 -0
  139. data/spec/paperclip/plural_cache_spec.rb +37 -0
  140. data/spec/paperclip/processor_helpers_spec.rb +57 -0
  141. data/spec/paperclip/processor_spec.rb +26 -0
  142. data/spec/paperclip/rails_environment_spec.rb +33 -0
  143. data/spec/paperclip/rake_spec.rb +103 -0
  144. data/spec/paperclip/schema_spec.rb +248 -0
  145. data/spec/paperclip/storage/filesystem_spec.rb +79 -0
  146. data/spec/paperclip/storage/fog_spec.rb +545 -0
  147. data/spec/paperclip/storage/s3_live_spec.rb +186 -0
  148. data/spec/paperclip/storage/s3_spec.rb +1583 -0
  149. data/spec/paperclip/style_spec.rb +255 -0
  150. data/spec/paperclip/tempfile_factory_spec.rb +33 -0
  151. data/spec/paperclip/thumbnail_spec.rb +500 -0
  152. data/spec/paperclip/url_generator_spec.rb +211 -0
  153. data/spec/paperclip/validators/attachment_content_type_validator_spec.rb +322 -0
  154. data/spec/paperclip/validators/attachment_file_name_validator_spec.rb +160 -0
  155. data/spec/paperclip/validators/attachment_presence_validator_spec.rb +85 -0
  156. data/spec/paperclip/validators/attachment_size_validator_spec.rb +235 -0
  157. data/spec/paperclip/validators/media_type_spoof_detection_validator_spec.rb +52 -0
  158. data/spec/paperclip/validators_spec.rb +164 -0
  159. data/spec/spec_helper.rb +45 -0
  160. data/spec/support/assertions.rb +78 -0
  161. data/spec/support/fake_model.rb +25 -0
  162. data/spec/support/fake_rails.rb +12 -0
  163. data/spec/support/fixtures/12k.png +0 -0
  164. data/spec/support/fixtures/50x50.png +0 -0
  165. data/spec/support/fixtures/5k.png +0 -0
  166. data/spec/support/fixtures/animated +0 -0
  167. data/spec/support/fixtures/animated.gif +0 -0
  168. data/spec/support/fixtures/animated.unknown +0 -0
  169. data/spec/support/fixtures/bad.png +1 -0
  170. data/spec/support/fixtures/empty.html +1 -0
  171. data/spec/support/fixtures/empty.xlsx +0 -0
  172. data/spec/support/fixtures/fog.yml +8 -0
  173. data/spec/support/fixtures/rotated.jpg +0 -0
  174. data/spec/support/fixtures/s3.yml +8 -0
  175. data/spec/support/fixtures/spaced file.jpg +0 -0
  176. data/spec/support/fixtures/spaced file.png +0 -0
  177. data/spec/support/fixtures/text.txt +1 -0
  178. data/spec/support/fixtures/twopage.pdf +0 -0
  179. data/spec/support/fixtures/uppercase.PNG +0 -0
  180. data/spec/support/matchers/accept.rb +5 -0
  181. data/spec/support/matchers/exist.rb +5 -0
  182. data/spec/support/matchers/have_column.rb +23 -0
  183. data/spec/support/mock_attachment.rb +22 -0
  184. data/spec/support/mock_interpolator.rb +24 -0
  185. data/spec/support/mock_url_generator_builder.rb +27 -0
  186. data/spec/support/model_reconstruction.rb +68 -0
  187. data/spec/support/reporting.rb +11 -0
  188. data/spec/support/test_data.rb +13 -0
  189. data/spec/support/version_helper.rb +9 -0
  190. metadata +713 -0
@@ -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(URI.escape(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,44 @@
1
+ require 'open-uri'
2
+
3
+ module Paperclip
4
+ class UriAdapter < AbstractAdapter
5
+ def initialize(target)
6
+ @target = target
7
+ @content = download_content
8
+ cache_current_values
9
+ @tempfile = copy_to_tempfile(@content)
10
+ end
11
+
12
+ attr_writer :content_type
13
+
14
+ private
15
+
16
+ def download_content
17
+ open(@target)
18
+ end
19
+
20
+ def cache_current_values
21
+ @original_filename = @target.path.split("/").last
22
+ @original_filename ||= "index.html"
23
+ self.original_filename = @original_filename.strip
24
+
25
+ @content_type = @content.content_type if @content.respond_to?(:content_type)
26
+ @content_type ||= "text/html"
27
+
28
+ @size = @content.size
29
+ end
30
+
31
+ def copy_to_tempfile(src)
32
+ while data = src.read(16*1024)
33
+ destination.write(data)
34
+ end
35
+ src.close
36
+ destination.rewind
37
+ destination
38
+ end
39
+ end
40
+ end
41
+
42
+ Paperclip.io_adapters.register Paperclip::UriAdapter do |target|
43
+ target.kind_of?(URI)
44
+ end
@@ -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,21 @@
1
+ module Paperclip
2
+ module Logger
3
+ # Log a paperclip-specific line. This will log to STDOUT
4
+ # by default. Set Paperclip.options[:log] to false to turn off.
5
+ def log message
6
+ logger.info("[paperclip] #{message}") if logging?
7
+ end
8
+
9
+ def logger #:nodoc:
10
+ @logger ||= options[:logger] || ::Logger.new(STDOUT)
11
+ end
12
+
13
+ def logger=(logger)
14
+ @logger = logger
15
+ end
16
+
17
+ def logging? #:nodoc:
18
+ options[:log]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,64 @@
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
+
6
+ module Paperclip
7
+ module Shoulda
8
+ # Provides RSpec-compatible & Test::Unit-compatible matchers for testing Paperclip attachments.
9
+ #
10
+ # *RSpec*
11
+ #
12
+ # In spec_helper.rb, you'll need to require the matchers:
13
+ #
14
+ # require "paperclip/matchers"
15
+ #
16
+ # And _include_ the module:
17
+ #
18
+ # RSpec.configure do |config|
19
+ # config.include Paperclip::Shoulda::Matchers
20
+ # end
21
+ #
22
+ # Example:
23
+ # describe User do
24
+ # it { should have_attached_file(:avatar) }
25
+ # it { should validate_attachment_presence(:avatar) }
26
+ # it { should validate_attachment_content_type(:avatar).
27
+ # allowing('image/png', 'image/gif').
28
+ # rejecting('text/plain', 'text/xml') }
29
+ # it { should validate_attachment_size(:avatar).
30
+ # less_than(2.megabytes) }
31
+ # end
32
+ #
33
+ #
34
+ # *TestUnit*
35
+ #
36
+ # In test_helper.rb, you'll need to require the matchers as well:
37
+ #
38
+ # require "paperclip/matchers"
39
+ #
40
+ # And _extend_ the module:
41
+ #
42
+ # class ActiveSupport::TestCase
43
+ # extend Paperclip::Shoulda::Matchers
44
+ #
45
+ # #...other initializers...#
46
+ # end
47
+ #
48
+ # Example:
49
+ # require 'test_helper'
50
+ #
51
+ # class UserTest < ActiveSupport::TestCase
52
+ # should have_attached_file(:avatar)
53
+ # should validate_attachment_presence(:avatar)
54
+ # should validate_attachment_content_type(:avatar).
55
+ # allowing('image/png', 'image/gif').
56
+ # rejecting('text/plain', 'text/xml')
57
+ # should validate_attachment_size(:avatar).
58
+ # less_than(2.megabytes)
59
+ # end
60
+ #
61
+ module Matchers
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,54 @@
1
+ module Paperclip
2
+ module Shoulda
3
+ module Matchers
4
+ # Ensures that the given instance or class has an attachment with the
5
+ # given name.
6
+ #
7
+ # Example:
8
+ # describe User do
9
+ # it { should have_attached_file(:avatar) }
10
+ # end
11
+ def have_attached_file name
12
+ HaveAttachedFileMatcher.new(name)
13
+ end
14
+
15
+ class HaveAttachedFileMatcher
16
+ def initialize attachment_name
17
+ @attachment_name = attachment_name
18
+ end
19
+
20
+ def matches? subject
21
+ @subject = subject
22
+ @subject = @subject.class unless Class === @subject
23
+ responds? && has_column?
24
+ end
25
+
26
+ def failure_message
27
+ "Should have an attachment named #{@attachment_name}"
28
+ end
29
+
30
+ def failure_message_when_negated
31
+ "Should not have an attachment named #{@attachment_name}"
32
+ end
33
+ alias negative_failure_message failure_message_when_negated
34
+
35
+ def description
36
+ "have an attachment named #{@attachment_name}"
37
+ end
38
+
39
+ protected
40
+
41
+ def responds?
42
+ methods = @subject.instance_methods.map(&:to_s)
43
+ methods.include?("#{@attachment_name}") &&
44
+ methods.include?("#{@attachment_name}=") &&
45
+ methods.include?("#{@attachment_name}?")
46
+ end
47
+
48
+ def has_column?
49
+ @subject.column_names.include?("#{@attachment_name}_file_name")
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end