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.
- data/LICENSE +26 -0
- data/README.md +402 -0
- data/Rakefile +86 -0
- data/generators/paperclip/USAGE +5 -0
- data/generators/paperclip/paperclip_generator.rb +27 -0
- data/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
- data/init.rb +4 -0
- data/lib/generators/paperclip/USAGE +8 -0
- data/lib/generators/paperclip/paperclip_generator.rb +33 -0
- data/lib/generators/paperclip/templates/paperclip_migration.rb.erb +19 -0
- data/lib/paperclip/attachment.rb +454 -0
- data/lib/paperclip/callback_compatibility.rb +61 -0
- data/lib/paperclip/geometry.rb +120 -0
- data/lib/paperclip/interpolations.rb +181 -0
- data/lib/paperclip/iostream.rb +45 -0
- data/lib/paperclip/matchers/have_attached_file_matcher.rb +57 -0
- data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +81 -0
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +54 -0
- data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +95 -0
- data/lib/paperclip/matchers.rb +33 -0
- data/lib/paperclip/missing_attachment_styles.rb +87 -0
- data/lib/paperclip/options.rb +79 -0
- data/lib/paperclip/processor.rb +58 -0
- data/lib/paperclip/railtie.rb +26 -0
- data/lib/paperclip/storage/filesystem.rb +81 -0
- data/lib/paperclip/storage/fog.rb +162 -0
- data/lib/paperclip/storage/s3.rb +262 -0
- data/lib/paperclip/storage.rb +3 -0
- data/lib/paperclip/style.rb +95 -0
- data/lib/paperclip/thumbnail.rb +105 -0
- data/lib/paperclip/upfile.rb +62 -0
- data/lib/paperclip/version.rb +3 -0
- data/lib/paperclip.rb +478 -0
- data/lib/tasks/paperclip.rake +97 -0
- data/rails/init.rb +2 -0
- data/shoulda_macros/paperclip.rb +124 -0
- data/test/attachment_test.rb +1120 -0
- data/test/database.yml +4 -0
- data/test/fixtures/12k.png +0 -0
- data/test/fixtures/50x50.png +0 -0
- data/test/fixtures/5k.png +0 -0
- data/test/fixtures/animated.gif +0 -0
- data/test/fixtures/bad.png +1 -0
- data/test/fixtures/fog.yml +8 -0
- data/test/fixtures/s3.yml +8 -0
- data/test/fixtures/spaced file.png +0 -0
- data/test/fixtures/text.txt +1 -0
- data/test/fixtures/twopage.pdf +0 -0
- data/test/fixtures/uppercase.PNG +0 -0
- data/test/fog_test.rb +191 -0
- data/test/geometry_test.rb +206 -0
- data/test/helper.rb +152 -0
- data/test/integration_test.rb +654 -0
- data/test/interpolations_test.rb +195 -0
- data/test/iostream_test.rb +71 -0
- data/test/matchers/have_attached_file_matcher_test.rb +24 -0
- data/test/matchers/validate_attachment_content_type_matcher_test.rb +87 -0
- data/test/matchers/validate_attachment_presence_matcher_test.rb +26 -0
- data/test/matchers/validate_attachment_size_matcher_test.rb +51 -0
- data/test/options_test.rb +68 -0
- data/test/paperclip_missing_attachment_styles_test.rb +80 -0
- data/test/paperclip_test.rb +329 -0
- data/test/processor_test.rb +10 -0
- data/test/storage/filesystem_test.rb +52 -0
- data/test/storage/s3_live_test.rb +51 -0
- data/test/storage/s3_test.rb +633 -0
- data/test/style_test.rb +180 -0
- data/test/thumbnail_test.rb +383 -0
- data/test/upfile_test.rb +53 -0
- 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
|