paperclip-cloudfiles 2.3.1.1.6 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -174,6 +174,11 @@ NOTE: Post processing will not even *start* if the attachment is not valid
174
174
  according to the validations. Your callbacks and processors will *only* be
175
175
  called with valid attachments.
176
176
 
177
+ ==Testing
178
+
179
+ Paperclip provides rspec-compatible matchers for testing attachments. See the
180
+ documentation on Paperclip::Shoulda::Matchers for more information.
181
+
177
182
  ==Contributing
178
183
 
179
184
  If you'd like to contribute a feature or bugfix: Thanks! To make sure your
data/Rakefile CHANGED
@@ -8,6 +8,11 @@ require 'paperclip'
8
8
  desc 'Default: run unit tests.'
9
9
  task :default => [:clean, :test]
10
10
 
11
+ desc 'Test the paperclip plugin under all supported Rails versions.'
12
+ task :all do |t|
13
+ exec('rake RAILS_VERSION=2.1 && rake RAILS_VERSION=2.3 && rake RAILS_VERSION=3.0')
14
+ end
15
+
11
16
  desc 'Test the paperclip plugin.'
12
17
  Rake::TestTask.new(:test) do |t|
13
18
  t.libs << 'lib' << 'profile'
@@ -40,49 +45,15 @@ task :clean do |t|
40
45
  FileUtils.rm_rf "doc"
41
46
  FileUtils.rm_rf "tmp"
42
47
  FileUtils.rm_rf "pkg"
48
+ FileUtils.rm_rf "public"
43
49
  FileUtils.rm "test/debug.log" rescue nil
44
50
  FileUtils.rm "test/paperclip.db" rescue nil
45
51
  Dir.glob("paperclip-*.gem").each{|f| FileUtils.rm f }
46
52
  end
47
53
 
48
- include_file_globs = ["README*",
49
- "LICENSE",
50
- "Rakefile",
51
- "init.rb",
52
- "{generators,lib,tasks,test,shoulda_macros}/**/*"]
53
- exclude_file_globs = ["test/s3.yml",
54
- "test/debug.log",
55
- "test/paperclip.db",
56
- "test/doc",
57
- "test/doc/*",
58
- "test/pkg",
59
- "test/pkg/*",
60
- "test/tmp",
61
- "test/tmp/*"]
62
- spec = Gem::Specification.new do |s|
63
- s.name = "paperclip-cloudfiles"
64
- s.version = Paperclip::VERSION
65
- s.authors = "Jon Yurek", "H. Wade Minter"
66
- s.email = "jyurek@thoughtbot.com", "minter@lunenburg.org"
67
- s.homepage = "http://github.com/minter/paperclip"
68
- s.platform = Gem::Platform::RUBY
69
- s.description = "A fork of the Thoughtbot Paperclip gem/plugin, adding support for Rackspace Cloud Files. This fork is maintained by H. Wade Minter <minter@lunenburg.org>"
70
- s.summary = "File attachments as attributes for ActiveRecord with Rackspace Cloud Files support"
71
- s.files = FileList[include_file_globs].to_a - FileList[exclude_file_globs].to_a
72
- s.require_path = "lib"
73
- s.test_files = FileList["test/**/test_*.rb"].to_a
74
- s.rubyforge_project = "paperclip"
75
- s.has_rdoc = true
76
- s.extra_rdoc_files = FileList["README*"].to_a
77
- s.rdoc_options << '--line-numbers' << '--inline-source'
78
- s.requirements << "ImageMagick"
79
- s.add_development_dependency 'shoulda'
80
- s.add_development_dependency 'jferris-mocha', '>= 0.9.5.0.1241126838'
81
- s.add_development_dependency 'aws-s3'
82
- s.add_development_dependency 'cloudfiles', '>= 1.4.4'
83
- s.add_development_dependency 'sqlite3-ruby'
84
- s.add_development_dependency 'activerecord'
85
- s.add_development_dependency 'activesupport'
54
+ desc 'Build the gemspec.'
55
+ task :gemspec do |t|
56
+ exec 'gem build paperclip-cloudfiles.gemspec'
86
57
  end
87
58
 
88
59
  desc "Print a list of the files to be put into the gem"
data/lib/paperclip.rb CHANGED
@@ -36,8 +36,9 @@ require 'paperclip/storage'
36
36
  require 'paperclip/interpolations'
37
37
  require 'paperclip/style'
38
38
  require 'paperclip/attachment'
39
- if defined? RAILS_ROOT
40
- Dir.glob(File.join(File.expand_path(RAILS_ROOT), "lib", "paperclip_processors", "*.rb")).each do |processor|
39
+ require 'paperclip/callback_compatability'
40
+ if defined?(Rails.root) && Rails.root
41
+ Dir.glob(File.join(File.expand_path(Rails.root), "lib", "paperclip_processors", "*.rb")).each do |processor|
41
42
  require processor
42
43
  end
43
44
  end
@@ -46,7 +47,7 @@ end
46
47
  # documentation for Paperclip::ClassMethods for more useful information.
47
48
  module Paperclip
48
49
 
49
- VERSION = "2.3.1.1.6"
50
+ VERSION = "2.3.2"
50
51
 
51
52
  class << self
52
53
  # Provides configurability to Paperclip. There are a number of options available, such as:
@@ -64,7 +65,7 @@ module Paperclip
64
65
  :image_magick_path => nil,
65
66
  :command_path => nil,
66
67
  :log => true,
67
- :log_command => false,
68
+ :log_command => true,
68
69
  :swallow_stderr => true
69
70
  }
70
71
  end
@@ -81,7 +82,7 @@ module Paperclip
81
82
  Paperclip::Interpolations[key] = block
82
83
  end
83
84
 
84
- # The run method takes a command to execute and a string of parameters
85
+ # The run method takes a command to execute and an array of parameters
85
86
  # that get passed to it. The command is prefixed with the :command_path
86
87
  # option from Paperclip.options. If you have many commands to run and
87
88
  # they are in different paths, the suggested course of action is to
@@ -90,29 +91,49 @@ module Paperclip
90
91
  # If the command returns with a result code that is not one of the
91
92
  # expected_outcodes, a PaperclipCommandLineError will be raised. Generally
92
93
  # a code of 0 is expected, but a list of codes may be passed if necessary.
94
+ # These codes should be passed as a hash as the last argument, like so:
95
+ #
96
+ # Paperclip.run("echo", "something", :expected_outcodes => [0,1,2,3])
93
97
  #
94
98
  # This method can log the command being run when
95
99
  # Paperclip.options[:log_command] is set to true (defaults to false). This
96
100
  # will only log if logging in general is set to true as well.
97
- def run cmd, params = "", expected_outcodes = 0
98
- command = %Q[#{path_for_command(cmd)} #{params}].gsub(/\s+/, " ")
101
+ def run cmd, *params
102
+ options = params.last.is_a?(Hash) ? params.pop : {}
103
+ expected_outcodes = options[:expected_outcodes] || [0]
104
+ params = quote_command_options(*params).join(" ")
105
+
106
+ command = %Q[#{path_for_command(cmd)} #{params}]
99
107
  command = "#{command} 2>#{bit_bucket}" if Paperclip.options[:swallow_stderr]
100
108
  Paperclip.log(command) if Paperclip.options[:log_command]
109
+
101
110
  output = `#{command}`
102
- unless [expected_outcodes].flatten.include?($?.exitstatus)
103
- raise PaperclipCommandLineError, "Error while running #{cmd}"
111
+ unless expected_outcodes.include?($?.exitstatus)
112
+ raise PaperclipCommandLineError,
113
+ "Error while running #{cmd}. Expected return code to be #{expected_outcodes.join(", ")} but was #{$?.exitstatus}",
114
+ output
104
115
  end
105
116
  output
106
117
  end
107
118
 
119
+ def quote_command_options(*options)
120
+ options.map do |option|
121
+ option.split("'").map{|m| "'#{m}'" }.join("\\'")
122
+ end
123
+ end
124
+
108
125
  def bit_bucket #:nodoc:
109
126
  File.exists?("/dev/null") ? "/dev/null" : "NUL"
110
127
  end
111
128
 
112
129
  def included base #:nodoc:
113
130
  base.extend ClassMethods
114
- unless base.respond_to?(:define_callbacks)
115
- base.send(:include, Paperclip::CallbackCompatability)
131
+ if base.respond_to?("set_callback")
132
+ base.send :include, Paperclip::CallbackCompatability::Rails3
133
+ elsif !base.respond_to?("define_callbacks")
134
+ base.send :include, Paperclip::CallbackCompatability::Rails20
135
+ else
136
+ base.send :include, Paperclip::CallbackCompatability::Rails21
116
137
  end
117
138
  end
118
139
 
@@ -144,6 +165,11 @@ module Paperclip
144
165
  end
145
166
 
146
167
  class PaperclipCommandLineError < StandardError #:nodoc:
168
+ attr_accessor :output
169
+ def initialize(msg = nil, output = nil)
170
+ super(msg)
171
+ @output = output
172
+ end
147
173
  end
148
174
 
149
175
  class NotIdentifiedByImageMagickError < PaperclipError #:nodoc:
@@ -192,7 +218,7 @@ module Paperclip
192
218
  # Defaults to true. This option used to be called :whiny_thumbanils, but this is
193
219
  # deprecated.
194
220
  # * +convert_options+: When creating thumbnails, use this free-form options
195
- # field to pass in various convert command options. Typical options are "-strip" to
221
+ # array to pass in various convert command options. Typical options are "-strip" to
196
222
  # remove all Exif data from the image (save space for thumbnails and avatars) or
197
223
  # "-depth 8" to specify the bit depth of the resulting conversion. See ImageMagick
198
224
  # convert documentation for more options: (http://www.imagemagick.org/script/convert.php)
@@ -209,6 +235,9 @@ module Paperclip
209
235
  # NOTE: While not deprecated yet, it is not recommended to specify options this way.
210
236
  # It is recommended that :convert_options option be included in the hash passed to each
211
237
  # :styles for compatability with future versions.
238
+ # NOTE: Strings supplied to :convert_options are split on space in order to undergo
239
+ # shell quoting for safety. If your options require a space, please pre-split them
240
+ # and pass an array to :convert_options instead.
212
241
  # * +storage+: Chooses the storage backend where the files will be stored. The current
213
242
  # choices are :filesystem and :s3. The default is :filesystem. Make sure you read the
214
243
  # documentation for Paperclip::Storage::Filesystem and Paperclip::Storage::S3
@@ -222,9 +251,8 @@ module Paperclip
222
251
  after_save :save_attached_files
223
252
  before_destroy :destroy_attached_files
224
253
 
225
- define_callbacks :before_post_process, :after_post_process
226
- define_callbacks :"before_#{name}_post_process", :"after_#{name}_post_process"
227
-
254
+ define_paperclip_callbacks :post_process, :"#{name}_post_process"
255
+
228
256
  define_method name do |*args|
229
257
  a = attachment_for(name)
230
258
  (args.length > 0) ? a.to_s(args.first) : a
@@ -308,7 +336,12 @@ module Paperclip
308
336
  types = [options.delete(:content_type)].flatten
309
337
  validates_each(:"#{name}_content_type", options) do |record, attr, value|
310
338
  unless types.any?{|t| t === value }
311
- record.errors.add(:"#{name}_content_type", :inclusion, :default => options[:message], :value => value)
339
+ if record.errors.method(:add).arity == -2
340
+ message = options[:message] || "is not one of #{types.join(", ")}"
341
+ record.errors.add(:"#{name}_content_type", message)
342
+ else
343
+ record.errors.add(:"#{name}_content_type", :inclusion, :default => options[:message], :value => value)
344
+ end
312
345
  end
313
346
  end
314
347
  end
@@ -333,14 +366,14 @@ module Paperclip
333
366
  end
334
367
 
335
368
  def save_attached_files
336
- logger.info("[paperclip] Saving attachments.")
369
+ Paperclip.log("Saving attachments.")
337
370
  each_attachment do |name, attachment|
338
371
  attachment.send(:save)
339
372
  end
340
373
  end
341
374
 
342
375
  def destroy_attached_files
343
- logger.info("[paperclip] Deleting attachments.")
376
+ Paperclip.log("Deleting attachments.")
344
377
  each_attachment do |name, attachment|
345
378
  attachment.send(:queue_existing_for_delete)
346
379
  attachment.send(:flush_deletes)
@@ -92,7 +92,7 @@ module Paperclip
92
92
  return nil if uploaded_file.nil?
93
93
 
94
94
  @queued_for_write[:original] = uploaded_file.to_tempfile
95
- instance_write(:file_name, uploaded_file.original_filename.strip.gsub(/[^A-Za-z\d\.\-_]+/, '_'))
95
+ instance_write(:file_name, uploaded_file.original_filename.strip)
96
96
  instance_write(:content_type, uploaded_file.content_type.to_s.strip)
97
97
  instance_write(:file_size, uploaded_file.size.to_i)
98
98
  instance_write(:updated_at, Time.now)
@@ -345,18 +345,11 @@ module Paperclip
345
345
 
346
346
  def post_process #:nodoc:
347
347
  return if @queued_for_write[:original].nil?
348
- return if fire_events(:before)
349
- post_process_styles
350
- return if fire_events(:after)
351
- end
352
-
353
- def fire_events(which) #:nodoc:
354
- return true if callback(:"#{which}_post_process") == false
355
- return true if callback(:"#{which}_#{name}_post_process") == false
356
- end
357
-
358
- def callback which #:nodoc:
359
- instance.run_callbacks(which, @queued_for_write){|result, obj| result == false }
348
+ instance.run_paperclip_callbacks(:post_process) do
349
+ instance.run_paperclip_callbacks(:"#{name}_post_process") do
350
+ post_process_styles
351
+ end
352
+ end
360
353
  end
361
354
 
362
355
  def post_process_styles #:nodoc:
@@ -1,33 +1,61 @@
1
1
  module Paperclip
2
- # This module is intended as a compatability shim for the differences in
3
- # callbacks between Rails 2.0 and Rails 2.1.
4
2
  module CallbackCompatability
5
- def self.included(base)
6
- base.extend(ClassMethods)
7
- base.send(:include, InstanceMethods)
8
- end
3
+ module Rails21
4
+ def self.included(base)
5
+ base.extend(Defining)
6
+ base.send(:include, Running)
7
+ end
9
8
 
10
- module ClassMethods
11
- # The implementation of this method is taken from the Rails 1.2.6 source,
12
- # from rails/activerecord/lib/active_record/callbacks.rb, line 192.
13
- def define_callbacks(*args)
14
- args.each do |method|
15
- self.class_eval <<-"end_eval"
16
- def self.#{method}(*callbacks, &block)
17
- callbacks << block if block_given?
18
- write_inheritable_array(#{method.to_sym.inspect}, callbacks)
19
- end
20
- end_eval
9
+ module Defining
10
+ def define_paperclip_callbacks(*args)
11
+ args.each do |callback|
12
+ define_callbacks("before_#{callback}")
13
+ define_callbacks("after_#{callback}")
14
+ end
15
+ end
16
+ end
17
+
18
+ module Running
19
+ def run_paperclip_callbacks(callback, opts = nil, &blk)
20
+ # The overall structure of this isn't ideal since after callbacks run even if
21
+ # befores return false. But this is how rails 3's callbacks work, unfortunately.
22
+ if run_callbacks(:"before_#{callback}"){ |result, object| result == false } != false
23
+ blk.call
24
+ end
25
+ run_callbacks(:"after_#{callback}"){ |result, object| result == false }
21
26
  end
22
27
  end
23
28
  end
24
29
 
25
- module InstanceMethods
26
- # The callbacks in < 2.1 don't worry about the extra options or the
27
- # block, so just run what we have available.
28
- def run_callbacks(meth, opts = nil, &blk)
29
- callback(meth)
30
+ module Rails3
31
+ def self.included(base)
32
+ base.extend(Defining)
33
+ base.send(:include, Running)
30
34
  end
35
+
36
+ module Defining
37
+ def define_paperclip_callbacks(*callbacks)
38
+ define_callbacks *[callbacks, {:terminator => "result == false"}].flatten
39
+ callbacks.each do |callback|
40
+ eval <<-end_callbacks
41
+ def before_#{callback}(*args, &blk)
42
+ set_callback(:#{callback}, :before, *args, &blk)
43
+ end
44
+ def after_#{callback}(*args, &blk)
45
+ set_callback(:#{callback}, :after, *args, &blk)
46
+ end
47
+ end_callbacks
48
+ end
49
+ end
50
+ end
51
+
52
+ module Running
53
+ def run_paperclip_callbacks(callback, opts = nil, &block)
54
+ run_callbacks(callback, opts, &block)
55
+ end
56
+ end
57
+
31
58
  end
59
+
32
60
  end
33
61
  end
@@ -16,7 +16,7 @@ module Paperclip
16
16
  def self.from_file file
17
17
  file = file.path if file.respond_to? "path"
18
18
  geometry = begin
19
- Paperclip.run("identify", %Q[-format "%wx%h" "#{file}"[0]])
19
+ Paperclip.run("identify", "-format", "%wx%h", "#{file}[0]")
20
20
  rescue PaperclipCommandLineError
21
21
  ""
22
22
  end
@@ -51,14 +51,14 @@ module Paperclip
51
51
  attachment.instance_read(:updated_at).to_s
52
52
  end
53
53
 
54
- # Returns the RAILS_ROOT constant.
54
+ # Returns the Rails.root constant.
55
55
  def rails_root attachment, style_name
56
- RAILS_ROOT
56
+ Rails.root
57
57
  end
58
58
 
59
- # Returns the RAILS_ENV constant.
59
+ # Returns the Rails.env constant.
60
60
  def rails_env attachment, style_name
61
- RAILS_ENV
61
+ Rails.env
62
62
  end
63
63
 
64
64
  # Returns the underscored, pluralized version of the class name.
@@ -5,7 +5,7 @@ module IOStream
5
5
  # Returns a Tempfile containing the contents of the readable object.
6
6
  def to_tempfile
7
7
  name = respond_to?(:original_filename) ? original_filename : (respond_to?(:path) ? path : "stream")
8
- tempfile = Paperclip::Tempfile.new(File.basename(name))
8
+ tempfile = Paperclip::Tempfile.new("stream" + File.extname(name))
9
9
  tempfile.binmode
10
10
  self.stream_to(tempfile)
11
11
  end
@@ -2,3 +2,32 @@ require 'paperclip/matchers/have_attached_file_matcher'
2
2
  require 'paperclip/matchers/validate_attachment_presence_matcher'
3
3
  require 'paperclip/matchers/validate_attachment_content_type_matcher'
4
4
  require 'paperclip/matchers/validate_attachment_size_matcher'
5
+
6
+ module Paperclip
7
+ module Shoulda
8
+ # Provides rspec-compatible matchers for testing Paperclip attachments.
9
+ #
10
+ # In spec_helper.rb, you'll need to require the matchers:
11
+ #
12
+ # require "paperclip/matchers"
13
+ #
14
+ # And include the module:
15
+ #
16
+ # Spec::Runner.configure do |config|
17
+ # config.include Paperclip::Shoulda::Matchers
18
+ # end
19
+ #
20
+ # Example:
21
+ # describe User do
22
+ # it { should have_attached_file(:avatar) }
23
+ # it { should validate_attachment_presence(:avatar) }
24
+ # it { should validate_attachment_content_type(:avatar).
25
+ # allowing('image/png', 'image/gif').
26
+ # rejecting('text/plain', 'text/xml') }
27
+ # it { should validate_attachment_size(:avatar).
28
+ # less_than(2.megabytes) }
29
+ # end
30
+ module Matchers
31
+ end
32
+ end
33
+ end
@@ -1,6 +1,13 @@
1
1
  module Paperclip
2
2
  module Shoulda
3
3
  module Matchers
4
+ # Ensures that the given instance or class has an attachment with the
5
+ # given name.
6
+ #
7
+ # Example:
8
+ # describe User do
9
+ # it { should have_attached_file(:avatar) }
10
+ # end
4
11
  def have_attached_file name
5
12
  HaveAttachedFileMatcher.new(name)
6
13
  end
@@ -12,6 +19,7 @@ module Paperclip
12
19
 
13
20
  def matches? subject
14
21
  @subject = subject
22
+ @subject = @subject.class unless Class === @subject
15
23
  responds? && has_column? && included?
16
24
  end
17
25