delayed_paperclip 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.log
2
+ public/
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
6
+ require 'paperclip'
7
+
8
+ desc 'Default: run unit tests.'
9
+ task :default => [:clean, :test]
10
+
11
+ desc 'Test the paperclip plugin.'
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'lib'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+
18
+ desc 'Generate documentation for the paperclip plugin.'
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'doc'
21
+ rdoc.title = 'Delayed::Paperclip'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('README*')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
26
+
27
+ desc 'Clean up files.'
28
+ task :clean do |t|
29
+ FileUtils.rm_rf "doc"
30
+ FileUtils.rm_rf "tmp"
31
+ FileUtils.rm_rf "pkg"
32
+ FileUtils.rm "test/debug.log" rescue nil
33
+ FileUtils.rm "test/paperclip.db" rescue nil
34
+ Dir.glob("paperclip-*.gem").each{|f| FileUtils.rm f }
35
+ end
36
+
37
+ begin
38
+ require 'jeweler'
39
+ Jeweler::Tasks.new do |gemspec|
40
+ gemspec.name = "delayed_paperclip"
41
+ gemspec.summary = "Process your Paperclip attachments in the background with delayed_job."
42
+ gemspec.description = "Process your Paperclip attachments in the background with delayed_job."
43
+ gemspec.email = "jesse@jstorimer.com"
44
+ gemspec.homepage = "http://github.com/jstorimer/delayed_paperclip"
45
+ gemspec.authors = ["Jesse Storimer"]
46
+ gemspec.add_dependency('paperclip', '>= 2.3.0')
47
+ gemspec.add_dependency('delayed_job', '>= 1.8.0')
48
+ end
49
+ Jeweler::GemcutterTasks.new
50
+ rescue LoadError
51
+ puts "Jeweler not available. Install it with: sudo gem install jeweler -s http://gemcutter.org"
52
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/dev/null ADDED
File without changes
@@ -0,0 +1,72 @@
1
+ module Delayed
2
+ module Paperclip
3
+ def self.included(base) #:nodoc:
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+ module ClassMethods
8
+ # +process_in_background+ gives the class it is called on an attribute that maps to a file. This
9
+ # is typically a file stored somewhere on the filesystem and has been uploaded by a user.
10
+ # The attribute returns a Paperclip::Attachment object which handles the management of
11
+ # that file. The intent is to make the attachment as much like a normal attribute. The
12
+ # thumbnails will be created when the new file is assigned, but they will *not* be saved
13
+ # until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is
14
+ # called on it, the attachment will *not* be deleted until +save+ is called. See the
15
+ # Paperclip::Attachment documentation for more specifics. There are a number of options
16
+ # you can set to change the behavior of a Paperclip attachment:
17
+ # * +url+: The full URL of where the attachment is publically accessible. This can just
18
+ # as easily point to a directory served directly through Apache as it can to an action
19
+ # that can control permissions. You can specify the full domain and path, but usually
20
+ # just an absolute path is sufficient. The leading slash *must* be included manually for
21
+ # absolute paths. The default value is
22
+ # "/system/:attachment/:id/:style/:filename". See
23
+ # Paperclip::Attachment#interpolate for more information on variable interpolaton.
24
+ # :url => "/:class/:attachment/:id/:style_:filename"
25
+ # :url => "http://some.other.host/stuff/:class/:id_:extension"
26
+ # * +default_url+: The URL that will be returned if there is no attachment assigned.
27
+ # This field is interpolated just as the url is. The default value is
28
+ # "/:attachment/:style/missing.png"
29
+ # has_attached_file :avatar, :default_url => "/images/default_:style_avatar.png"
30
+ # User.new.avatar_url(:small) # => "/images/default_small_avatar.png"
31
+
32
+ def process_in_background(name)
33
+ include InstanceMethods
34
+
35
+ define_method "#{name}_changed?" do
36
+ attachment_changed?(name)
37
+ end
38
+
39
+ define_method "halt_processing_for_#{name}" do
40
+ if self.send("#{name}_changed?")
41
+ self.processing = true if self.respond_to?(:processing)
42
+ false # halts processing
43
+ end
44
+ end
45
+
46
+ define_method "enqueue_job_for_#{name}" do
47
+ if self.send("#{name}_changed?")
48
+ Delayed::Job.enqueue DelayedPaperclipJob.new(read_attribute(:id), self.class.name, name.to_sym)
49
+ end
50
+ end
51
+
52
+ self.send("before_#{name}_post_process", :"halt_processing_for_#{name}")
53
+ after_save :"enqueue_job_for_#{name}"
54
+ end
55
+ end
56
+
57
+ module InstanceMethods
58
+ PAPERCLIP_ATTRIBUTES = ['_file_size', '_file_name', '_content_type', '_updated_at']
59
+
60
+ def attachment_changed?(name)
61
+ PAPERCLIP_ATTRIBUTES.each do |attribute|
62
+ full_attribute = "#{name}#{attribute}_changed?".to_sym
63
+
64
+ next unless self.respond_to?(full_attribute)
65
+ return true if self.send("#{name}#{attribute}_changed?")
66
+ end
67
+
68
+ false
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,12 @@
1
+ class DelayedPaperclipJob < Struct.new(:instance_id, :instance_klass, :attachment_name)
2
+ def perform
3
+ instance = instance_klass.constantize.find(instance_id)
4
+
5
+ instance.send(attachment_name).reprocess!
6
+
7
+ if instance.respond_to?(:processing)
8
+ instance.processing = false
9
+ instance.save
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ require 'delayed/paperclip'
2
+ require 'delayed/paperclip_job'
3
+
4
+ if Object.const_defined?("ActiveRecord")
5
+ ActiveRecord::Base.send(:include, Delayed::Paperclip)
6
+ end
data/test/database.yml ADDED
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+
@@ -0,0 +1,107 @@
1
+ require 'test/test_helper'
2
+
3
+ class DelayedPaperclipTest < Test::Unit::TestCase
4
+ def setup
5
+ build_delayed_jobs
6
+ reset_dummy
7
+ end
8
+
9
+ def test_attachment_changed
10
+ @dummy.stubs(:image_file_size_changed?).returns(false)
11
+ @dummy.stubs(:image_file_name_changed?).returns(false)
12
+
13
+ assert !@dummy.image_changed?
14
+ end
15
+
16
+ def test_attachment_changed_when_image_changes
17
+ @dummy.stubs(:image_file_size_changed?).returns(true)
18
+
19
+ assert @dummy.image_changed?
20
+ end
21
+
22
+ def test_before_post_process
23
+ Dummy.expects(:before_image_post_process)
24
+ @dummy_class.process_in_background :image
25
+ end
26
+
27
+ def test_halt_processing_if_source_changed
28
+ @dummy.stubs(:image_changed?).returns(true)
29
+ assert !@dummy.halt_processing_for_image
30
+ end
31
+
32
+ def test_halt_processing_if_source_changed_and_processing_attribute_defined
33
+ reset_table("dummies") do |d|
34
+ d.string :image_file_name
35
+ d.integer :image_file_size
36
+ d.boolean :processing
37
+ end
38
+ @dummy_class = reset_class "Dummy"
39
+ @dummy_class.has_attached_file :image
40
+ @dummy_class.process_in_background :image
41
+ @dummy = Dummy.new(:image => File.read("#{RAILS_ROOT}/test/fixtures/12k.png"))
42
+
43
+ @dummy.stubs(:image_changed?).returns(true)
44
+ assert !@dummy.halt_processing_for_image
45
+ assert @dummy.processing
46
+ end
47
+
48
+ def test_halt_processing_if_source_has_not_changed
49
+ @dummy.stubs(:image_changed?).returns(false)
50
+ assert_not_equal false, @dummy.halt_processing_for_image
51
+ end
52
+
53
+ def test_after_save
54
+ Dummy.expects(:after_save)
55
+ @dummy_class.process_in_background :image
56
+ end
57
+
58
+ def test_enqueue_job_if_source_changed
59
+ @dummy.stubs(:image_changed?).returns(true)
60
+
61
+ original_job_count = Delayed::Job.count
62
+ @dummy.enqueue_job_for_image
63
+
64
+ assert_equal original_job_count + 1, Delayed::Job.count
65
+ end
66
+
67
+ def test_perform_job
68
+ Paperclip::Attachment.any_instance.expects(:reprocess!)
69
+
70
+ @dummy.save!
71
+ DelayedPaperclipJob.new(@dummy.id, @dummy.class.name, :image).perform
72
+ end
73
+
74
+ def test_perform_job_with_processing_attribute
75
+ reset_table("dummies") do |d|
76
+ d.string :image_file_name
77
+ d.integer :image_file_size
78
+ d.boolean :processing
79
+ end
80
+ @dummy_class = reset_class "Dummy"
81
+ @dummy_class.has_attached_file :image
82
+ @dummy_class.process_in_background :image
83
+
84
+ @dummy = Dummy.new(:image => File.open("#{RAILS_ROOT}/test/fixtures/12k.png"))
85
+
86
+ Paperclip::Attachment.any_instance.expects(:reprocess!)
87
+
88
+ @dummy.processing = true
89
+ @dummy.save!
90
+ DelayedPaperclipJob.new(@dummy.id, @dummy.class.name, :image).perform
91
+
92
+ assert !@dummy.reload.processing
93
+ end
94
+
95
+ private
96
+ def reset_dummy
97
+ reset_table("dummies") do |d|
98
+ d.string :image_file_name
99
+ d.integer :image_file_size
100
+ end
101
+ @dummy_class = reset_class "Dummy"
102
+ @dummy_class.has_attached_file :image
103
+ @dummy_class.process_in_background :image
104
+
105
+ @dummy = Dummy.new(:image => File.open("#{RAILS_ROOT}/test/fixtures/12k.png"))
106
+ end
107
+ end
Binary file
@@ -0,0 +1,84 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'mocha'
4
+
5
+ require 'active_record'
6
+ require 'active_support'
7
+
8
+ gem 'sqlite3-ruby'
9
+ gem 'paperclip'
10
+ require 'paperclip'
11
+ gem 'delayed_job'
12
+ require 'delayed_job'
13
+
14
+ FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
15
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
16
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
17
+ ActiveRecord::Base.establish_connection(config['test'])
18
+
19
+ ROOT = File.join(File.dirname(__FILE__), '..')
20
+ RAILS_ROOT = ROOT
21
+ RAILS_ENV = "test"
22
+
23
+ $LOAD_PATH << File.join(ROOT, 'lib')
24
+ $LOAD_PATH << File.join(ROOT, 'lib', 'delayed', 'paperclip')
25
+ $LOAD_PATH << File.join(ROOT, 'test')
26
+
27
+ module ActiveRecord
28
+ class Base
29
+ end
30
+ end
31
+
32
+ require File.join(ROOT, 'lib', 'delayed_paperclip.rb')
33
+
34
+ def reset_class class_name
35
+ ActiveRecord::Base.send(:include, Paperclip)
36
+ Object.send(:remove_const, class_name) rescue nil
37
+ klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
38
+ klass.class_eval{ include Paperclip }
39
+ klass
40
+ end
41
+
42
+ def reset_table table_name, &block
43
+ block ||= lambda { |table| true }
44
+ ActiveRecord::Base.connection.create_table :dummies, {:force => true}, &block
45
+ end
46
+
47
+ def modify_table table_name, &block
48
+ ActiveRecord::Base.connection.change_table :dummies, &block
49
+ end
50
+
51
+ def rebuild_model options = {}
52
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
53
+ table.column :other, :string
54
+ table.column :avatar_file_name, :string
55
+ table.column :avatar_content_type, :string
56
+ table.column :avatar_file_size, :integer
57
+ table.column :avatar_updated_at, :datetime
58
+ end
59
+ rebuild_class options
60
+ end
61
+
62
+ def rebuild_class options = {}
63
+ ActiveRecord::Base.send(:include, Paperclip)
64
+ Object.send(:remove_const, "Dummy") rescue nil
65
+ Object.const_set("Dummy", Class.new(ActiveRecord::Base))
66
+ Dummy.class_eval do
67
+ include Paperclip
68
+ has_attached_file :avatar, options
69
+ end
70
+ end
71
+
72
+ def build_delayed_jobs
73
+ ActiveRecord::Base.connection.create_table :delayed_jobs, :force => true do |table|
74
+ table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
75
+ table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
76
+ table.text :handler # YAML-encoded string of the object that will do work
77
+ table.string :last_error # reason for last failure (See Note below)
78
+ table.datetime :run_at # When to run. Could be Time.now for immediately, or sometime in the future.
79
+ table.datetime :locked_at # Set when a client is working on this object
80
+ table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
81
+ table.string :locked_by # Who is working on this object (if locked)
82
+ table.timestamps
83
+ end
84
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: delayed_paperclip
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jesse Storimer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-26 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: paperclip
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.3.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: delayed_job
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.0
34
+ version:
35
+ description: Process your Paperclip attachments in the background with delayed_job.
36
+ email: jesse@jstorimer.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - .gitignore
45
+ - Rakefile
46
+ - VERSION
47
+ - dev/null
48
+ - lib/delayed/paperclip.rb
49
+ - lib/delayed/paperclip_job.rb
50
+ - lib/delayed_paperclip.rb
51
+ - test/database.yml
52
+ - test/delayed_paperclip_test.rb
53
+ - test/fixtures/12k.png
54
+ - test/test_helper.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/jstorimer/delayed_paperclip
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options:
61
+ - --charset=UTF-8
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.5
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: Process your Paperclip attachments in the background with delayed_job.
83
+ test_files:
84
+ - test/delayed_paperclip_test.rb
85
+ - test/test_helper.rb