mender_paperclip 2.4.3

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 (70) hide show
  1. data/LICENSE +26 -0
  2. data/README.md +402 -0
  3. data/Rakefile +86 -0
  4. data/generators/paperclip/USAGE +5 -0
  5. data/generators/paperclip/paperclip_generator.rb +27 -0
  6. data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  7. data/init.rb +4 -0
  8. data/lib/generators/paperclip/USAGE +8 -0
  9. data/lib/generators/paperclip/paperclip_generator.rb +33 -0
  10. data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
  11. data/lib/paperclip/attachment.rb +454 -0
  12. data/lib/paperclip/callback_compatibility.rb +61 -0
  13. data/lib/paperclip/geometry.rb +120 -0
  14. data/lib/paperclip/interpolations.rb +181 -0
  15. data/lib/paperclip/iostream.rb +45 -0
  16. data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
  17. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
  18. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
  19. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
  20. data/lib/paperclip/matchers.rb +33 -0
  21. data/lib/paperclip/missing_attachment_styles.rb +87 -0
  22. data/lib/paperclip/options.rb +79 -0
  23. data/lib/paperclip/processor.rb +58 -0
  24. data/lib/paperclip/railtie.rb +26 -0
  25. data/lib/paperclip/storage/filesystem.rb +81 -0
  26. data/lib/paperclip/storage/fog.rb +162 -0
  27. data/lib/paperclip/storage/s3.rb +262 -0
  28. data/lib/paperclip/storage.rb +3 -0
  29. data/lib/paperclip/style.rb +95 -0
  30. data/lib/paperclip/thumbnail.rb +105 -0
  31. data/lib/paperclip/upfile.rb +62 -0
  32. data/lib/paperclip/version.rb +3 -0
  33. data/lib/paperclip.rb +478 -0
  34. data/lib/tasks/paperclip.rake +97 -0
  35. data/rails/init.rb +2 -0
  36. data/shoulda_macros/paperclip.rb +124 -0
  37. data/test/attachment_test.rb +1120 -0
  38. data/test/database.yml +4 -0
  39. data/test/fixtures/12k.png +0 -0
  40. data/test/fixtures/50x50.png +0 -0
  41. data/test/fixtures/5k.png +0 -0
  42. data/test/fixtures/animated.gif +0 -0
  43. data/test/fixtures/bad.png +1 -0
  44. data/test/fixtures/fog.yml +8 -0
  45. data/test/fixtures/s3.yml +8 -0
  46. data/test/fixtures/spaced file.png +0 -0
  47. data/test/fixtures/text.txt +1 -0
  48. data/test/fixtures/twopage.pdf +0 -0
  49. data/test/fixtures/uppercase.PNG +0 -0
  50. data/test/fog_test.rb +191 -0
  51. data/test/geometry_test.rb +206 -0
  52. data/test/helper.rb +152 -0
  53. data/test/integration_test.rb +654 -0
  54. data/test/interpolations_test.rb +195 -0
  55. data/test/iostream_test.rb +71 -0
  56. data/test/matchers/have_attached_file_matcher_test.rb +24 -0
  57. data/test/matchers/validate_attachment_content_type_matcher_test.rb +87 -0
  58. data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
  59. data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
  60. data/test/options_test.rb +68 -0
  61. data/test/paperclip_missing_attachment_styles_test.rb +80 -0
  62. data/test/paperclip_test.rb +329 -0
  63. data/test/processor_test.rb +10 -0
  64. data/test/storage/filesystem_test.rb +52 -0
  65. data/test/storage/s3_live_test.rb +51 -0
  66. data/test/storage/s3_test.rb +633 -0
  67. data/test/style_test.rb +180 -0
  68. data/test/thumbnail_test.rb +383 -0
  69. data/test/upfile_test.rb +53 -0
  70. metadata +243 -0
@@ -0,0 +1,95 @@
1
+ # encoding: utf-8
2
+ module Paperclip
3
+ # The Style class holds the definition of a thumbnail style, applying
4
+ # whatever processing is required to normalize the definition and delaying
5
+ # the evaluation of block parameters until useful context is available.
6
+
7
+ class Style
8
+
9
+ attr_reader :name, :attachment, :format
10
+
11
+ # Creates a Style object. +name+ is the name of the attachment,
12
+ # +definition+ is the style definition from has_attached_file, which
13
+ # can be string, array or hash
14
+ def initialize name, definition, attachment
15
+ @name = name
16
+ @attachment = attachment
17
+ if definition.is_a? Hash
18
+ @geometry = definition.delete(:geometry)
19
+ @format = definition.delete(:format)
20
+ @processors = definition.delete(:processors)
21
+ @other_args = definition
22
+ else
23
+ @geometry, @format = [definition, nil].flatten[0..1]
24
+ @other_args = {}
25
+ end
26
+ @format = nil if @format.blank?
27
+ end
28
+
29
+ # retrieves from the attachment the processors defined in the has_attached_file call
30
+ # (which method (in the attachment) will call any supplied procs)
31
+ # There is an important change of interface here: a style rule can set its own processors
32
+ # by default we behave as before, though.
33
+ # if a proc has been supplied, we call it here
34
+ def processors
35
+ @processors.respond_to?(:call) ? @processors.call(attachment.instance) : (@processors || attachment.options.processors)
36
+ end
37
+
38
+ # retrieves from the attachment the whiny setting
39
+ def whiny
40
+ attachment.options.whiny
41
+ end
42
+
43
+ # returns true if we're inclined to grumble
44
+ def whiny?
45
+ !!whiny
46
+ end
47
+
48
+ def convert_options
49
+ attachment.send(:extra_options_for, name)
50
+ end
51
+
52
+ def source_file_options
53
+ attachment.send(:extra_source_file_options_for, name)
54
+ end
55
+
56
+ # returns the geometry string for this style
57
+ # if a proc has been supplied, we call it here
58
+ def geometry
59
+ @geometry.respond_to?(:call) ? @geometry.call(attachment.instance) : @geometry
60
+ end
61
+
62
+ # Supplies the hash of options that processors expect to receive as their second argument
63
+ # Arguments other than the standard geometry, format etc are just passed through from
64
+ # initialization and any procs are called here, just before post-processing.
65
+ def processor_options
66
+ args = {}
67
+ @other_args.each do |k,v|
68
+ args[k] = v.respond_to?(:call) ? v.call(attachment) : v
69
+ end
70
+ [:processors, :geometry, :format, :whiny, :convert_options, :source_file_options].each do |k|
71
+ (arg = send(k)) && args[k] = arg
72
+ end
73
+ args
74
+ end
75
+
76
+ # Supports getting and setting style properties with hash notation to ensure backwards-compatibility
77
+ # eg. @attachment.options.styles[:large][:geometry]@ will still work
78
+ def [](key)
79
+ if [:name, :convert_options, :whiny, :processors, :geometry, :format, :animated, :source_file_options].include?(key)
80
+ send(key)
81
+ elsif defined? @other_args[key]
82
+ @other_args[key]
83
+ end
84
+ end
85
+
86
+ def []=(key, value)
87
+ if [:name, :convert_options, :whiny, :processors, :geometry, :format, :animated, :source_file_options].include?(key)
88
+ send("#{key}=".intern, value)
89
+ else
90
+ @other_args[key] = value
91
+ end
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,105 @@
1
+ module Paperclip
2
+ # Handles thumbnailing images that are uploaded.
3
+ class Thumbnail < Processor
4
+
5
+ attr_accessor :current_geometry, :target_geometry, :format, :whiny, :convert_options,
6
+ :source_file_options, :animated
7
+
8
+ # List of formats that we need to preserve animation
9
+ ANIMATED_FORMATS = %w(gif)
10
+
11
+ # Creates a Thumbnail object set to work on the +file+ given. It
12
+ # will attempt to transform the image into one defined by +target_geometry+
13
+ # which is a "WxH"-style string. +format+ will be inferred from the +file+
14
+ # unless specified. Thumbnail creation will raise no errors unless
15
+ # +whiny+ is true (which it is, by default. If +convert_options+ is
16
+ # set, the options will be appended to the convert command upon image conversion
17
+ #
18
+ # Options include:
19
+ #
20
+ # +geometry+ - the desired width and height of the thumbnail (required)
21
+ # +file_geometry_parser+ - an object with a method named +from_file+ that takes an image file and produces its geometry and a +transformation_to+. Defaults to Paperclip::Geometry
22
+ # +string_geometry_parser+ - an object with a method named +parse+ that takes a string and produces an object with +width+, +height+, and +to_s+ accessors. Defaults to Paperclip::Geometry
23
+ # +source_file_options+ - flags passed to the +convert+ command that influence how the source file is read
24
+ # +convert_options+ - flags passed to the +convert+ command that influence how the image is processed
25
+ # +whiny+ - whether to raise an error when processing fails. Defaults to true
26
+ # +format+ - the desired filename extension
27
+ # +animated+ - whether to merge all the layers in the image. Defaults to true
28
+ def initialize(file, options = {}, attachment = nil)
29
+ super
30
+
31
+ geometry = options[:geometry] # this is not an option
32
+ @file = file
33
+ @crop = geometry[-1,1] == '#'
34
+ @target_geometry = (options[:string_geometry_parser] || Geometry).parse(geometry)
35
+ @current_geometry = (options[:file_geometry_parser] || Geometry).from_file(@file)
36
+ @source_file_options = options[:source_file_options]
37
+ @convert_options = options[:convert_options]
38
+ @whiny = options[:whiny].nil? ? true : options[:whiny]
39
+ @format = options[:format]
40
+ @animated = options[:animated].nil? ? true : options[:animated]
41
+
42
+ @source_file_options = @source_file_options.split(/\s+/) if @source_file_options.respond_to?(:split)
43
+ @convert_options = @convert_options.split(/\s+/) if @convert_options.respond_to?(:split)
44
+
45
+ @current_format = File.extname(@file.path)
46
+ @basename = File.basename(@file.path, @current_format)
47
+
48
+ end
49
+
50
+ # Returns true if the +target_geometry+ is meant to crop.
51
+ def crop?
52
+ @crop
53
+ end
54
+
55
+ # Returns true if the image is meant to make use of additional convert options.
56
+ def convert_options?
57
+ !@convert_options.nil? && !@convert_options.empty?
58
+ end
59
+
60
+ # Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile
61
+ # that contains the new image.
62
+ def make
63
+ src = @file
64
+ dst = Tempfile.new([@basename, @format ? ".#{@format}" : ''])
65
+ dst.binmode
66
+
67
+ begin
68
+ parameters = []
69
+ parameters << source_file_options
70
+ parameters << ":source"
71
+ parameters << transformation_command
72
+ parameters << convert_options
73
+ parameters << ":dest"
74
+
75
+ parameters = parameters.flatten.compact.join(" ").strip.squeeze(" ")
76
+
77
+ success = Paperclip.run("convert", parameters, :source => "#{File.expand_path(src.path)}#{'[0]' unless animated?}", :dest => File.expand_path(dst.path))
78
+ rescue Cocaine::ExitStatusError => e
79
+ raise PaperclipError, "There was an error processing the thumbnail for #{@basename}" if @whiny
80
+ rescue Cocaine::CommandNotFoundError => e
81
+ raise Paperclip::CommandNotFoundError.new("Could not run the `convert` command. Please install ImageMagick.")
82
+ end
83
+
84
+ dst
85
+ end
86
+
87
+ # Returns the command ImageMagick's +convert+ needs to transform the image
88
+ # into the thumbnail.
89
+ def transformation_command
90
+ scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
91
+ trans = []
92
+ trans << "-coalesce" if animated?
93
+ trans << "-resize" << %["#{scale}"] unless scale.nil? || scale.empty?
94
+ trans << "-crop" << %["#{crop}"] << "+repage" if crop
95
+ trans
96
+ end
97
+
98
+ protected
99
+
100
+ # Return true if the format is animated
101
+ def animated?
102
+ @animated && ANIMATED_FORMATS.include?(@current_format[1..-1]) && (ANIMATED_FORMATS.include?(@format.to_s) || @format.blank?)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,62 @@
1
+ require 'mime/types'
2
+
3
+ module Paperclip
4
+ # The Upfile module is a convenience module for adding uploaded-file-type methods
5
+ # to the +File+ class. Useful for testing.
6
+ # user.avatar = File.new("test/test_avatar.jpg")
7
+ module Upfile
8
+
9
+ # Infer the MIME-type of the file from the extension.
10
+ def content_type
11
+ types = MIME::Types.type_for(self.original_filename)
12
+ if types.length == 0
13
+ type_from_file_command
14
+ elsif types.length == 1
15
+ types.first.content_type
16
+ else
17
+ iterate_over_array_to_find_best_option(types)
18
+ end
19
+ end
20
+
21
+ def iterate_over_array_to_find_best_option(types)
22
+ types.reject {|type| type.content_type.match(/\/x-/) }.first
23
+ end
24
+
25
+ def type_from_file_command
26
+ # On BSDs, `file` doesn't give a result code of 1 if the file doesn't exist.
27
+ type = (self.original_filename.match(/\.(\w+)$/)[1] rescue "octet-stream").downcase
28
+ mime_type = (Paperclip.run("file", "-b --mime :file", :file => self.path).split(/[:;]\s+/)[0] rescue "application/x-#{type}")
29
+ mime_type = "application/x-#{type}" if mime_type.match(/\(.*?\)/)
30
+ mime_type
31
+ end
32
+
33
+ # Returns the file's normal name.
34
+ def original_filename
35
+ File.basename(self.path)
36
+ end
37
+
38
+ # Returns the size of the file.
39
+ def size
40
+ File.size(self)
41
+ end
42
+ end
43
+ end
44
+
45
+ if defined? StringIO
46
+ class StringIO
47
+ attr_accessor :original_filename, :content_type, :fingerprint
48
+ def original_filename
49
+ @original_filename ||= "stringio.txt"
50
+ end
51
+ def content_type
52
+ @content_type ||= "text/plain"
53
+ end
54
+ def fingerprint
55
+ @fingerprint ||= Digest::MD5.hexdigest(self.string)
56
+ end
57
+ end
58
+ end
59
+
60
+ class File #:nodoc:
61
+ include Paperclip::Upfile
62
+ end
@@ -0,0 +1,3 @@
1
+ module Paperclip
2
+ VERSION = "2.4.3" unless defined? Paperclip::VERSION
3
+ end