paperclip 3.5.0 → 3.5.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of paperclip might be problematic. Click here for more details.
- checksums.yaml +8 -8
- data/Appraisals +5 -0
- data/NEWS +8 -0
- data/features/basic_integration.feature +9 -15
- data/features/rake_tasks.feature +2 -3
- data/features/step_definitions/rails_steps.rb +66 -7
- data/features/step_definitions/s3_steps.rb +1 -1
- data/features/support/file_helpers.rb +10 -0
- data/features/support/rails.rb +18 -2
- data/gemfiles/4.0.gemfile +11 -0
- data/lib/paperclip.rb +1 -1
- data/lib/paperclip/attachment_registry.rb +57 -0
- data/lib/paperclip/content_type_detector.rb +37 -15
- data/lib/paperclip/has_attached_file.rb +20 -7
- data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +5 -1
- data/lib/paperclip/missing_attachment_styles.rb +2 -2
- data/lib/paperclip/version.rb +1 -1
- data/lib/tasks/paperclip.rake +2 -2
- data/paperclip.gemspec +1 -0
- data/test/attachment_definitions_test.rb +12 -0
- data/test/{tasks/attachments_test.rb → attachment_registry_test.rb} +18 -18
- data/test/attachment_test.rb +4 -1
- data/test/content_type_detector_test.rb +37 -27
- data/test/has_attached_file_test.rb +21 -5
- data/test/helper.rb +9 -6
- data/test/matchers/validate_attachment_presence_matcher_test.rb +22 -0
- data/test/paperclip_missing_attachment_styles_test.rb +2 -2
- data/test/paperclip_test.rb +19 -17
- metadata +10 -6
- data/lib/paperclip/tasks/attachments.rb +0 -59
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MDk3MDQ5M2FjY2Q3OTIzMDQzNTg4YzE3OGMwMTU1YTBiZGM0ZDVmNg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MDkwNWQ0M2I2MzAwMDk0NDA4NDdhZDM0ZTFiODg3MjZlY2ZmYTU1NA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Y2U4ZDI0Y2Q3MGE2NTJmZTQ5MDZlODJiZDIzOTJlNjM5MDAwZDI5Yjk5NmYx
|
10
|
+
MWRmNjc1YjQ3MmI2YzMwMzU2ODIwZGI2NTcyZjNhY2I3YWVhOWViNTZmOTZj
|
11
|
+
Yjc1ZDI1OTExNWE3MTgxN2Y2Nzc5YzdjODU1ZjA1ZDk3ZjNjOGM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Y2RkZGY4MjViZTVjOTczMmRiZTNjYjBhYzMyNTRkODczOWVkMjdmMzU0ZDY0
|
14
|
+
ZmRkNGNiNGM2MjRkMmNjYTU4ODQzZTQwZmY5YmVmMGM1ZmE3NTZiYzRjMzIy
|
15
|
+
NDdkY2JkNDFmNTNhNDk0ZjAxNDZhNWNkZDk3ZTU0YjAyNzI5ZDM=
|
data/Appraisals
CHANGED
data/NEWS
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
New in 3.5.1:
|
2
|
+
|
3
|
+
* Bug Fix: Returned the class-level `attachment_definitions` method for compatability.
|
4
|
+
* Improvement: Ensured compatability with Rails 4
|
5
|
+
* Improvement: Added Rails 4 to the Appraisals
|
6
|
+
* Bug Fix: #1296, where validations were generating errors
|
7
|
+
* Improvement: Specify MIT license in the gemspec
|
8
|
+
|
1
9
|
New in 3.5.0:
|
2
10
|
|
3
11
|
* Feature: Handle Base64-encoded data URIs as uploads
|
@@ -7,17 +7,14 @@ Feature: Rails integration
|
|
7
7
|
And I run a migration
|
8
8
|
And I update my new user view to include the file upload field
|
9
9
|
And I update my user view to include the attachment
|
10
|
+
And I allow the attachment to be submitted
|
10
11
|
|
11
12
|
Scenario: Configure defaults for all attachments through Railtie
|
12
13
|
Given I add this snippet to config/application.rb:
|
13
14
|
"""
|
14
15
|
config.paperclip_defaults = {:url => "/paperclip/custom/:attachment/:style/:filename"}
|
15
16
|
"""
|
16
|
-
|
17
|
-
"""
|
18
|
-
attr_accessible :name, :attachment
|
19
|
-
has_attached_file :attachment
|
20
|
-
"""
|
17
|
+
And I attach :attachment
|
21
18
|
And I start the rails application
|
22
19
|
When I go to the new user page
|
23
20
|
And I fill in "Name" with "something"
|
@@ -28,10 +25,9 @@ Feature: Rails integration
|
|
28
25
|
And the file at "/paperclip/custom/attachments/original/5k.png" should be the same as "test/fixtures/5k.png"
|
29
26
|
|
30
27
|
Scenario: Filesystem integration test
|
31
|
-
Given I
|
28
|
+
Given I attach :attachment with:
|
32
29
|
"""
|
33
|
-
|
34
|
-
has_attached_file :attachment, :url => "/system/:attachment/:style/:filename"
|
30
|
+
:url => "/system/:attachment/:style/:filename"
|
35
31
|
"""
|
36
32
|
And I start the rails application
|
37
33
|
When I go to the new user page
|
@@ -43,14 +39,12 @@ Feature: Rails integration
|
|
43
39
|
And the file at "/system/attachments/original/5k.png" should be the same as "test/fixtures/5k.png"
|
44
40
|
|
45
41
|
Scenario: S3 Integration test
|
46
|
-
Given I
|
42
|
+
Given I attach :attachment with:
|
47
43
|
"""
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
:s3_credentials => Rails.root.join("config/s3.yml"),
|
53
|
-
:styles => { :square => "100x100#" }
|
44
|
+
:storage => :s3,
|
45
|
+
:path => "/:attachment/:style/:filename",
|
46
|
+
:s3_credentials => Rails.root.join("config/s3.yml"),
|
47
|
+
:styles => { :square => "100x100#" }
|
54
48
|
"""
|
55
49
|
And I write to "config/s3.yml" with:
|
56
50
|
"""
|
data/features/rake_tasks.feature
CHANGED
@@ -5,10 +5,9 @@ Feature: Rake tasks
|
|
5
5
|
And I run a rails generator to generate a "User" scaffold with "name:string"
|
6
6
|
And I run a paperclip generator to add a paperclip "attachment" to the "User" model
|
7
7
|
And I run a migration
|
8
|
-
And I
|
8
|
+
And I attach :attachment with:
|
9
9
|
"""
|
10
|
-
|
11
|
-
has_attached_file :attachment, :path => ":rails_root/public/system/:attachment/:style/:filename"
|
10
|
+
:path => ":rails_root/public/system/:attachment/:style/:filename"
|
12
11
|
"""
|
13
12
|
|
14
13
|
Scenario: Paperclip refresh thumbnails task
|
@@ -15,6 +15,8 @@ Given /^I generate a new rails application$/ do
|
|
15
15
|
gem "gherkin"
|
16
16
|
gem "aws-sdk"
|
17
17
|
"""
|
18
|
+
And I remove turbolinks
|
19
|
+
And I empty the application.js file
|
18
20
|
And I configure the application to use "paperclip" from this project
|
19
21
|
And I reset Bundler environment variable
|
20
22
|
And I successfully run `bundle install --local`
|
@@ -29,6 +31,59 @@ Given "I fix the application.rb for 3.0.12" do
|
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
34
|
+
Given "I allow the attachment to be submitted" do
|
35
|
+
in_current_dir do
|
36
|
+
transform_file("app/controllers/users_controller.rb") do |content|
|
37
|
+
content.gsub("params.require(:user).permit(:name)",
|
38
|
+
"params.require(:user).permit!")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Given "I remove turbolinks" do
|
44
|
+
in_current_dir do
|
45
|
+
transform_file("app/assets/javascripts/application.js") do |content|
|
46
|
+
content.gsub("//= require turbolinks", "")
|
47
|
+
end
|
48
|
+
transform_file("app/views/layouts/application.html.erb") do |content|
|
49
|
+
content.gsub(', "data-turbolinks-track" => true', "")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
Given /^I attach :attachment$/ do
|
55
|
+
attach_attachment("attachment")
|
56
|
+
end
|
57
|
+
|
58
|
+
Given /^I attach :attachment with:$/ do |definition|
|
59
|
+
attach_attachment("attachment", definition)
|
60
|
+
end
|
61
|
+
|
62
|
+
def attach_attachment(name, definition = nil)
|
63
|
+
snippet = ""
|
64
|
+
if using_protected_attributes?
|
65
|
+
snippet += "attr_accessible :name, :#{name}\n"
|
66
|
+
end
|
67
|
+
snippet += "has_attached_file :#{name}"
|
68
|
+
if definition
|
69
|
+
snippet += ", \n"
|
70
|
+
snippet += definition
|
71
|
+
end
|
72
|
+
in_current_dir do
|
73
|
+
transform_file("app/models/user.rb") do |content|
|
74
|
+
content.sub(/end\Z/, "#{snippet}\nend")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
Given "I empty the application.js file" do
|
80
|
+
in_current_dir do
|
81
|
+
transform_file("app/assets/javascripts/application.js") do |content|
|
82
|
+
""
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
32
87
|
Given /^I run a rails generator to generate a "([^"]*)" scaffold with "([^"]*)"$/ do |model_name, attributes|
|
33
88
|
step %[I successfully run `bundle exec #{generator_command} scaffold #{model_name} #{attributes}`]
|
34
89
|
end
|
@@ -109,13 +164,7 @@ end
|
|
109
164
|
|
110
165
|
Then /^the file at "([^"]*)" should be the same as "([^"]*)"$/ do |web_file, path|
|
111
166
|
expected = IO.read(path)
|
112
|
-
actual =
|
113
|
-
Net::HTTP.get(URI.parse(web_file))
|
114
|
-
else
|
115
|
-
visit(web_file)
|
116
|
-
page.source
|
117
|
-
end
|
118
|
-
actual.force_encoding("UTF-8") if actual.respond_to?(:force_encoding)
|
167
|
+
actual = read_from_web(web_file)
|
119
168
|
actual.should == expected
|
120
169
|
end
|
121
170
|
|
@@ -145,3 +194,13 @@ Given /^I am using Rails newer than ([\d\.]+)$/ do |version|
|
|
145
194
|
pending "Not supported in Rails < #{version}"
|
146
195
|
end
|
147
196
|
end
|
197
|
+
|
198
|
+
def transform_file(filename)
|
199
|
+
if File.exists?(filename)
|
200
|
+
content = File.read(filename)
|
201
|
+
File.open(filename, "w") do |f|
|
202
|
+
content = yield(content)
|
203
|
+
f.write(content)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
When /^I attach the file "([^"]*)" to "([^"]*)" on S3$/ do |file_path, field|
|
2
|
-
definition = Paperclip::
|
2
|
+
definition = Paperclip::AttachmentRegistry.definitions_for(User)[field.downcase.to_sym]
|
3
3
|
path = "https://paperclip.s3.amazonaws.com#{definition[:path]}"
|
4
4
|
path.gsub!(':filename', File.basename(file_path))
|
5
5
|
path.gsub!(/:([^\/\.]+)/) do |match|
|
@@ -19,6 +19,16 @@ module FileHelpers
|
|
19
19
|
File.open("Gemfile", 'w'){ |file| file.write(gemfile) }
|
20
20
|
end
|
21
21
|
end
|
22
|
+
|
23
|
+
def read_from_web(url)
|
24
|
+
file = if url.match %r{^https?://}
|
25
|
+
Net::HTTP.get(URI.parse(url))
|
26
|
+
else
|
27
|
+
visit(url)
|
28
|
+
page.source
|
29
|
+
end
|
30
|
+
file.force_encoding("UTF-8") if file.respond_to?(:force_encoding)
|
31
|
+
end
|
22
32
|
end
|
23
33
|
|
24
34
|
World(FileHelpers)
|
data/features/support/rails.rb
CHANGED
@@ -31,16 +31,32 @@ module RailsCommandHelpers
|
|
31
31
|
@framework_version ||= `rails -v`[/^Rails (.+)$/, 1]
|
32
32
|
end
|
33
33
|
|
34
|
+
def framework_major_version
|
35
|
+
framework_version.split(".").first.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def using_protected_attributes?
|
39
|
+
framework_major_version < 4
|
40
|
+
end
|
41
|
+
|
34
42
|
def new_application_command
|
35
43
|
"rails new"
|
36
44
|
end
|
37
45
|
|
38
46
|
def generator_command
|
39
|
-
|
47
|
+
if framework_major_version >= 4
|
48
|
+
"rails generate"
|
49
|
+
else
|
50
|
+
"script/rails generate"
|
51
|
+
end
|
40
52
|
end
|
41
53
|
|
42
54
|
def runner_command
|
43
|
-
|
55
|
+
if framework_major_version >= 4
|
56
|
+
"rails runner"
|
57
|
+
else
|
58
|
+
"script/rails runner"
|
59
|
+
end
|
44
60
|
end
|
45
61
|
end
|
46
62
|
World(RailsCommandHelpers)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file was generated by Appraisal
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gem "jruby-openssl", :platform=>:jruby
|
6
|
+
gem "activerecord-jdbcsqlite3-adapter", :platform=>:jruby
|
7
|
+
gem "sqlite3", :platform=>:ruby
|
8
|
+
gem "rails", "~> 4.0.0"
|
9
|
+
gem "paperclip", :path=>"../"
|
10
|
+
|
11
|
+
gemspec :path=>"../"
|
data/lib/paperclip.rb
CHANGED
@@ -51,7 +51,7 @@ require 'paperclip/validators'
|
|
51
51
|
require 'paperclip/logger'
|
52
52
|
require 'paperclip/helpers'
|
53
53
|
require 'paperclip/has_attached_file'
|
54
|
-
require 'paperclip/
|
54
|
+
require 'paperclip/attachment_registry'
|
55
55
|
require 'paperclip/filename_cleaner'
|
56
56
|
require 'mime/types'
|
57
57
|
require 'logger'
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Paperclip
|
4
|
+
class AttachmentRegistry
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def self.register(klass, attachment_name, attachment_options)
|
8
|
+
instance.register(klass, attachment_name, attachment_options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.clear
|
12
|
+
instance.clear
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.names_for(klass)
|
16
|
+
instance.names_for(klass)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.each_definition(&block)
|
20
|
+
instance.each_definition(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.definitions_for(klass)
|
24
|
+
instance.definitions_for(klass)
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
clear
|
29
|
+
end
|
30
|
+
|
31
|
+
def register(klass, attachment_name, attachment_options)
|
32
|
+
@attachments ||= {}
|
33
|
+
@attachments[klass] ||= {}
|
34
|
+
@attachments[klass][attachment_name] = attachment_options
|
35
|
+
end
|
36
|
+
|
37
|
+
def clear
|
38
|
+
@attachments = Hash.new { |h,k| h[k] = {} }
|
39
|
+
end
|
40
|
+
|
41
|
+
def names_for(klass)
|
42
|
+
@attachments[klass].keys
|
43
|
+
end
|
44
|
+
|
45
|
+
def each_definition
|
46
|
+
@attachments.each do |klass, attachments|
|
47
|
+
attachments.each do |name, options|
|
48
|
+
yield klass, name, options
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def definitions_for(klass)
|
54
|
+
@attachments[klass]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,5 +1,22 @@
|
|
1
1
|
module Paperclip
|
2
2
|
class ContentTypeDetector
|
3
|
+
# The content-type detection strategy is as follows:
|
4
|
+
#
|
5
|
+
# 1. Blank/Empty files: If there's no filename or the file is empty,
|
6
|
+
# provide a sensible default (application/octet-stream or inode/x-empty)
|
7
|
+
#
|
8
|
+
# 2. Calculated match: Return the first result that is found by both the
|
9
|
+
# `file` command and MIME::Types.
|
10
|
+
#
|
11
|
+
# 3. Standard types: Return the first standard (without an x- prefix) entry
|
12
|
+
# in MIME::Types
|
13
|
+
#
|
14
|
+
# 4. Experimental types: If there were no standard types in MIME::Types
|
15
|
+
# list, try to return the first experimental one
|
16
|
+
#
|
17
|
+
# 5. Raw `file` command: Just use the output of the `file` command raw, or
|
18
|
+
# a sensible default. This is cached from Step 2.
|
19
|
+
|
3
20
|
EMPTY_TYPE = "inode/x-empty"
|
4
21
|
SENSIBLE_DEFAULT = "application/octet-stream"
|
5
22
|
|
@@ -7,17 +24,20 @@ module Paperclip
|
|
7
24
|
@filename = filename
|
8
25
|
end
|
9
26
|
|
27
|
+
# Returns a String describing the file's content type
|
10
28
|
def detect
|
11
29
|
if blank_name?
|
12
30
|
SENSIBLE_DEFAULT
|
13
31
|
elsif empty_file?
|
14
32
|
EMPTY_TYPE
|
15
|
-
elsif
|
16
|
-
|
17
|
-
elsif
|
18
|
-
|
33
|
+
elsif calculated_type_matches.any?
|
34
|
+
calculated_type_matches.first
|
35
|
+
elsif official_type_matches.any?
|
36
|
+
official_type_matches.first
|
37
|
+
elsif unofficial_type_matches.any?
|
38
|
+
unofficial_type_matches.first
|
19
39
|
else
|
20
|
-
|
40
|
+
type_from_file_command || SENSIBLE_DEFAULT
|
21
41
|
end.to_s
|
22
42
|
end
|
23
43
|
|
@@ -31,26 +51,28 @@ module Paperclip
|
|
31
51
|
@filename.nil? || @filename.empty?
|
32
52
|
end
|
33
53
|
|
54
|
+
def empty?
|
55
|
+
File.exists?(@filename) && File.size(@filename) == 0
|
56
|
+
end
|
57
|
+
|
34
58
|
def possible_types
|
35
|
-
|
59
|
+
MIME::Types.type_for(@filename).collect(&:content_type)
|
36
60
|
end
|
37
61
|
|
38
|
-
def
|
39
|
-
possible_types.
|
62
|
+
def calculated_type_matches
|
63
|
+
possible_types.select{|content_type| content_type == type_from_file_command }
|
40
64
|
end
|
41
65
|
|
42
|
-
def
|
43
|
-
possible_types.
|
66
|
+
def official_type_matches
|
67
|
+
possible_types.reject{|content_type| content_type.match(/\/x-/) }
|
44
68
|
end
|
45
69
|
|
46
|
-
def
|
47
|
-
|
48
|
-
(official_types.first || possible_types.first).content_type
|
70
|
+
def unofficial_type_matches
|
71
|
+
possible_types.select{|content_type| content_type.match(/\/x-/) }
|
49
72
|
end
|
50
73
|
|
51
74
|
def type_from_file_command
|
52
|
-
FileCommandContentTypeDetector.new(@filename).detect
|
75
|
+
@type_from_file_command ||= FileCommandContentTypeDetector.new(@filename).detect
|
53
76
|
end
|
54
|
-
|
55
77
|
end
|
56
78
|
end
|
@@ -12,10 +12,10 @@ module Paperclip
|
|
12
12
|
|
13
13
|
def define
|
14
14
|
define_flush_errors
|
15
|
-
|
15
|
+
define_getters
|
16
16
|
define_setter
|
17
17
|
define_query
|
18
|
-
|
18
|
+
register_new_attachment
|
19
19
|
add_active_record_callbacks
|
20
20
|
add_paperclip_callbacks
|
21
21
|
end
|
@@ -29,7 +29,12 @@ module Paperclip
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
32
|
+
def define_getters
|
33
|
+
define_instance_getter
|
34
|
+
define_class_getter
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_instance_getter
|
33
38
|
name = @name
|
34
39
|
options = @options
|
35
40
|
|
@@ -50,9 +55,12 @@ module Paperclip
|
|
50
55
|
end
|
51
56
|
end
|
52
57
|
|
58
|
+
def define_class_getter
|
59
|
+
@klass.extend(ClassMethods)
|
60
|
+
end
|
61
|
+
|
53
62
|
def define_setter
|
54
63
|
name = @name
|
55
|
-
|
56
64
|
@klass.send :define_method, "#{@name}=" do |file|
|
57
65
|
send(name).assign(file)
|
58
66
|
end
|
@@ -60,14 +68,13 @@ module Paperclip
|
|
60
68
|
|
61
69
|
def define_query
|
62
70
|
name = @name
|
63
|
-
|
64
71
|
@klass.send :define_method, "#{@name}?" do
|
65
72
|
send(name).file?
|
66
73
|
end
|
67
74
|
end
|
68
75
|
|
69
|
-
def
|
70
|
-
Paperclip::
|
76
|
+
def register_new_attachment
|
77
|
+
Paperclip::AttachmentRegistry.register(@klass, @name, @options)
|
71
78
|
end
|
72
79
|
|
73
80
|
def add_active_record_callbacks
|
@@ -82,5 +89,11 @@ module Paperclip
|
|
82
89
|
:define_paperclip_callbacks,
|
83
90
|
:post_process, :"#{@name}_post_process")
|
84
91
|
end
|
92
|
+
|
93
|
+
module ClassMethods
|
94
|
+
def attachment_definitions
|
95
|
+
Paperclip::AttachmentRegistry.definitions_for(self)
|
96
|
+
end
|
97
|
+
end
|
85
98
|
end
|
86
99
|
end
|
@@ -46,7 +46,11 @@ module Paperclip
|
|
46
46
|
@file = StringIO.new(".")
|
47
47
|
@subject.send(@attachment_name).assign(@file)
|
48
48
|
@subject.valid?
|
49
|
-
|
49
|
+
expected_message = [
|
50
|
+
@attachment_name.to_s.titleize,
|
51
|
+
I18n.t(:blank, scope: [:errors, :messages])
|
52
|
+
].join(' ')
|
53
|
+
@subject.errors.full_messages.exclude?(expected_message)
|
50
54
|
end
|
51
55
|
end
|
52
56
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'paperclip/
|
1
|
+
require 'paperclip/attachment_registry'
|
2
2
|
require 'set'
|
3
3
|
|
4
4
|
module Paperclip
|
@@ -34,7 +34,7 @@ module Paperclip
|
|
34
34
|
# }
|
35
35
|
def self.current_attachments_styles
|
36
36
|
Hash.new.tap do |current_styles|
|
37
|
-
Paperclip::
|
37
|
+
Paperclip::AttachmentRegistry.each_definition do |klass, attachment_name, attachment_attributes|
|
38
38
|
# TODO: is it even possible to take into account Procs?
|
39
39
|
next if attachment_attributes[:styles].kind_of?(Proc)
|
40
40
|
attachment_attributes[:styles].try(:keys).try(:each) do |style_name|
|
data/lib/paperclip/version.rb
CHANGED
data/lib/tasks/paperclip.rake
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'paperclip/
|
1
|
+
require 'paperclip/attachment_registry'
|
2
2
|
|
3
3
|
module Paperclip
|
4
4
|
module Task
|
@@ -12,7 +12,7 @@ module Paperclip
|
|
12
12
|
klass = Paperclip.class_for(klass.to_s)
|
13
13
|
name = ENV['ATTACHMENT'] || ENV['attachment']
|
14
14
|
|
15
|
-
attachment_names = Paperclip::
|
15
|
+
attachment_names = Paperclip::AttachmentRegistry.names_for(klass)
|
16
16
|
|
17
17
|
if attachment_names.empty?
|
18
18
|
raise "Class #{klass.name} has no attachments specified"
|
data/paperclip.gemspec
CHANGED
@@ -10,6 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.homepage = "https://github.com/thoughtbot/paperclip"
|
11
11
|
s.summary = "File attachments as attributes for ActiveRecord"
|
12
12
|
s.description = "Easy upload management for ActiveRecord"
|
13
|
+
s.license = "MIT"
|
13
14
|
|
14
15
|
s.rubyforge_project = "paperclip"
|
15
16
|
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require './test/helper'
|
2
|
+
|
3
|
+
class AttachmentDefinitionsTest < Test::Unit::TestCase
|
4
|
+
should 'return all of the attachments on the class' do
|
5
|
+
reset_class "Dummy"
|
6
|
+
Dummy.has_attached_file :avatar, {:path => "abc"}
|
7
|
+
Dummy.has_attached_file :other_attachment, {:url => "123"}
|
8
|
+
expected = {:avatar => {:path => "abc"}, :other_attachment => {:url => "123"}}
|
9
|
+
|
10
|
+
assert_equal expected, Dummy.attachment_definitions
|
11
|
+
end
|
12
|
+
end
|
@@ -1,30 +1,30 @@
|
|
1
1
|
require './test/helper'
|
2
|
-
require 'paperclip/
|
2
|
+
require 'paperclip/attachment_registry'
|
3
3
|
|
4
|
-
class
|
4
|
+
class AttachmentRegistryTest < Test::Unit::TestCase
|
5
5
|
def setup
|
6
|
-
Paperclip::
|
6
|
+
Paperclip::AttachmentRegistry.clear
|
7
7
|
end
|
8
8
|
|
9
9
|
context '.names_for' do
|
10
10
|
should 'include attachment names for the given class' do
|
11
11
|
foo = Class.new
|
12
|
-
Paperclip::
|
12
|
+
Paperclip::AttachmentRegistry.register(foo, :avatar, {})
|
13
13
|
|
14
|
-
assert_equal [:avatar], Paperclip::
|
14
|
+
assert_equal [:avatar], Paperclip::AttachmentRegistry.names_for(foo)
|
15
15
|
end
|
16
16
|
|
17
17
|
should 'not include attachment names for other classes' do
|
18
18
|
foo = Class.new
|
19
19
|
bar = Class.new
|
20
|
-
Paperclip::
|
21
|
-
Paperclip::
|
20
|
+
Paperclip::AttachmentRegistry.register(foo, :avatar, {})
|
21
|
+
Paperclip::AttachmentRegistry.register(bar, :lover, {})
|
22
22
|
|
23
|
-
assert_equal [:lover], Paperclip::
|
23
|
+
assert_equal [:lover], Paperclip::AttachmentRegistry.names_for(bar)
|
24
24
|
end
|
25
25
|
|
26
26
|
should 'produce the empty array for a missing key' do
|
27
|
-
assert_empty Paperclip::
|
27
|
+
assert_empty Paperclip::AttachmentRegistry.names_for(Class.new)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -32,15 +32,15 @@ class AttachmentsTest < Test::Unit::TestCase
|
|
32
32
|
should 'call the block with the class, attachment name, and options' do
|
33
33
|
foo = Class.new
|
34
34
|
expected_accumulations = [
|
35
|
-
[foo
|
35
|
+
[foo, :avatar, { yo: 'greeting' }],
|
36
36
|
[foo, :greeter, { ciao: 'greeting' }]
|
37
37
|
]
|
38
38
|
expected_accumulations.each do |args|
|
39
|
-
Paperclip::
|
39
|
+
Paperclip::AttachmentRegistry.register(*args)
|
40
40
|
end
|
41
41
|
accumulations = []
|
42
42
|
|
43
|
-
Paperclip::
|
43
|
+
Paperclip::AttachmentRegistry.each_definition do |*args|
|
44
44
|
accumulations << args
|
45
45
|
end
|
46
46
|
|
@@ -55,10 +55,10 @@ class AttachmentsTest < Test::Unit::TestCase
|
|
55
55
|
greeter: { ciao: 'greeting' }
|
56
56
|
}
|
57
57
|
foo = Class.new
|
58
|
-
Paperclip::
|
59
|
-
Paperclip::
|
58
|
+
Paperclip::AttachmentRegistry.register(foo, :avatar, { yo: 'greeting' })
|
59
|
+
Paperclip::AttachmentRegistry.register(foo, :greeter, { ciao: 'greeting' })
|
60
60
|
|
61
|
-
definitions = Paperclip::
|
61
|
+
definitions = Paperclip::AttachmentRegistry.definitions_for(foo)
|
62
62
|
|
63
63
|
assert_equal expected_definitions, definitions
|
64
64
|
end
|
@@ -67,11 +67,11 @@ class AttachmentsTest < Test::Unit::TestCase
|
|
67
67
|
context '.clear' do
|
68
68
|
should 'remove all of the existing attachment definitions' do
|
69
69
|
foo = Class.new
|
70
|
-
Paperclip::
|
70
|
+
Paperclip::AttachmentRegistry.register(foo, :greeter, { ciao: 'greeting' })
|
71
71
|
|
72
|
-
Paperclip::
|
72
|
+
Paperclip::AttachmentRegistry.clear
|
73
73
|
|
74
|
-
assert_empty Paperclip::
|
74
|
+
assert_empty Paperclip::AttachmentRegistry.names_for(foo)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
data/test/attachment_test.rb
CHANGED
@@ -201,7 +201,10 @@ class AttachmentTest < Test::Unit::TestCase
|
|
201
201
|
dummy = Dummy.new
|
202
202
|
dummy.id = 1234
|
203
203
|
dummy.avatar_file_name = "fake.jpg"
|
204
|
-
expected_string = '{"
|
204
|
+
expected_string = '{"avatar":"/system/dummies/avatars/000/001/234/original/fake.jpg"}'
|
205
|
+
if ActiveRecord::Base.include_root_in_json # This is true by default in Rails 3, and false in 4
|
206
|
+
expected_string = %({"dummy":#{expected_string}})
|
207
|
+
end
|
205
208
|
# active_model pre-3.2 checks only by calling any? on it, thus it doesn't work if it is empty
|
206
209
|
assert_equal expected_string, dummy.to_json(:only => [:dummy_key_for_old_active_model], :methods => [:avatar])
|
207
210
|
end
|
@@ -1,40 +1,50 @@
|
|
1
1
|
require './test/helper'
|
2
2
|
|
3
3
|
class ContentTypeDetectorTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
assert_equal "image/jpeg", Paperclip::ContentTypeDetector.new(@filename).detect
|
8
|
-
end
|
4
|
+
should 'give a sensible default when the name is empty' do
|
5
|
+
assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new("").detect
|
6
|
+
end
|
9
7
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
should 'return the empty content type when the file is empty' do
|
9
|
+
tempfile = Tempfile.new("empty")
|
10
|
+
assert_equal "inode/x-empty", Paperclip::ContentTypeDetector.new(tempfile.path).detect
|
11
|
+
end
|
14
12
|
|
15
|
-
|
16
|
-
|
13
|
+
should 'return content type of file if it is an acceptable type' do
|
14
|
+
MIME::Types.stubs(:type_for).returns([MIME::Type.new('application/mp4'), MIME::Type.new('video/mp4'), MIME::Type.new('audio/mp4')])
|
15
|
+
Paperclip.stubs(:run).returns("video/mp4")
|
16
|
+
@filename = "my_file.mp4"
|
17
|
+
assert_equal "video/mp4", Paperclip::ContentTypeDetector.new(@filename).detect
|
18
|
+
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
should 'find the first result that matches from the official types' do
|
21
|
+
@filename = "/path/to/something.bmp"
|
22
|
+
assert_equal "image/bmp", Paperclip::ContentTypeDetector.new(@filename).detect
|
23
|
+
end
|
21
24
|
|
22
|
-
|
23
|
-
|
25
|
+
should 'find the first unofficial result for this filename if no official ones exist' do
|
26
|
+
@filename = "/path/to/something.aiff"
|
27
|
+
assert_equal "audio/x-aiff", Paperclip::ContentTypeDetector.new(@filename).detect
|
28
|
+
end
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
should 'find the right type in the list via the file command' do
|
31
|
+
@filename = "#{Dir.tmpdir}/something.hahalolnotreal"
|
32
|
+
File.open(@filename, "w+") do |file|
|
33
|
+
file.puts "This is a text file."
|
34
|
+
file.rewind
|
35
|
+
assert_equal "text/plain", Paperclip::ContentTypeDetector.new(file.path).detect
|
27
36
|
end
|
37
|
+
FileUtils.rm @filename
|
38
|
+
end
|
28
39
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
40
|
+
should 'return a sensible default if something is wrong, like the file is gone' do
|
41
|
+
@filename = "/path/to/nothing"
|
42
|
+
assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new(@filename).detect
|
43
|
+
end
|
33
44
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
45
|
+
should 'return a sensible default when the file command is missing' do
|
46
|
+
Paperclip.stubs(:run).raises(Cocaine::CommandLineError.new)
|
47
|
+
@filename = "/path/to/something"
|
48
|
+
assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new(@filename).detect
|
39
49
|
end
|
40
50
|
end
|
@@ -15,12 +15,16 @@ class HasAttachedFileTest < Test::Unit::TestCase
|
|
15
15
|
assert_adding_attachment('avatar').defines_method('avatar?')
|
16
16
|
end
|
17
17
|
|
18
|
+
should 'define a method on the class to get all of its attachments' do
|
19
|
+
assert_adding_attachment('avatar').defines_class_method('attachment_definitions')
|
20
|
+
end
|
21
|
+
|
18
22
|
should 'flush errors as part of validations' do
|
19
23
|
assert_adding_attachment('avatar').defines_validation
|
20
24
|
end
|
21
25
|
|
22
|
-
should 'register the attachment with Paperclip::
|
23
|
-
assert_adding_attachment('avatar').
|
26
|
+
should 'register the attachment with Paperclip::AttachmentRegistry' do
|
27
|
+
assert_adding_attachment('avatar').registers_attachment
|
24
28
|
end
|
25
29
|
|
26
30
|
should 'define an after_save callback' do
|
@@ -64,6 +68,17 @@ class HasAttachedFileTest < Test::Unit::TestCase
|
|
64
68
|
end
|
65
69
|
end
|
66
70
|
|
71
|
+
def defines_class_method(method_name)
|
72
|
+
a_class = stub_class
|
73
|
+
a_class.class.stubs(:define_method)
|
74
|
+
|
75
|
+
Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {})
|
76
|
+
|
77
|
+
assert_received(a_class, :extend) do |expect|
|
78
|
+
expect.with(Paperclip::HasAttachedFile::ClassMethods)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
67
82
|
def defines_validation
|
68
83
|
a_class = stub_class
|
69
84
|
|
@@ -74,13 +89,13 @@ class HasAttachedFileTest < Test::Unit::TestCase
|
|
74
89
|
end
|
75
90
|
end
|
76
91
|
|
77
|
-
def
|
92
|
+
def registers_attachment
|
78
93
|
a_class = stub_class
|
79
|
-
Paperclip::
|
94
|
+
Paperclip::AttachmentRegistry.stubs(:register)
|
80
95
|
|
81
96
|
Paperclip::HasAttachedFile.define_on(a_class, @attachment_name, {size: 1})
|
82
97
|
|
83
|
-
assert_received(Paperclip::
|
98
|
+
assert_received(Paperclip::AttachmentRegistry, :register) do |expect|
|
84
99
|
expect.with(a_class, @attachment_name, {size: 1})
|
85
100
|
end
|
86
101
|
end
|
@@ -103,6 +118,7 @@ class HasAttachedFileTest < Test::Unit::TestCase
|
|
103
118
|
before_destroy: nil,
|
104
119
|
after_destroy: nil,
|
105
120
|
define_paperclip_callbacks: nil,
|
121
|
+
extend: nil,
|
106
122
|
name: 'Billy')
|
107
123
|
end
|
108
124
|
end
|
data/test/helper.rb
CHANGED
@@ -2,15 +2,14 @@ require 'rubygems'
|
|
2
2
|
require 'tempfile'
|
3
3
|
require 'pathname'
|
4
4
|
require 'test/unit'
|
5
|
-
|
6
|
-
require 'shoulda'
|
7
|
-
require 'mocha/setup'
|
8
|
-
require 'bourne'
|
9
|
-
|
10
5
|
require 'active_record'
|
11
6
|
require 'active_record/version'
|
12
7
|
require 'active_support'
|
13
8
|
require 'active_support/core_ext'
|
9
|
+
require 'shoulda'
|
10
|
+
require 'mocha/setup'
|
11
|
+
require 'bourne'
|
12
|
+
require 'shoulda/context'
|
14
13
|
require 'mime/types'
|
15
14
|
require 'pathname'
|
16
15
|
require 'ostruct'
|
@@ -48,10 +47,14 @@ require './shoulda_macros/paperclip'
|
|
48
47
|
|
49
48
|
FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
|
50
49
|
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
51
|
-
ActiveRecord::Base.logger =
|
50
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
52
51
|
ActiveRecord::Base.establish_connection(config['test'])
|
53
52
|
Paperclip.options[:logger] = ActiveRecord::Base.logger
|
54
53
|
|
54
|
+
def using_protected_attributes?
|
55
|
+
ActiveRecord::VERSION::MAJOR < 4
|
56
|
+
end
|
57
|
+
|
55
58
|
def require_everything_in_directory(directory_name)
|
56
59
|
Dir[File.join(File.dirname(__FILE__), directory_name, '*')].each do |f|
|
57
60
|
require f
|
@@ -23,6 +23,28 @@ class ValidateAttachmentPresenceMatcherTest < Test::Unit::TestCase
|
|
23
23
|
should_accept_dummy_class
|
24
24
|
end
|
25
25
|
|
26
|
+
context "given an instance with other attachment validations" do
|
27
|
+
setup do
|
28
|
+
reset_table("dummies") do |d|
|
29
|
+
d.string :avatar_file_name
|
30
|
+
d.string :avatar_content_type
|
31
|
+
end
|
32
|
+
|
33
|
+
@dummy_class.class_eval do
|
34
|
+
validates_attachment_presence :avatar
|
35
|
+
validates_attachment_content_type :avatar, :content_type => 'image/gif'
|
36
|
+
end
|
37
|
+
|
38
|
+
@dummy = @dummy_class.new
|
39
|
+
@matcher = self.class.validate_attachment_presence(:avatar)
|
40
|
+
end
|
41
|
+
|
42
|
+
should "it should validate properly" do
|
43
|
+
@dummy.avatar = File.new fixture_file('5k.png')
|
44
|
+
assert_accepts @matcher, @dummy
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
26
48
|
context "using an :if to control the validation" do
|
27
49
|
setup do
|
28
50
|
@dummy_class.class_eval do
|
@@ -2,12 +2,12 @@ require './test/helper'
|
|
2
2
|
|
3
3
|
class PaperclipMissingAttachmentStylesTest < Test::Unit::TestCase
|
4
4
|
def setup
|
5
|
-
Paperclip::
|
5
|
+
Paperclip::AttachmentRegistry.clear
|
6
6
|
end
|
7
7
|
|
8
8
|
context "Paperclip" do
|
9
9
|
setup do
|
10
|
-
Paperclip::
|
10
|
+
Paperclip::AttachmentRegistry.clear
|
11
11
|
end
|
12
12
|
|
13
13
|
teardown do
|
data/test/paperclip_test.rb
CHANGED
@@ -123,28 +123,30 @@ class PaperclipTest < Test::Unit::TestCase
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
if using_protected_attributes?
|
127
|
+
context "that is attr_protected" do
|
128
|
+
setup do
|
129
|
+
Dummy.class_eval do
|
130
|
+
attr_protected :avatar
|
131
|
+
end
|
132
|
+
@dummy = Dummy.new
|
130
133
|
end
|
131
|
-
@dummy = Dummy.new
|
132
|
-
end
|
133
134
|
|
134
|
-
|
135
|
-
|
136
|
-
|
135
|
+
should "not assign the avatar on mass-set" do
|
136
|
+
@dummy.attributes = { :other => "I'm set!",
|
137
|
+
:avatar => @file }
|
137
138
|
|
138
|
-
|
139
|
-
|
140
|
-
|
139
|
+
assert_equal "I'm set!", @dummy.other
|
140
|
+
assert ! @dummy.avatar?
|
141
|
+
end
|
141
142
|
|
142
|
-
|
143
|
-
|
144
|
-
|
143
|
+
should "still allow assigment on normal set" do
|
144
|
+
@dummy.other = "I'm set!"
|
145
|
+
@dummy.avatar = @file
|
145
146
|
|
146
|
-
|
147
|
-
|
147
|
+
assert_equal "I'm set!", @dummy.other
|
148
|
+
assert @dummy.avatar?
|
149
|
+
end
|
148
150
|
end
|
149
151
|
end
|
150
152
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paperclip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.5.
|
4
|
+
version: 3.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Yurek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-07-
|
11
|
+
date: 2013-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -391,11 +391,13 @@ files:
|
|
391
391
|
- gemfiles/3.0.gemfile
|
392
392
|
- gemfiles/3.1.gemfile
|
393
393
|
- gemfiles/3.2.gemfile
|
394
|
+
- gemfiles/4.0.gemfile
|
394
395
|
- lib/generators/paperclip/USAGE
|
395
396
|
- lib/generators/paperclip/paperclip_generator.rb
|
396
397
|
- lib/generators/paperclip/templates/paperclip_migration.rb.erb
|
397
398
|
- lib/paperclip.rb
|
398
399
|
- lib/paperclip/attachment.rb
|
400
|
+
- lib/paperclip/attachment_registry.rb
|
399
401
|
- lib/paperclip/callbacks.rb
|
400
402
|
- lib/paperclip/content_type_detector.rb
|
401
403
|
- lib/paperclip/errors.rb
|
@@ -436,7 +438,6 @@ files:
|
|
436
438
|
- lib/paperclip/storage/fog.rb
|
437
439
|
- lib/paperclip/storage/s3.rb
|
438
440
|
- lib/paperclip/style.rb
|
439
|
-
- lib/paperclip/tasks/attachments.rb
|
440
441
|
- lib/paperclip/tempfile.rb
|
441
442
|
- lib/paperclip/tempfile_factory.rb
|
442
443
|
- lib/paperclip/thumbnail.rb
|
@@ -449,7 +450,9 @@ files:
|
|
449
450
|
- lib/tasks/paperclip.rake
|
450
451
|
- paperclip.gemspec
|
451
452
|
- shoulda_macros/paperclip.rb
|
453
|
+
- test/attachment_definitions_test.rb
|
452
454
|
- test/attachment_processing_test.rb
|
455
|
+
- test/attachment_registry_test.rb
|
453
456
|
- test/attachment_test.rb
|
454
457
|
- test/content_type_detector_test.rb
|
455
458
|
- test/database.yml
|
@@ -508,7 +511,6 @@ files:
|
|
508
511
|
- test/support/mock_interpolator.rb
|
509
512
|
- test/support/mock_model.rb
|
510
513
|
- test/support/mock_url_generator_builder.rb
|
511
|
-
- test/tasks/attachments_test.rb
|
512
514
|
- test/tempfile_factory_test.rb
|
513
515
|
- test/thumbnail_test.rb
|
514
516
|
- test/url_generator_test.rb
|
@@ -517,7 +519,8 @@ files:
|
|
517
519
|
- test/validators/attachment_size_validator_test.rb
|
518
520
|
- test/validators_test.rb
|
519
521
|
homepage: https://github.com/thoughtbot/paperclip
|
520
|
-
licenses:
|
522
|
+
licenses:
|
523
|
+
- MIT
|
521
524
|
metadata: {}
|
522
525
|
post_install_message: ! "##################################################\n# NOTE
|
523
526
|
FOR UPGRADING FROM PRE-3.0 VERSION #\n##################################################\n\nPaperclip
|
@@ -565,7 +568,9 @@ test_files:
|
|
565
568
|
- features/support/paths.rb
|
566
569
|
- features/support/rails.rb
|
567
570
|
- features/support/selectors.rb
|
571
|
+
- test/attachment_definitions_test.rb
|
568
572
|
- test/attachment_processing_test.rb
|
573
|
+
- test/attachment_registry_test.rb
|
569
574
|
- test/attachment_test.rb
|
570
575
|
- test/content_type_detector_test.rb
|
571
576
|
- test/database.yml
|
@@ -624,7 +629,6 @@ test_files:
|
|
624
629
|
- test/support/mock_interpolator.rb
|
625
630
|
- test/support/mock_model.rb
|
626
631
|
- test/support/mock_url_generator_builder.rb
|
627
|
-
- test/tasks/attachments_test.rb
|
628
632
|
- test/tempfile_factory_test.rb
|
629
633
|
- test/thumbnail_test.rb
|
630
634
|
- test/url_generator_test.rb
|
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
|
3
|
-
module Paperclip
|
4
|
-
module Tasks
|
5
|
-
class Attachments
|
6
|
-
include Singleton
|
7
|
-
|
8
|
-
def self.add(klass, attachment_name, attachment_options)
|
9
|
-
instance.add(klass, attachment_name, attachment_options)
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.clear
|
13
|
-
instance.clear
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.names_for(klass)
|
17
|
-
instance.names_for(klass)
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.each_definition(&block)
|
21
|
-
instance.each_definition(&block)
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.definitions_for(klass)
|
25
|
-
instance.definitions_for(klass)
|
26
|
-
end
|
27
|
-
|
28
|
-
def initialize
|
29
|
-
clear
|
30
|
-
end
|
31
|
-
|
32
|
-
def add(klass, attachment_name, attachment_options)
|
33
|
-
@attachments ||= {}
|
34
|
-
@attachments[klass] ||= {}
|
35
|
-
@attachments[klass][attachment_name] = attachment_options
|
36
|
-
end
|
37
|
-
|
38
|
-
def clear
|
39
|
-
@attachments = Hash.new { |h,k| h[k] = {} }
|
40
|
-
end
|
41
|
-
|
42
|
-
def names_for(klass)
|
43
|
-
@attachments[klass].keys
|
44
|
-
end
|
45
|
-
|
46
|
-
def each_definition
|
47
|
-
@attachments.each do |klass, attachments|
|
48
|
-
attachments.each do |name, options|
|
49
|
-
yield klass, name, options
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def definitions_for(klass)
|
55
|
-
@attachments[klass]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|