cloudfuji_paperclip 2.4.6 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/.gitignore +2 -0
  2. data/.travis.yml +9 -6
  3. data/Appraisals +6 -6
  4. data/CONTRIBUTING.md +34 -2
  5. data/Gemfile +2 -0
  6. data/NEWS +90 -0
  7. data/README.md +62 -29
  8. data/RUNNING_TESTS.md +4 -0
  9. data/Rakefile +7 -2
  10. data/UPGRADING +14 -0
  11. data/features/basic_integration.feature +11 -7
  12. data/features/rake_tasks.feature +1 -1
  13. data/features/step_definitions/attachment_steps.rb +11 -2
  14. data/features/step_definitions/rails_steps.rb +17 -79
  15. data/features/support/env.rb +3 -0
  16. data/features/support/fakeweb.rb +7 -0
  17. data/features/support/file_helpers.rb +24 -0
  18. data/features/support/rails.rb +3 -3
  19. data/gemfiles/{rails3_1.gemfile → 3.0.gemfile} +3 -1
  20. data/gemfiles/{rails2.gemfile → 3.1.gemfile} +3 -1
  21. data/gemfiles/{rails3.gemfile → 3.2.gemfile} +3 -1
  22. data/images.rake +21 -0
  23. data/lib/cloudfuji_paperclip.rb +1 -0
  24. data/lib/generators/paperclip/paperclip_generator.rb +1 -2
  25. data/lib/paperclip.rb +54 -319
  26. data/lib/paperclip/attachment.rb +86 -107
  27. data/lib/paperclip/attachment_options.rb +9 -0
  28. data/lib/paperclip/callbacks.rb +30 -0
  29. data/lib/paperclip/errors.rb +27 -0
  30. data/lib/paperclip/geometry.rb +6 -4
  31. data/lib/paperclip/glue.rb +23 -0
  32. data/lib/paperclip/helpers.rb +71 -0
  33. data/lib/paperclip/instance_methods.rb +35 -0
  34. data/lib/paperclip/interpolations.rb +4 -4
  35. data/lib/paperclip/io_adapters/attachment_adapter.rb +69 -0
  36. data/lib/paperclip/io_adapters/file_adapter.rb +81 -0
  37. data/lib/paperclip/io_adapters/identity_adapter.rb +12 -0
  38. data/lib/paperclip/io_adapters/nil_adapter.rb +34 -0
  39. data/lib/paperclip/io_adapters/registry.rb +32 -0
  40. data/lib/paperclip/io_adapters/stringio_adapter.rb +64 -0
  41. data/lib/paperclip/io_adapters/uploaded_file_adapter.rb +63 -0
  42. data/lib/paperclip/locales/en.yml +17 -0
  43. data/lib/paperclip/logger.rb +21 -0
  44. data/lib/paperclip/matchers/validate_attachment_content_type_matcher.rb +5 -5
  45. data/lib/paperclip/matchers/validate_attachment_presence_matcher.rb +7 -7
  46. data/lib/paperclip/matchers/validate_attachment_size_matcher.rb +11 -11
  47. data/lib/paperclip/missing_attachment_styles.rb +6 -9
  48. data/lib/paperclip/processor.rb +32 -17
  49. data/lib/paperclip/railtie.rb +13 -17
  50. data/lib/paperclip/storage/filesystem.rb +4 -13
  51. data/lib/paperclip/storage/fog.rb +33 -24
  52. data/lib/paperclip/storage/s3.rb +36 -28
  53. data/lib/paperclip/tempfile.rb +41 -0
  54. data/lib/paperclip/thumbnail.rb +2 -3
  55. data/lib/paperclip/validators.rb +45 -0
  56. data/lib/paperclip/validators/attachment_content_type_validator.rb +54 -0
  57. data/lib/paperclip/validators/attachment_presence_validator.rb +26 -0
  58. data/lib/paperclip/validators/attachment_size_validator.rb +102 -0
  59. data/lib/paperclip/version.rb +1 -1
  60. data/lib/tasks/paperclip.rake +4 -12
  61. data/paperclip.gemspec +15 -5
  62. data/test/adapter_registry_test.rb +32 -0
  63. data/test/attachment_adapter_test.rb +51 -0
  64. data/test/attachment_options_test.rb +27 -0
  65. data/test/attachment_test.rb +130 -46
  66. data/test/file_adapter_test.rb +88 -0
  67. data/test/generator_test.rb +78 -0
  68. data/test/geometry_test.rb +5 -5
  69. data/test/helper.rb +21 -22
  70. data/test/identity_adapter_test.rb +8 -0
  71. data/test/integration_test.rb +55 -102
  72. data/test/interpolations_test.rb +15 -5
  73. data/test/matchers/validate_attachment_content_type_matcher_test.rb +23 -0
  74. data/test/matchers/validate_attachment_presence_matcher_test.rb +21 -0
  75. data/test/matchers/validate_attachment_size_matcher_test.rb +37 -2
  76. data/test/nil_adapter_test.rb +25 -0
  77. data/test/paperclip_missing_attachment_styles_test.rb +16 -0
  78. data/test/paperclip_test.rb +34 -183
  79. data/test/storage/filesystem_test.rb +27 -27
  80. data/test/storage/fog_test.rb +68 -12
  81. data/test/storage/s3_live_test.rb +79 -38
  82. data/test/storage/s3_test.rb +204 -34
  83. data/test/stringio_adapter_test.rb +42 -0
  84. data/test/thumbnail_test.rb +29 -8
  85. data/test/uploaded_file_adapter_test.rb +98 -0
  86. data/test/url_generator_test.rb +8 -8
  87. data/test/validators/attachment_content_type_validator_test.rb +192 -0
  88. data/test/validators/attachment_presence_validator_test.rb +85 -0
  89. data/test/validators/attachment_size_validator_test.rb +207 -0
  90. data/test/validators_test.rb +25 -0
  91. metadata +166 -59
  92. data/generators/paperclip/USAGE +0 -5
  93. data/generators/paperclip/paperclip_generator.rb +0 -27
  94. data/generators/paperclip/templates/paperclip_migration.rb.erb +0 -19
  95. data/init.rb +0 -4
  96. data/lib/paperclip/callback_compatibility.rb +0 -61
  97. data/lib/paperclip/iostream.rb +0 -45
  98. data/lib/paperclip/upfile.rb +0 -62
  99. data/rails/init.rb +0 -2
  100. data/test/.gitignore +0 -1
  101. data/test/fixtures/question?mark.png +0 -0
  102. data/test/iostream_test.rb +0 -71
  103. data/test/upfile_test.rb +0 -53
@@ -5,9 +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 the paperclip rake task to a Rails 2.3 application
9
8
  And I add this snippet to the User model:
10
9
  """
10
+ attr_accessible :name, :attachment
11
11
  has_attached_file :attachment, :path => ":rails_root/public/system/:attachment/:style/:filename"
12
12
  """
13
13
 
@@ -10,11 +10,13 @@ end
10
10
  World(AttachmentHelpers)
11
11
 
12
12
  When /^I modify my attachment definition to:$/ do |definition|
13
- write_file "app/models/user.rb", <<-FILE
14
- class User < ActiveRecord::Base
13
+ content = in_current_dir { File.read("app/models/user.rb") }
14
+ content.gsub!(/has_attached_file.+end/m, <<-FILE)
15
15
  #{definition}
16
16
  end
17
17
  FILE
18
+
19
+ write_file "app/models/user.rb", content
18
20
  in_current_dir { FileUtils.rm_rf ".rbx" }
19
21
  end
20
22
 
@@ -51,6 +53,13 @@ Then /^the attachment should have the same content type as the fixture "([^"]*)"
51
53
  end
52
54
  end
53
55
 
56
+ Then /^the attachment should have the same file name as the fixture "([^"]*)"$/ do |filename|
57
+ in_current_dir do
58
+ attachment_file_name = `bundle exec #{runner_command} "puts User.last.attachment_file_name"`.strip
59
+ attachment_file_name.should == File.name(fixture_path(filename)).to_s
60
+ end
61
+ end
62
+
54
63
  Then /^the attachment should have the same file size as the fixture "([^"]*)"$/ do |filename|
55
64
  in_current_dir do
56
65
  attachment_file_size = `bundle exec #{runner_command} "puts User.last.attachment_file_size"`.strip
@@ -1,13 +1,15 @@
1
1
  Given /^I generate a new rails application$/ do
2
2
  steps %{
3
- When I run `bundle exec #{new_application_command} #{APP_NAME}`
3
+ When I run `bundle exec #{new_application_command} #{APP_NAME} --skip-bundle`
4
4
  And I cd to "#{APP_NAME}"
5
5
  And I turn off class caching
6
6
  And I write to "Gemfile" with:
7
7
  """
8
8
  source "http://rubygems.org"
9
9
  gem "rails", "#{framework_version}"
10
- gem "sqlite3"
10
+ gem "sqlite3", :platform => :ruby
11
+ gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
12
+ gem "jruby-openssl", :platform => :jruby
11
13
  gem "capybara"
12
14
  gem "gherkin"
13
15
  gem "aws-sdk"
@@ -31,33 +33,18 @@ Given /^I run a migration$/ do
31
33
  end
32
34
 
33
35
  Given /^I update my new user view to include the file upload field$/ do
34
- if framework_version?("3")
35
- steps %{
36
- Given I overwrite "app/views/users/new.html.erb" with:
37
- """
38
- <%= form_for @user, :html => { :multipart => true } do |f| %>
39
- <%= f.label :name %>
40
- <%= f.text_field :name %>
41
- <%= f.label :attachment %>
42
- <%= f.file_field :attachment %>
43
- <%= submit_tag "Submit" %>
44
- <% end %>
45
- """
46
- }
47
- else
48
- steps %{
49
- Given I overwrite "app/views/users/new.html.erb" with:
50
- """
51
- <% form_for @user, :html => { :multipart => true } do |f| %>
52
- <%= f.label :name %>
53
- <%= f.text_field :name %>
54
- <%= f.label :attachment %>
55
- <%= f.file_field :attachment %>
56
- <%= submit_tag "Submit" %>
57
- <% end %>
58
- """
59
- }
60
- end
36
+ steps %{
37
+ Given I overwrite "app/views/users/new.html.erb" with:
38
+ """
39
+ <%= form_for @user, :html => { :multipart => true } do |f| %>
40
+ <%= f.label :name %>
41
+ <%= f.text_field :name %>
42
+ <%= f.label :attachment %>
43
+ <%= f.file_field :attachment %>
44
+ <%= submit_tag "Submit" %>
45
+ <% end %>
46
+ """
47
+ }
61
48
  end
62
49
 
63
50
  Given /^I update my user view to include the attachment$/ do
@@ -89,7 +76,7 @@ Given /^I reload my application$/ do
89
76
  Rails::Application.reload!
90
77
  end
91
78
 
92
- When %r{I turn off class caching} do
79
+ When /^I turn off class caching$/ do
93
80
  in_current_dir do
94
81
  file = "config/environments/test.rb"
95
82
  config = IO.read(file)
@@ -99,30 +86,6 @@ When %r{I turn off class caching} do
99
86
  end
100
87
  end
101
88
 
102
- Given /^I update my application to use Bundler$/ do
103
- if framework_version?("2")
104
- boot_config_template = File.read('features/support/fixtures/boot_config.txt')
105
- preinitializer_template = File.read('features/support/fixtures/preinitializer.txt')
106
- gemfile_template = File.read('features/support/fixtures/gemfile.txt')
107
- in_current_dir do
108
- content = File.read("config/boot.rb").sub(/Rails\.boot!/, boot_config_template)
109
- File.open("config/boot.rb", "w") { |file| file.write(content) }
110
- File.open("config/preinitializer.rb", "w") { |file| file.write(preinitializer_template) }
111
- File.open("Gemfile", "w") { |file| file.write(gemfile_template.sub(/RAILS_VERSION/, framework_version)) }
112
- end
113
- end
114
- end
115
-
116
- Given /^I add the paperclip rake task to a Rails 2.3 application$/ do
117
- if framework_version?("2.3")
118
- require 'fileutils'
119
- source = File.expand_path('lib/tasks/paperclip.rake')
120
- destination = in_current_dir { File.expand_path("lib/tasks") }
121
- FileUtils.cp source, destination
122
- append_to "Rakefile", "require 'paperclip'"
123
- end
124
- end
125
-
126
89
  Then /^the file at "([^"]*)" should be the same as "([^"]*)"$/ do |web_file, path|
127
90
  expected = IO.read(path)
128
91
  actual = if web_file.match %r{^https?://}
@@ -155,28 +118,3 @@ end
155
118
  When /^I comment out the gem "([^"]*)" from the Gemfile$/ do |gemname|
156
119
  comment_out_gem_in_gemfile gemname
157
120
  end
158
-
159
- module FileHelpers
160
- def append_to(path, contents)
161
- in_current_dir do
162
- File.open(path, "a") do |file|
163
- file.puts
164
- file.puts contents
165
- end
166
- end
167
- end
168
-
169
- def append_to_gemfile(contents)
170
- append_to('Gemfile', contents)
171
- end
172
-
173
- def comment_out_gem_in_gemfile(gemname)
174
- in_current_dir do
175
- gemfile = File.read("Gemfile")
176
- gemfile.sub!(/^(\s*)(gem\s*['"]#{gemname})/, "\\1# \\2")
177
- File.open("Gemfile", 'w'){ |file| file.write(gemfile) }
178
- end
179
- end
180
- end
181
-
182
- World(FileHelpers)
@@ -1,6 +1,9 @@
1
1
  require 'aruba/cucumber'
2
2
  require 'capybara/cucumber'
3
3
  require 'test/unit/assertions'
4
+
5
+ $CUCUMBER=1
6
+
4
7
  World(Test::Unit::Assertions)
5
8
 
6
9
  Before do
@@ -1,3 +1,10 @@
1
1
  require 'fake_web'
2
2
 
3
3
  FakeWeb.allow_net_connect = false
4
+
5
+ module FakeWeb
6
+ class StubSocket
7
+ def read_timeout=(ignored)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ module FileHelpers
2
+ def append_to(path, contents)
3
+ in_current_dir do
4
+ File.open(path, "a") do |file|
5
+ file.puts
6
+ file.puts contents
7
+ end
8
+ end
9
+ end
10
+
11
+ def append_to_gemfile(contents)
12
+ append_to('Gemfile', contents)
13
+ end
14
+
15
+ def comment_out_gem_in_gemfile(gemname)
16
+ in_current_dir do
17
+ gemfile = File.read("Gemfile")
18
+ gemfile.sub!(/^(\s*)(gem\s*['"]#{gemname})/, "\\1# \\2")
19
+ File.open("Gemfile", 'w'){ |file| file.write(gemfile) }
20
+ end
21
+ end
22
+ end
23
+
24
+ World(FileHelpers)
@@ -32,15 +32,15 @@ module RailsCommandHelpers
32
32
  end
33
33
 
34
34
  def new_application_command
35
- framework_version?("3") ? "rails new" : "rails"
35
+ "rails new"
36
36
  end
37
37
 
38
38
  def generator_command
39
- framework_version?("3") ? "script/rails generate" : "script/generate"
39
+ "script/rails generate"
40
40
  end
41
41
 
42
42
  def runner_command
43
- framework_version?("3") ? "script/rails runner" : "script/runner"
43
+ "script/rails runner"
44
44
  end
45
45
  end
46
46
  World(RailsCommandHelpers)
@@ -3,7 +3,9 @@
3
3
  source "http://rubygems.org"
4
4
 
5
5
  gem "jruby-openssl", :platform=>:jruby
6
- gem "rails", "~> 3.1.0"
6
+ gem "activerecord-jdbcsqlite3-adapter", :platform=>:jruby
7
+ gem "sqlite3", :platform=>:ruby
8
+ gem "rails", "~> 3.0.12"
7
9
  gem "paperclip", :path=>"../"
8
10
 
9
11
  gemspec :path=>"../"
@@ -3,7 +3,9 @@
3
3
  source "http://rubygems.org"
4
4
 
5
5
  gem "jruby-openssl", :platform=>:jruby
6
- gem "rails", "~> 2.3.14"
6
+ gem "activerecord-jdbcsqlite3-adapter", :platform=>:jruby
7
+ gem "sqlite3", :platform=>:ruby
8
+ gem "rails", "~> 3.1.4"
7
9
  gem "paperclip", :path=>"../"
8
10
 
9
11
  gemspec :path=>"../"
@@ -3,7 +3,9 @@
3
3
  source "http://rubygems.org"
4
4
 
5
5
  gem "jruby-openssl", :platform=>:jruby
6
- gem "rails", "~> 3.0.10"
6
+ gem "activerecord-jdbcsqlite3-adapter", :platform=>:jruby
7
+ gem "sqlite3", :platform=>:ruby
8
+ gem "rails", "~> 3.2.2"
7
9
  gem "paperclip", :path=>"../"
8
10
 
9
11
  gemspec :path=>"../"
@@ -0,0 +1,21 @@
1
+ namespace :images do
2
+ desc "Regenerate images"
3
+ task :regenerate => :environment do
4
+ require 'open-uri'
5
+ OpportunityPhoto.all.each do |photo|
6
+ begin
7
+ old_name = photo.image_file_name
8
+ new_image = open(photo.image.url(:original, escape: false))
9
+ class << new_image
10
+ def original_filename; @original_filename; end
11
+ def original_filename=(name); @original_filename = name; end
12
+ end
13
+ new_image.original_filename = old_name
14
+ photo.image = new_image
15
+ photo.save
16
+ rescue => e
17
+ puts "ERROR: #{e.message} while processing #{photo.id}"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1 @@
1
+ require 'paperclip' # assholes
@@ -19,7 +19,7 @@ class PaperclipGenerator < ActiveRecord::Generators::Base
19
19
  protected
20
20
 
21
21
  def migration_name
22
- "add_attachment_#{attachment_names.join("_")}_to_#{name.underscore}"
22
+ "add_attachment_#{attachment_names.join("_")}_to_#{name.underscore.pluralize}"
23
23
  end
24
24
 
25
25
  def migration_file_name
@@ -29,5 +29,4 @@ class PaperclipGenerator < ActiveRecord::Generators::Base
29
29
  def migration_class_name
30
30
  migration_name.camelize
31
31
  end
32
-
33
32
  end
@@ -29,206 +29,61 @@ require 'erb'
29
29
  require 'digest'
30
30
  require 'tempfile'
31
31
  require 'paperclip/version'
32
- require 'paperclip/upfile'
33
- require 'paperclip/iostream'
34
32
  require 'paperclip/geometry'
35
33
  require 'paperclip/processor'
34
+ require 'paperclip/tempfile'
36
35
  require 'paperclip/thumbnail'
37
36
  require 'paperclip/interpolations'
38
37
  require 'paperclip/style'
39
38
  require 'paperclip/attachment'
39
+ require 'paperclip/attachment_options'
40
40
  require 'paperclip/storage'
41
- require 'paperclip/callback_compatibility'
41
+ require 'paperclip/callbacks'
42
+ require 'paperclip/glue'
43
+ require 'paperclip/errors'
42
44
  require 'paperclip/missing_attachment_styles'
43
- require 'paperclip/railtie'
45
+ require 'paperclip/validators'
46
+ require 'paperclip/instance_methods'
47
+ require 'paperclip/logger'
48
+ require 'paperclip/helpers'
49
+ require 'mime/types'
44
50
  require 'logger'
45
51
  require 'cocaine'
46
52
 
53
+ require 'paperclip/railtie' if defined?(Rails)
54
+
47
55
  # The base module that gets included in ActiveRecord::Base. See the
48
56
  # documentation for Paperclip::ClassMethods for more useful information.
49
57
  module Paperclip
50
-
51
- class << self
52
- # Provides configurability to Paperclip. There are a number of options available, such as:
53
- # * whiny: Will raise an error if Paperclip cannot process thumbnails of
54
- # an uploaded image. Defaults to true.
55
- # * log: Logs progress to the Rails log. Uses ActiveRecord's logger, so honors
56
- # log levels, etc. Defaults to true.
57
- # * command_path: Defines the path at which to find the command line
58
- # programs if they are not visible to Rails the system's search path. Defaults to
59
- # nil, which uses the first executable found in the user's search path.
60
- # * image_magick_path: Deprecated alias of command_path.
61
- def options
62
- @options ||= {
63
- :whiny => true,
64
- :image_magick_path => nil,
65
- :command_path => nil,
66
- :log => true,
67
- :log_command => true,
68
- :swallow_stderr => true
69
- }
70
- end
71
-
72
- def configure
73
- yield(self) if block_given?
74
- end
75
-
76
- def interpolates key, &block
77
- Paperclip::Interpolations[key] = block
78
- end
79
-
80
- # The run method takes the name of a binary to run, the arguments to that binary
81
- # and some options:
82
- #
83
- # :command_path -> A $PATH-like variable that defines where to look for the binary
84
- # on the filesystem. Colon-separated, just like $PATH.
85
- #
86
- # :expected_outcodes -> An array of integers that defines the expected exit codes
87
- # of the binary. Defaults to [0].
88
- #
89
- # :log_command -> Log the command being run when set to true (defaults to false).
90
- # This will only log if logging in general is set to true as well.
91
- #
92
- # :swallow_stderr -> Set to true if you don't care what happens on STDERR.
93
- #
94
- def run(cmd, arguments = "", local_options = {})
95
- if options[:image_magick_path]
96
- Paperclip.log("[DEPRECATION] :image_magick_path is deprecated and will be removed. Use :command_path instead")
97
- end
98
- command_path = options[:command_path] || options[:image_magick_path]
99
- Cocaine::CommandLine.path = ( Cocaine::CommandLine.path ? [Cocaine::CommandLine.path, command_path ].flatten : command_path )
100
- local_options = local_options.merge(:logger => logger) if logging? && (options[:log_command] || local_options[:log_command])
101
- Cocaine::CommandLine.new(cmd, arguments, local_options).run
102
- end
103
-
104
- def processor(name) #:nodoc:
105
- @known_processors ||= {}
106
- if @known_processors[name.to_s]
107
- @known_processors[name.to_s]
108
- else
109
- name = name.to_s.camelize
110
- load_processor(name) unless Paperclip.const_defined?(name)
111
- processor = Paperclip.const_get(name)
112
- @known_processors[name.to_s] = processor
113
- end
114
- end
115
-
116
- def load_processor(name)
117
- if defined?(Rails.root) && Rails.root
118
- require File.expand_path(Rails.root.join("lib", "paperclip_processors", "#{name.underscore}.rb"))
119
- end
120
- end
121
-
122
- def clear_processors!
123
- @known_processors.try(:clear)
124
- end
125
-
126
- # You can add your own processor via the Paperclip configuration. Normally
127
- # Paperclip will load all processors from the
128
- # Rails.root/lib/paperclip_processors directory, but here you can add any
129
- # existing class using this mechanism.
130
- #
131
- # Paperclip.configure do |c|
132
- # c.register_processor :watermarker, WatermarkingProcessor.new
133
- # end
134
- def register_processor(name, processor)
135
- @known_processors ||= {}
136
- @known_processors[name.to_s] = processor
137
- end
138
-
139
- # Find all instances of the given Active Record model +klass+ with attachment +name+.
140
- # This method is used by the refresh rake tasks.
141
- def each_instance_with_attachment(klass, name)
142
- unscope_method = class_for(klass).respond_to?(:unscoped) ? :unscoped : :with_exclusive_scope
143
- class_for(klass).send(unscope_method) do
144
- class_for(klass).find(:all, :order => 'id').each do |instance|
145
- yield(instance) if instance.send(:"#{name}?")
146
- end
147
- end
148
- end
149
-
150
- # Log a paperclip-specific line. This will logs to STDOUT
151
- # by default. Set Paperclip.options[:log] to false to turn off.
152
- def log message
153
- logger.info("[paperclip] #{message}") if logging?
154
- end
155
-
156
- def logger #:nodoc:
157
- @logger ||= options[:logger] || Logger.new(STDOUT)
158
- end
159
-
160
- def logger=(logger)
161
- @logger = logger
162
- end
163
-
164
- def logging? #:nodoc:
165
- options[:log]
166
- end
167
-
168
- def class_for(class_name)
169
- # Ruby 1.9 introduces an inherit argument for Module#const_get and
170
- # #const_defined? and changes their default behavior.
171
- # https://github.com/rails/rails/blob/v3.0.9/activesupport/lib/active_support/inflector/methods.rb#L89
172
- if Module.method(:const_get).arity == 1
173
- class_name.split('::').inject(Object) do |klass, partial_class_name|
174
- klass.const_defined?(partial_class_name) ? klass.const_get(partial_class_name) : klass.const_missing(partial_class_name)
175
- end
176
- else
177
- class_name.split('::').inject(Object) do |klass, partial_class_name|
178
- klass.const_defined?(partial_class_name) ? klass.const_get(partial_class_name, false) : klass.const_missing(partial_class_name)
179
- end
180
- end
181
- rescue ArgumentError => e
182
- # Sadly, we need to capture ArguementError here because Rails 2.3.x
183
- # Active Support dependency's management will try to the constant inherited
184
- # from Object, and fail misably with "Object is not missing constant X" error
185
- # https://github.com/rails/rails/blob/v2.3.12/activesupport/lib/active_support/dependencies.rb#L124
186
- if e.message =~ /is not missing constant/
187
- raise NameError, "uninitialized constant #{class_name}"
188
- else
189
- raise e
190
- end
191
- end
192
-
193
- def check_for_url_clash(name,url,klass)
194
- @names_url ||= {}
195
- default_url = url || Attachment.default_options[:url]
196
- if @names_url[name] && @names_url[name][:url] == default_url && @names_url[name][:class] != klass && @names_url[name][:url] !~ /:class/
197
- log("Duplicate URL for #{name} with #{default_url}. This will clash with attachment defined in #{@names_url[name][:class]} class")
198
- end
199
- @names_url[name] = {:url => default_url, :class => klass}
200
- end
201
-
202
- def reset_duplicate_clash_check!
203
- @names_url = nil
204
- end
205
- end
206
-
207
- class PaperclipError < StandardError #:nodoc:
58
+ extend Helpers
59
+ extend Logger
60
+ extend ProcessorHelpers
61
+
62
+ # Provides configurability to Paperclip. The options available are:
63
+ # * whiny: Will raise an error if Paperclip cannot process thumbnails of
64
+ # an uploaded image. Defaults to true.
65
+ # * log: Logs progress to the Rails log. Uses ActiveRecord's logger, so honors
66
+ # log levels, etc. Defaults to true.
67
+ # * command_path: Defines the path at which to find the command line
68
+ # programs if they are not visible to Rails the system's search path. Defaults to
69
+ # nil, which uses the first executable found in the user's search path.
70
+ def self.options
71
+ @options ||= {
72
+ :whiny => true,
73
+ :image_magick_path => nil,
74
+ :command_path => nil,
75
+ :log => true,
76
+ :log_command => true,
77
+ :swallow_stderr => true
78
+ }
208
79
  end
209
80
 
210
- class StorageMethodNotFound < PaperclipError
81
+ def self.io_adapters=(new_registry)
82
+ @io_adapters = new_registry
211
83
  end
212
84
 
213
- class CommandNotFoundError < PaperclipError
214
- end
215
-
216
- class NotIdentifiedByImageMagickError < PaperclipError #:nodoc:
217
- end
218
-
219
- class InfiniteInterpolationError < PaperclipError #:nodoc:
220
- end
221
-
222
- module Glue
223
- def self.included base #:nodoc:
224
- base.extend ClassMethods
225
- base.class_attribute :attachment_definitions if base.respond_to?(:class_attribute)
226
- if base.respond_to?(:set_callback)
227
- base.send :include, Paperclip::CallbackCompatability::Rails3
228
- else
229
- base.send :include, Paperclip::CallbackCompatability::Rails21
230
- end
231
- end
85
+ def self.io_adapters
86
+ @io_adapters ||= Paperclip::AdapterRegistry.new
232
87
  end
233
88
 
234
89
  module ClassMethods
@@ -271,8 +126,7 @@ module Paperclip
271
126
  # Defaults to +false+.#
272
127
  # * +whiny+: Will raise an error if Paperclip cannot post_process an uploaded file due
273
128
  # to a command line error. This will override the global setting for this attachment.
274
- # Defaults to true. This option used to be called :whiny_thumbanils, but this is
275
- # deprecated.
129
+ # Defaults to true.
276
130
  # * +convert_options+: When creating thumbnails, use this free-form options
277
131
  # array to pass in various convert command options. Typical options are "-strip" to
278
132
  # remove all Exif data from the image (save space for thumbnails and avatars) or
@@ -295,11 +149,11 @@ module Paperclip
295
149
  # shell quoting for safety. If your options require a space, please pre-split them
296
150
  # and pass an array to :convert_options instead.
297
151
  # * +storage+: Chooses the storage backend where the files will be stored. The current
298
- # choices are :filesystem and :s3. The default is :filesystem. Make sure you read the
299
- # documentation for Paperclip::Storage::Filesystem and Paperclip::Storage::S3
152
+ # choices are :filesystem, :fog and :s3. The default is :filesystem. Make sure you read the
153
+ # documentation for Paperclip::Storage::Filesystem, Paperclip::Storage::Fog and Paperclip::Storage::S3
300
154
  # for backend-specific options.
301
155
  #
302
- # It's also possible for you to dynamicly define your interpolation string for :url,
156
+ # It's also possible for you to dynamically define your interpolation string for :url,
303
157
  # :default_url, and :path in your model by passing a method name as a symbol as a argument
304
158
  # for your has_attached_file definition:
305
159
  #
@@ -312,20 +166,16 @@ module Paperclip
312
166
  # "/assets/avatars/default_#{gender}.png"
313
167
  # end
314
168
  # end
315
- def has_attached_file name, options = {}
169
+ def has_attached_file(name, options = {})
316
170
  include InstanceMethods
317
171
 
318
172
  if attachment_definitions.nil?
319
- if respond_to?(:class_attribute)
320
- self.attachment_definitions = {}
321
- else
322
- write_inheritable_attribute(:attachment_definitions, {})
323
- end
173
+ self.attachment_definitions = {}
324
174
  else
325
175
  self.attachment_definitions = self.attachment_definitions.dup
326
176
  end
327
177
 
328
- attachment_definitions[name] = {:validations => []}.merge(options)
178
+ attachment_definitions[name] = Paperclip::AttachmentOptions.new(options)
329
179
  Paperclip.classes_with_attachments << self.name
330
180
  Paperclip.check_for_url_clash(name,attachment_definitions[name][:url],self.name)
331
181
 
@@ -354,134 +204,19 @@ module Paperclip
354
204
  end
355
205
  end
356
206
 
357
- # Places ActiveRecord-style validations on the size of the file assigned. The
358
- # possible options are:
359
- # * +in+: a Range of bytes (i.e. +1..1.megabyte+),
360
- # * +less_than+: equivalent to :in => 0..options[:less_than]
361
- # * +greater_than+: equivalent to :in => options[:greater_than]..Infinity
362
- # * +message+: error message to display, use :min and :max as replacements
363
- # * +if+: A lambda or name of a method on the instance. Validation will only
364
- # be run is this lambda or method returns true.
365
- # * +unless+: Same as +if+ but validates if lambda or method returns false.
366
- def validates_attachment_size name, options = {}
367
- min = options[:greater_than] || (options[:in] && options[:in].first) || 0
368
- max = options[:less_than] || (options[:in] && options[:in].last) || (1.0/0)
369
- range = (min..max)
370
- message = options[:message] || "file size must be between :min and :max bytes"
371
- message = message.call if message.respond_to?(:call)
372
- message = message.gsub(/:min/, min.to_s).gsub(/:max/, max.to_s)
373
-
374
- validates_inclusion_of :"#{name}_file_size",
375
- :in => range,
376
- :message => message,
377
- :if => options[:if],
378
- :unless => options[:unless],
379
- :allow_nil => true
380
- end
381
-
382
- # Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true.
383
- def validates_attachment_thumbnails name, options = {}
384
- warn('[DEPRECATION] validates_attachment_thumbnail is deprecated. ' +
385
- 'This validation is on by default and will be removed from future versions. ' +
386
- 'If you wish to turn it off, supply :whiny => false in your definition.')
387
- attachment_definitions[name][:whiny_thumbnails] = true
388
- end
389
-
390
- # Places ActiveRecord-style validations on the presence of a file.
391
- # Options:
392
- # * +if+: A lambda or name of a method on the instance. Validation will only
393
- # be run if this lambda or method returns true.
394
- # * +unless+: Same as +if+ but validates if lambda or method returns false.
395
- def validates_attachment_presence name, options = {}
396
- message = options[:message] || :empty
397
- validates_each :"#{name}_file_name" do |record, attr, value|
398
- if_clause_passed = options[:if].nil? || (options[:if].respond_to?(:call) ? options[:if].call(record) != false : record.send(options[:if]))
399
- unless_clause_passed = options[:unless].nil? || (options[:unless].respond_to?(:call) ? !!options[:unless].call(record) == false : !record.send(options[:unless]))
400
- if if_clause_passed && unless_clause_passed && value.blank?
401
- record.errors.add(name, message)
402
- record.errors.add("#{name}_file_name", message)
403
- end
404
- end
405
- end
406
-
407
- # Places ActiveRecord-style validations on the content type of the file
408
- # assigned. The possible options are:
409
- # * +content_type+: Allowed content types. Can be a single content type
410
- # or an array. Each type can be a String or a Regexp. It should be
411
- # noted that Internet Explorer upload files with content_types that you
412
- # may not expect. For example, JPEG images are given image/pjpeg and
413
- # PNGs are image/x-png, so keep that in mind when determining how you
414
- # match. Allows all by default.
415
- # * +message+: The message to display when the uploaded file has an invalid
416
- # content type.
417
- # * +if+: A lambda or name of a method on the instance. Validation will only
418
- # be run is this lambda or method returns true.
419
- # * +unless+: Same as +if+ but validates if lambda or method returns false.
420
- # NOTE: If you do not specify an [attachment]_content_type field on your
421
- # model, content_type validation will work _ONLY upon assignment_ and
422
- # re-validation after the instance has been reloaded will always succeed.
423
- # You'll still need to have a virtual attribute (created by +attr_accessor+)
424
- # name +[attachment]_content_type+ to be able to use this validator.
425
- def validates_attachment_content_type name, options = {}
426
- validation_options = options.dup
427
- allowed_types = [validation_options[:content_type]].flatten
428
- validates_each(:"#{name}_content_type", validation_options) do |record, attr, value|
429
- if !allowed_types.any?{|t| t === value } && !(value.nil? || value.blank?)
430
- if record.errors.method(:add).arity == -2
431
- message = options[:message] || "is not one of #{allowed_types.join(", ")}"
432
- message = message.call if message.respond_to?(:call)
433
- record.errors.add(:"#{name}_content_type", message)
434
- else
435
- record.errors.add(:"#{name}_content_type", :inclusion, :default => options[:message], :value => value)
436
- end
437
- end
438
- end
439
- end
440
-
441
207
  # Returns the attachment definitions defined by each call to
442
208
  # has_attached_file.
443
209
  def attachment_definitions
444
- if respond_to?(:class_attribute)
445
- self.attachment_definitions
446
- else
447
- read_inheritable_attribute(:attachment_definitions)
448
- end
210
+ self.attachment_definitions
449
211
  end
450
212
  end
451
-
452
- module InstanceMethods #:nodoc:
453
- def attachment_for name
454
- @_paperclip_attachments ||= {}
455
- @_paperclip_attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name])
456
- end
457
-
458
- def each_attachment
459
- self.class.attachment_definitions.each do |name, definition|
460
- yield(name, attachment_for(name))
461
- end
462
- end
463
-
464
- def save_attached_files
465
- Paperclip.log("Saving attachments.")
466
- each_attachment do |name, attachment|
467
- attachment.send(:save)
468
- end
469
- end
470
-
471
- def destroy_attached_files
472
- Paperclip.log("Deleting attachments.")
473
- each_attachment do |name, attachment|
474
- attachment.send(:flush_deletes)
475
- end
476
- end
477
-
478
- def prepare_for_destroy
479
- Paperclip.log("Scheduling attachments for deletion.")
480
- each_attachment do |name, attachment|
481
- attachment.send(:queue_existing_for_delete)
482
- end
483
- end
484
-
485
- end
486
-
487
213
  end
214
+
215
+ # This stuff needs to be run after Paperclip is defined.
216
+ require 'paperclip/io_adapters/registry'
217
+ require 'paperclip/io_adapters/identity_adapter'
218
+ require 'paperclip/io_adapters/file_adapter'
219
+ require 'paperclip/io_adapters/stringio_adapter'
220
+ require 'paperclip/io_adapters/nil_adapter'
221
+ require 'paperclip/io_adapters/attachment_adapter'
222
+ require 'paperclip/io_adapters/uploaded_file_adapter'