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,181 @@
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
+ end
14
+
15
+ # Hash access of interpolations. Included only for compatibility,
16
+ # and is not intended for normal use.
17
+ def self.[] name
18
+ method(name)
19
+ end
20
+
21
+ # Returns a sorted list of all interpolations.
22
+ def self.all
23
+ self.instance_methods(false).sort
24
+ end
25
+
26
+ # Perform the actual interpolation. Takes the pattern to interpolate
27
+ # and the arguments to pass, which are the attachment and style name.
28
+ # You can pass a method name on your record as a symbol, which should turn
29
+ # an interpolation pattern for Paperclip to use.
30
+ def self.interpolate pattern, *args
31
+ pattern = args.first.instance.send(pattern) if pattern.kind_of? Symbol
32
+ all.reverse.inject( pattern.dup ) do |result, tag|
33
+ result.gsub(/:#{tag}/) do |match|
34
+ send( tag, *args )
35
+ end
36
+ end
37
+ end
38
+
39
+ # Returns the filename, the same way as ":basename.:extension" would.
40
+ def filename attachment, style_name
41
+ [ basename(attachment, style_name), extension(attachment, style_name) ].reject(&:blank?).join(".")
42
+ end
43
+
44
+ # Returns the interpolated URL. Will raise an error if the url itself
45
+ # contains ":url" to prevent infinite recursion. This interpolation
46
+ # is used in the default :path to ease default specifications.
47
+ RIGHT_HERE = "#{__FILE__.gsub(%r{^\./}, "")}:#{__LINE__ + 3}"
48
+ def url attachment, style_name
49
+ raise InfiniteInterpolationError if caller.any?{|b| b.index(RIGHT_HERE) }
50
+ attachment.url(style_name, false)
51
+ end
52
+
53
+ # Returns the timestamp as defined by the <attachment>_updated_at field
54
+ # in the server default time zone unless :use_global_time_zone is set
55
+ # to false. Note that a Rails.config.time_zone change will still
56
+ # invalidate any path or URL that uses :timestamp. For a
57
+ # time_zone-agnostic timestamp, use #updated_at.
58
+ def timestamp attachment, style_name
59
+ attachment.instance_read(:updated_at).in_time_zone(attachment.time_zone).to_s
60
+ end
61
+
62
+ # Returns an integer timestamp that is time zone-neutral, so that paths
63
+ # remain valid even if a server's time zone changes.
64
+ def updated_at attachment, style_name
65
+ attachment.updated_at
66
+ end
67
+
68
+ # Returns the Rails.root constant.
69
+ def rails_root attachment, style_name
70
+ Rails.root
71
+ end
72
+
73
+ # Returns the Rails.env constant.
74
+ def rails_env attachment, style_name
75
+ Rails.env
76
+ end
77
+
78
+ # Returns the underscored, pluralized version of the class name.
79
+ # e.g. "users" for the User class.
80
+ # NOTE: The arguments need to be optional, because some tools fetch
81
+ # all class names. Calling #class will return the expected class.
82
+ def class attachment = nil, style_name = nil
83
+ return super() if attachment.nil? && style_name.nil?
84
+ attachment.instance.class.to_s.underscore.pluralize
85
+ end
86
+
87
+ # Returns the basename of the file. e.g. "file" for "file.jpg"
88
+ def basename attachment, style_name
89
+ attachment.original_filename.gsub(/#{File.extname(attachment.original_filename)}$/, "")
90
+ end
91
+
92
+ # Returns the extension of the file. e.g. "jpg" for "file.jpg"
93
+ # If the style has a format defined, it will return the format instead
94
+ # of the actual extension.
95
+ def extension attachment, style_name
96
+ style = attachment.styles[style_name]
97
+ ext = (style && style[:format]) || File.extname(attachment.original_filename).gsub(/^\.+/, "")
98
+
99
+ if style && (except_formats = style[:except_formats])
100
+ except_formats = except_formats.split(/\s+/) if except_formats.respond_to?(:split)
101
+ original_ext = File.extname(attachment.original_filename).gsub(/^\.+/, "")
102
+ ext = original_ext if except_formats.include?(original_ext)
103
+ end
104
+
105
+ ext
106
+ #((style = attachment.styles[style_name]) && style[:format]) ||
107
+ # File.extname(attachment.original_filename).gsub(/^\.+/, "")
108
+ end
109
+
110
+ # Returns an extension based on the content type. e.g. "jpeg" for "image/jpeg".
111
+ # Each mime type generally has multiple extensions associated with it, so
112
+ # if the extension from teh original filename is one of these extensions,
113
+ # that extension is used, otherwise, the first in the list is used.
114
+ def content_type_extension attachment, style_name
115
+ mime_type = MIME::Types[attachment.content_type]
116
+ extensions_for_mime_type = unless mime_type.empty?
117
+ mime_type.first.extensions
118
+ else
119
+ []
120
+ end
121
+
122
+ original_extension = extension(attachment, style_name)
123
+ if extensions_for_mime_type.include? original_extension
124
+ original_extension
125
+ elsif !extensions_for_mime_type.empty?
126
+ extensions_for_mime_type.first
127
+ else
128
+ # It's possible, though unlikely, that the mime type is not in the
129
+ # database, so just use the part after the '/' in the mime type as the
130
+ # extension.
131
+ %r{/([^/]*)$}.match(attachment.content_type)[1]
132
+ end
133
+ end
134
+
135
+ # Returns the id of the instance.
136
+ def id attachment, style_name
137
+ attachment.instance.id
138
+ end
139
+
140
+ # Returns the #to_param of the instance.
141
+ def param attachment, style_name
142
+ attachment.instance.to_param
143
+ end
144
+
145
+ # Returns the fingerprint of the instance.
146
+ def fingerprint attachment, style_name
147
+ attachment.fingerprint
148
+ end
149
+
150
+ # Returns a the attachment hash. See Paperclip::Attachment#hash for
151
+ # more details.
152
+ def hash attachment=nil, style_name=nil
153
+ if attachment && style_name
154
+ attachment.hash(style_name)
155
+ else
156
+ super()
157
+ end
158
+ end
159
+
160
+ # Returns the id of the instance in a split path form. e.g. returns
161
+ # 000/001/234 for an id of 1234.
162
+ def id_partition attachment, style_name
163
+ if (id = attachment.instance.id).is_a?(Integer)
164
+ ("%09d" % id).scan(/\d{3}/).join("/")
165
+ else
166
+ id.scan(/.{3}/).first(3).join("/")
167
+ end
168
+ end
169
+
170
+ # Returns the pluralized form of the attachment name. e.g.
171
+ # "avatars" for an attachment of :avatar
172
+ def attachment attachment, style_name
173
+ attachment.name.to_s.downcase.pluralize
174
+ end
175
+
176
+ # Returns the style, or the default style if nil is supplied.
177
+ def style attachment, style_name
178
+ style_name || attachment.default_style
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,45 @@
1
+ # Provides method that can be included on File-type objects (IO, StringIO, Tempfile, etc) to allow stream copying
2
+ # and Tempfile conversion.
3
+ module IOStream
4
+ # Returns a Tempfile containing the contents of the readable object.
5
+ def to_tempfile(object)
6
+ return object.to_tempfile if object.respond_to?(:to_tempfile)
7
+ name = object.respond_to?(:original_filename) ? object.original_filename : (object.respond_to?(:path) ? object.path : "stream")
8
+ tempfile = Paperclip::Tempfile.new(["stream", File.extname(name)])
9
+ tempfile.binmode
10
+ stream_to(object, tempfile)
11
+ end
12
+
13
+ # Copies one read-able object from one place to another in blocks, obviating the need to load
14
+ # the whole thing into memory. Defaults to 8k blocks. Returns a File if a String is passed
15
+ # in as the destination and returns the IO or Tempfile as passed in if one is sent as the destination.
16
+ def stream_to object, path_or_file, in_blocks_of = 8192
17
+ dstio = case path_or_file
18
+ when String then File.new(path_or_file, "wb+")
19
+ when IO then path_or_file
20
+ when Tempfile then path_or_file
21
+ end
22
+ buffer = ""
23
+ object.rewind
24
+ while object.read(in_blocks_of, buffer) do
25
+ dstio.write(buffer)
26
+ end
27
+ dstio.rewind
28
+ dstio
29
+ end
30
+ end
31
+
32
+ # Corrects a bug in Windows when asking for Tempfile size.
33
+ if defined?(Tempfile) && RUBY_PLATFORM !~ /java/
34
+ class Tempfile
35
+ def size
36
+ if @tmpfile
37
+ @tmpfile.fsync
38
+ @tmpfile.flush
39
+ @tmpfile.stat.size
40
+ else
41
+ 0
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,57 @@
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? && included?
24
+ end
25
+
26
+ def failure_message
27
+ "Should have an attachment named #{@attachment_name}"
28
+ end
29
+
30
+ def negative_failure_message
31
+ "Should not have an attachment named #{@attachment_name}"
32
+ end
33
+
34
+ def description
35
+ "have an attachment named #{@attachment_name}"
36
+ end
37
+
38
+ protected
39
+
40
+ def responds?
41
+ methods = @subject.instance_methods.map(&:to_s)
42
+ methods.include?("#{@attachment_name}") &&
43
+ methods.include?("#{@attachment_name}=") &&
44
+ methods.include?("#{@attachment_name}?")
45
+ end
46
+
47
+ def has_column?
48
+ @subject.column_names.include?("#{@attachment_name}_file_name")
49
+ end
50
+
51
+ def included?
52
+ @subject.ancestors.include?(Paperclip::InstanceMethods)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,81 @@
1
+ module Paperclip
2
+ module Shoulda
3
+ module Matchers
4
+ # Ensures that the given instance or class validates the content type of
5
+ # the given attachment as specified.
6
+ #
7
+ # Example:
8
+ # describe User do
9
+ # it { should validate_attachment_content_type(:icon).
10
+ # allowing('image/png', 'image/gif').
11
+ # rejecting('text/plain', 'text/xml') }
12
+ # end
13
+ def validate_attachment_content_type name
14
+ ValidateAttachmentContentTypeMatcher.new(name)
15
+ end
16
+
17
+ class ValidateAttachmentContentTypeMatcher
18
+ def initialize attachment_name
19
+ @attachment_name = attachment_name
20
+ @allowed_types = []
21
+ @rejected_types = []
22
+ end
23
+
24
+ def allowing *types
25
+ @allowed_types = types.flatten
26
+ self
27
+ end
28
+
29
+ def rejecting *types
30
+ @rejected_types = types.flatten
31
+ self
32
+ end
33
+
34
+ def matches? subject
35
+ @subject = subject
36
+ @subject = @subject.class unless Class === @subject
37
+ @allowed_types && @rejected_types &&
38
+ allowed_types_allowed? && rejected_types_rejected?
39
+ end
40
+
41
+ def failure_message
42
+ "".tap do |str|
43
+ str << "Content types #{@allowed_types.join(", ")} should be accepted" if @allowed_types.present?
44
+ str << "\n" if @allowed_types.present? && @rejected_types.present?
45
+ str << "Content types #{@rejected_types.join(", ")} should be rejected by #{@attachment_name}" if @rejected_types.present?
46
+ end
47
+ end
48
+
49
+ def negative_failure_message
50
+ "".tap do |str|
51
+ str << "Content types #{@allowed_types.join(", ")} should be rejected" if @allowed_types.present?
52
+ str << "\n" if @allowed_types.present? && @rejected_types.present?
53
+ str << "Content types #{@rejected_types.join(", ")} should be accepted by #{@attachment_name}" if @rejected_types.present?
54
+ end
55
+ end
56
+
57
+ def description
58
+ "validate the content types allowed on attachment #{@attachment_name}"
59
+ end
60
+
61
+ protected
62
+
63
+ def type_allowed?(type)
64
+ file = StringIO.new(".")
65
+ file.content_type = type
66
+ (subject = @subject.new).attachment_for(@attachment_name).assign(file)
67
+ subject.valid?
68
+ subject.errors[:"#{@attachment_name}_content_type"].blank?
69
+ end
70
+
71
+ def allowed_types_allowed?
72
+ @allowed_types.all? { |type| type_allowed?(type) }
73
+ end
74
+
75
+ def rejected_types_rejected?
76
+ !@rejected_types.any? { |type| type_allowed?(type) }
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,54 @@
1
+ module Paperclip
2
+ module Shoulda
3
+ module Matchers
4
+ # Ensures that the given instance or class validates the presence of the
5
+ # given attachment.
6
+ #
7
+ # describe User do
8
+ # it { should validate_attachment_presence(:avatar) }
9
+ # end
10
+ def validate_attachment_presence name
11
+ ValidateAttachmentPresenceMatcher.new(name)
12
+ end
13
+
14
+ class ValidateAttachmentPresenceMatcher
15
+ def initialize attachment_name
16
+ @attachment_name = attachment_name
17
+ end
18
+
19
+ def matches? subject
20
+ @subject = subject
21
+ @subject = @subject.class unless Class === @subject
22
+ error_when_not_valid? && no_error_when_valid?
23
+ end
24
+
25
+ def failure_message
26
+ "Attachment #{@attachment_name} should be required"
27
+ end
28
+
29
+ def negative_failure_message
30
+ "Attachment #{@attachment_name} should not be required"
31
+ end
32
+
33
+ def description
34
+ "require presence of attachment #{@attachment_name}"
35
+ end
36
+
37
+ protected
38
+
39
+ def error_when_not_valid?
40
+ (subject = @subject.new).send(@attachment_name).assign(nil)
41
+ subject.valid?
42
+ not subject.errors[:"#{@attachment_name}_file_name"].blank?
43
+ end
44
+
45
+ def no_error_when_valid?
46
+ @file = StringIO.new(".")
47
+ (subject = @subject.new).send(@attachment_name).assign(@file)
48
+ subject.valid?
49
+ subject.errors[:"#{@attachment_name}_file_name"].blank?
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,95 @@
1
+ module Paperclip
2
+ module Shoulda
3
+ module Matchers
4
+ # Ensures that the given instance or class validates the size of the
5
+ # given attachment as specified.
6
+ #
7
+ # Examples:
8
+ # it { should validate_attachment_size(:avatar).
9
+ # less_than(2.megabytes) }
10
+ # it { should validate_attachment_size(:icon).
11
+ # greater_than(1024) }
12
+ # it { should validate_attachment_size(:icon).
13
+ # in(0..100) }
14
+ def validate_attachment_size name
15
+ ValidateAttachmentSizeMatcher.new(name)
16
+ end
17
+
18
+ class ValidateAttachmentSizeMatcher
19
+ def initialize attachment_name
20
+ @attachment_name = attachment_name
21
+ @low, @high = 0, (1.0/0)
22
+ end
23
+
24
+ def less_than size
25
+ @high = size
26
+ self
27
+ end
28
+
29
+ def greater_than size
30
+ @low = size
31
+ self
32
+ end
33
+
34
+ def in range
35
+ @low, @high = range.first, range.last
36
+ self
37
+ end
38
+
39
+ def matches? subject
40
+ @subject = subject
41
+ @subject = @subject.class unless Class === @subject
42
+ lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high?
43
+ end
44
+
45
+ def failure_message
46
+ "Attachment #{@attachment_name} must be between #{@low} and #{@high} bytes"
47
+ end
48
+
49
+ def negative_failure_message
50
+ "Attachment #{@attachment_name} cannot be between #{@low} and #{@high} bytes"
51
+ end
52
+
53
+ def description
54
+ "validate the size of attachment #{@attachment_name}"
55
+ end
56
+
57
+ protected
58
+
59
+ def override_method object, method, &replacement
60
+ (class << object; self; end).class_eval do
61
+ define_method(method, &replacement)
62
+ end
63
+ end
64
+
65
+ def passes_validation_with_size(new_size)
66
+ file = StringIO.new(".")
67
+ override_method(file, :size){ new_size }
68
+ override_method(file, :to_tempfile){ file }
69
+
70
+ (subject = @subject.new).send(@attachment_name).assign(file)
71
+ subject.valid?
72
+ subject.errors[:"#{@attachment_name}_file_size"].blank?
73
+ end
74
+
75
+ def lower_than_low?
76
+ not passes_validation_with_size(@low - 1)
77
+ end
78
+
79
+ def higher_than_low?
80
+ passes_validation_with_size(@low + 1)
81
+ end
82
+
83
+ def lower_than_high?
84
+ return true if @high == (1.0/0)
85
+ passes_validation_with_size(@high - 1)
86
+ end
87
+
88
+ def higher_than_high?
89
+ return true if @high == (1.0/0)
90
+ not passes_validation_with_size(@high + 1)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,33 @@
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 matchers for testing Paperclip attachments.
9
+ #
10
+ # In spec_helper.rb, you'll need to require the matchers:
11
+ #
12
+ # require "paperclip/matchers"
13
+ #
14
+ # And include the module:
15
+ #
16
+ # Spec::Runner.configure do |config|
17
+ # config.include Paperclip::Shoulda::Matchers
18
+ # end
19
+ #
20
+ # Example:
21
+ # describe User do
22
+ # it { should have_attached_file(:avatar) }
23
+ # it { should validate_attachment_presence(:avatar) }
24
+ # it { should validate_attachment_content_type(:avatar).
25
+ # allowing('image/png', 'image/gif').
26
+ # rejecting('text/plain', 'text/xml') }
27
+ # it { should validate_attachment_size(:avatar).
28
+ # less_than(2.megabytes) }
29
+ # end
30
+ module Matchers
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,87 @@
1
+
2
+ require 'set'
3
+ module Paperclip
4
+
5
+ class << self
6
+ attr_accessor :classes_with_attachments
7
+ attr_writer :registered_attachments_styles_path
8
+ def registered_attachments_styles_path
9
+ @registered_attachments_styles_path ||= Rails.root.join('public/system/paperclip_attachments.yml').to_s
10
+ end
11
+ end
12
+
13
+ self.classes_with_attachments = Set.new
14
+
15
+
16
+ # Get list of styles saved on previous deploy (running rake paperclip:refresh:missing_styles)
17
+ def self.get_registered_attachments_styles
18
+ YAML.load_file(Paperclip.registered_attachments_styles_path)
19
+ rescue Errno::ENOENT
20
+ nil
21
+ end
22
+ private_class_method :get_registered_attachments_styles
23
+
24
+ def self.save_current_attachments_styles!
25
+ File.open(Paperclip.registered_attachments_styles_path, 'w') do |f|
26
+ YAML.dump(current_attachments_styles, f)
27
+ end
28
+ end
29
+
30
+ # Returns hash with styles for all classes using Paperclip.
31
+ # Unfortunately current version does not work with lambda styles:(
32
+ # {
33
+ # :User => {:avatar => [:small, :big]},
34
+ # :Book => {
35
+ # :cover => [:thumb, :croppable]},
36
+ # :sample => [:thumb, :big]},
37
+ # }
38
+ # }
39
+ def self.current_attachments_styles
40
+ Hash.new.tap do |current_styles|
41
+ Paperclip.classes_with_attachments.each do |klass_name|
42
+ klass = Paperclip.class_for(klass_name)
43
+ klass.attachment_definitions.each do |attachment_name, attachment_attributes|
44
+ # TODO: is it even possible to take into account Procs?
45
+ next if attachment_attributes[:styles].kind_of?(Proc)
46
+ attachment_attributes[:styles].try(:keys).try(:each) do |style_name|
47
+ klass_sym = klass.to_s.to_sym
48
+ current_styles[klass_sym] ||= Hash.new
49
+ current_styles[klass_sym][attachment_name.to_sym] ||= Array.new
50
+ current_styles[klass_sym][attachment_name.to_sym] << style_name.to_sym
51
+ current_styles[klass_sym][attachment_name.to_sym].map!(&:to_s).sort!.map!(&:to_sym).uniq!
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ private_class_method :current_attachments_styles
58
+
59
+ # Returns hash with styles missing from recent run of rake paperclip:refresh:missing_styles
60
+ # {
61
+ # :User => {:avatar => [:big]},
62
+ # :Book => {
63
+ # :cover => [:croppable]},
64
+ # }
65
+ # }
66
+ def self.missing_attachments_styles
67
+ current_styles = current_attachments_styles
68
+ registered_styles = get_registered_attachments_styles
69
+
70
+ Hash.new.tap do |missing_styles|
71
+ current_styles.each do |klass, attachment_definitions|
72
+ attachment_definitions.each do |attachment_name, styles|
73
+ registered = registered_styles[klass][attachment_name] rescue []
74
+ missed = styles - registered
75
+ if missed.present?
76
+ klass_sym = klass.to_s.to_sym
77
+ missing_styles[klass_sym] ||= Hash.new
78
+ missing_styles[klass_sym][attachment_name.to_sym] ||= Array.new
79
+ missing_styles[klass_sym][attachment_name.to_sym].concat(missed.to_a)
80
+ missing_styles[klass_sym][attachment_name.to_sym].map!(&:to_s).sort!.map!(&:to_sym).uniq!
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ end