delayed_paperclip 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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