mender_paperclip 2.4.3

Sign up to get free protection for your applications and to get access to all the features.
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