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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YjZlZGIxNTY3NDRlZTkyZjE2NmU4NTk3NDg0YTc5YjczODhjYzA2OA==
4
+ MDk3MDQ5M2FjY2Q3OTIzMDQzNTg4YzE3OGMwMTU1YTBiZGM0ZDVmNg==
5
5
  data.tar.gz: !binary |-
6
- NjI1NGVkNTkxNDE2MGZjYWJkYzVhMjZhMWNhNzFhYmYzNTUxNzZhMA==
6
+ MDkwNWQ0M2I2MzAwMDk0NDA4NDdhZDM0ZTFiODg3MjZlY2ZmYTU1NA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- Y2M4M2UyYjBlZTk4MzNlOGMwODdhM2I0YjIyYmI0YmQxODE1MjMwZTY0YTc5
10
- ZWUxNDAyNjlhOGNiNGRkOGE4YzNiZjNiMmQ2Mzg2ZmE2OGJhNDEwMDU4MTll
11
- MWUyYzkxOThiMmY0MzFkZjFlYzk1YWFhMWVhZTQwZjIyOWZhMjU=
9
+ Y2U4ZDI0Y2Q3MGE2NTJmZTQ5MDZlODJiZDIzOTJlNjM5MDAwZDI5Yjk5NmYx
10
+ MWRmNjc1YjQ3MmI2YzMwMzU2ODIwZGI2NTcyZjNhY2I3YWVhOWViNTZmOTZj
11
+ Yjc1ZDI1OTExNWE3MTgxN2Y2Nzc5YzdjODU1ZjA1ZDk3ZjNjOGM=
12
12
  data.tar.gz: !binary |-
13
- Njk5MTE2NDhkYzk3OWFlOWM2ODUwMjQ2MTIxMmQ1YWIyZDcyZDg5OWQyNTEw
14
- ZDczODg2NmRkMzMyMWJmMDY0ZWI3NDljNmJmMTQ0ODJkYTNiMWIyN2EyZTM4
15
- YTYyODEwMTE1NzA2ZWFmMjIzMDAwOTZkMjZmYjVjYjZkNDIwYTI=
13
+ Y2RkZGY4MjViZTVjOTczMmRiZTNjYjBhYzMyNTRkODczOWVkMjdmMzU0ZDY0
14
+ ZmRkNGNiNGM2MjRkMmNjYTU4ODQzZTQwZmY5YmVmMGM1ZmE3NTZiYzRjMzIy
15
+ NDdkY2JkNDFmNTNhNDk0ZjAxNDZhNWNkZDk3ZTU0YjAyNzI5ZDM=
data/Appraisals CHANGED
@@ -12,3 +12,8 @@ appraise "3.2" do
12
12
  gem "rails", "~> 3.2.6"
13
13
  gem "paperclip", :path => "../"
14
14
  end
15
+
16
+ appraise "4.0" do
17
+ gem "rails", "~> 4.0.0"
18
+ gem "paperclip", :path => "../"
19
+ end
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
- Given I add this snippet to the User model:
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 add this snippet to the User model:
28
+ Given I attach :attachment with:
32
29
  """
33
- attr_accessible :name, :attachment
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 add this snippet to the User model:
42
+ Given I attach :attachment with:
47
43
  """
48
- attr_accessible :name, :attachment
49
- has_attached_file :attachment,
50
- :storage => :s3,
51
- :path => "/:attachment/:style/:filename",
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
  """
@@ -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 add this snippet to the User model:
8
+ And I attach :attachment with:
9
9
  """
10
- attr_accessible :name, :attachment
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 = if web_file.match %r{^https?://}
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::Tasks::Attachments.definitions_for(User)[field.downcase.to_sym]
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)
@@ -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
- "script/rails generate"
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
- "script/rails runner"
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=>"../"
@@ -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/tasks/attachments'
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 !match?
16
- type_from_file_command
17
- elsif !multiple?
18
- possible_types.first
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
- best_type_match
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
- @possible_types ||= MIME::Types.type_for(@filename)
59
+ MIME::Types.type_for(@filename).collect(&:content_type)
36
60
  end
37
61
 
38
- def match?
39
- possible_types.length > 0
62
+ def calculated_type_matches
63
+ possible_types.select{|content_type| content_type == type_from_file_command }
40
64
  end
41
65
 
42
- def multiple?
43
- possible_types.length > 1
66
+ def official_type_matches
67
+ possible_types.reject{|content_type| content_type.match(/\/x-/) }
44
68
  end
45
69
 
46
- def best_type_match
47
- official_types = possible_types.reject {|type| type.content_type.match(/\/x-/) }
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
- define_getter
15
+ define_getters
16
16
  define_setter
17
17
  define_query
18
- register_with_rake_tasks
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 define_getter
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 register_with_rake_tasks
70
- Paperclip::Tasks::Attachments.add(@klass, @name, @options)
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
- @subject.errors[:"#{@attachment_name}"].blank?
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/tasks/attachments'
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::Tasks::Attachments.each_definition do |klass, attachment_name, attachment_attributes|
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|
@@ -1,3 +1,3 @@
1
1
  module Paperclip
2
- VERSION = "3.5.0" unless defined? Paperclip::VERSION
2
+ VERSION = "3.5.1" unless defined? Paperclip::VERSION
3
3
  end
@@ -1,4 +1,4 @@
1
- require 'paperclip/tasks/attachments'
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::Tasks::Attachments.names_for(klass)
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"
@@ -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/tasks/attachments'
2
+ require 'paperclip/attachment_registry'
3
3
 
4
- class AttachmentsTest < Test::Unit::TestCase
4
+ class AttachmentRegistryTest < Test::Unit::TestCase
5
5
  def setup
6
- Paperclip::Tasks::Attachments.clear
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::Tasks::Attachments.add(foo, :avatar, {})
12
+ Paperclip::AttachmentRegistry.register(foo, :avatar, {})
13
13
 
14
- assert_equal [:avatar], Paperclip::Tasks::Attachments.names_for(foo)
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::Tasks::Attachments.add(foo, :avatar, {})
21
- Paperclip::Tasks::Attachments.add(bar, :lover, {})
20
+ Paperclip::AttachmentRegistry.register(foo, :avatar, {})
21
+ Paperclip::AttachmentRegistry.register(bar, :lover, {})
22
22
 
23
- assert_equal [:lover], Paperclip::Tasks::Attachments.names_for(bar)
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::Tasks::Attachments.names_for(Class.new)
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,:avatar, { yo: 'greeting' }],
35
+ [foo, :avatar, { yo: 'greeting' }],
36
36
  [foo, :greeter, { ciao: 'greeting' }]
37
37
  ]
38
38
  expected_accumulations.each do |args|
39
- Paperclip::Tasks::Attachments.add(*args)
39
+ Paperclip::AttachmentRegistry.register(*args)
40
40
  end
41
41
  accumulations = []
42
42
 
43
- Paperclip::Tasks::Attachments.each_definition do |*args|
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::Tasks::Attachments.add(foo, :avatar, { yo: 'greeting' })
59
- Paperclip::Tasks::Attachments.add(foo, :greeter, { ciao: 'greeting' })
58
+ Paperclip::AttachmentRegistry.register(foo, :avatar, { yo: 'greeting' })
59
+ Paperclip::AttachmentRegistry.register(foo, :greeter, { ciao: 'greeting' })
60
60
 
61
- definitions = Paperclip::Tasks::Attachments.definitions_for(foo)
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::Tasks::Attachments.add(foo, :greeter, { ciao: 'greeting' })
70
+ Paperclip::AttachmentRegistry.register(foo, :greeter, { ciao: 'greeting' })
71
71
 
72
- Paperclip::Tasks::Attachments.clear
72
+ Paperclip::AttachmentRegistry.clear
73
73
 
74
- assert_empty Paperclip::Tasks::Attachments.names_for(foo)
74
+ assert_empty Paperclip::AttachmentRegistry.names_for(foo)
75
75
  end
76
76
  end
77
77
  end
@@ -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 = '{"dummy":{"avatar":"/system/dummies/avatars/000/001/234/original/fake.jpg"}}'
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
- context 'given a name' do
5
- should 'return a content type based on that name' do
6
- @filename = "/path/to/something.jpg"
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
- should 'return a content type based on the content of the file' do
11
- tempfile = Tempfile.new("something")
12
- tempfile.write("This is a file.")
13
- tempfile.rewind
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
- assert_equal "text/plain", Paperclip::ContentTypeDetector.new(tempfile.path).detect
16
- end
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
- should 'return an empty content type if the file is empty' do
19
- tempfile = Tempfile.new("something")
20
- tempfile.rewind
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
- assert_equal "inode/x-empty", Paperclip::ContentTypeDetector.new(tempfile.path).detect
23
- end
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
- should 'return a sensible default if no filename is supplied' do
26
- assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new('').detect
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
- should 'return a sensible default if something goes wrong' do
30
- @filename = "/path/to/something"
31
- assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new(@filename).detect
32
- end
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
- should 'return a sensible default when the file command is missing' do
35
- Paperclip.stubs(:run).raises(Cocaine::CommandLineError.new)
36
- @filename = "/path/to/something"
37
- assert_equal "application/octet-stream", Paperclip::ContentTypeDetector.new(@filename).detect
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::Tasks' do
23
- assert_adding_attachment('avatar').registers_with_tasks
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 registers_with_tasks
92
+ def registers_attachment
78
93
  a_class = stub_class
79
- Paperclip::Tasks::Attachments.stubs(:add)
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::Tasks::Attachments, :add) do |expect|
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
@@ -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 = ActiveSupport::BufferedLogger.new(File.dirname(__FILE__) + "/debug.log")
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::Tasks::Attachments.clear
5
+ Paperclip::AttachmentRegistry.clear
6
6
  end
7
7
 
8
8
  context "Paperclip" do
9
9
  setup do
10
- Paperclip::Tasks::Attachments.clear
10
+ Paperclip::AttachmentRegistry.clear
11
11
  end
12
12
 
13
13
  teardown do
@@ -123,28 +123,30 @@ class PaperclipTest < Test::Unit::TestCase
123
123
  end
124
124
  end
125
125
 
126
- context "that is attr_protected" do
127
- setup do
128
- Dummy.class_eval do
129
- attr_protected :avatar
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
- should "not assign the avatar on mass-set" do
135
- @dummy.attributes = { :other => "I'm set!",
136
- :avatar => @file }
135
+ should "not assign the avatar on mass-set" do
136
+ @dummy.attributes = { :other => "I'm set!",
137
+ :avatar => @file }
137
138
 
138
- assert_equal "I'm set!", @dummy.other
139
- assert ! @dummy.avatar?
140
- end
139
+ assert_equal "I'm set!", @dummy.other
140
+ assert ! @dummy.avatar?
141
+ end
141
142
 
142
- should "still allow assigment on normal set" do
143
- @dummy.other = "I'm set!"
144
- @dummy.avatar = @file
143
+ should "still allow assigment on normal set" do
144
+ @dummy.other = "I'm set!"
145
+ @dummy.avatar = @file
145
146
 
146
- assert_equal "I'm set!", @dummy.other
147
- assert @dummy.avatar?
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.0
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-19 00:00:00.000000000 Z
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