destroy_soon 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ *.swp
6
+ *.swo
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
@@ -0,0 +1,12 @@
1
+ ## v0.0.3
2
+
3
+ * Configuring which delayed job queue to use
4
+
5
+ ## v0.0.2
6
+
7
+ * Fixing rubygems issue
8
+
9
+ ## v0.0.1
10
+
11
+ * Initial release.
12
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in destroy_soon.gemspec
4
+ gemspec
@@ -0,0 +1,80 @@
1
+ ## About
2
+
3
+ DestroySoon encapsulates the common pattern of asynchronously removing ActiveRecord models. In complex systems where there is a [God](http://en.wikipedia.org/wiki/God_object) entity, the God descruction take a long time to run due to all dependent destruction. In this case it's a good ideia to place the heavy weight job to the background.
4
+
5
+ DestroySoon uses [DelayedJob](https://github.com/collectiveidea/delayed_job) as queue processing system.
6
+
7
+ [![Build Status](https://secure.travis-ci.org/redu/destroy-soon.png)](http://travis-ci.org/redu/destroy-soon)
8
+
9
+ ## Quickstart
10
+
11
+ Add DestroySoon to your gemfile:
12
+
13
+ ```ruby
14
+ gem 'destroy_soon', :git => 'git://github.com/redu/destroy-soon.git'
15
+ ```
16
+
17
+ You just need to inject some behaivor to the object you want to destroy asynchronously:
18
+
19
+ ```ruby
20
+ class Course < ActiveRecord::Base
21
+ include DestroySoon::ModelAdditions
22
+ end
23
+ ```
24
+
25
+ The ActiveRecord model should have a new column called ``destroy_soon``. This column will be setted to true when a destruction task is scheduled. You should generate a migration as follows:
26
+
27
+ ```sh
28
+ $ rails g migration AddDestroySoonToCourse
29
+ ```
30
+
31
+ Edit the migration to add the column:
32
+
33
+ ```ruby
34
+ class AddDestroySoonToCourse < ActiveRecord::Migration
35
+ def self.up
36
+ add_column :courses, :destroy_soon, :boolean, :default => false
37
+ add_index :courses, :destroy_soon
38
+ end
39
+
40
+ def self.down
41
+ remove_column :courses, :destroy_soon
42
+ end
43
+ end
44
+ ```
45
+
46
+ And migrate the database using ``rake db:migrate``. In order to destroy Course instance in the backgroud call the ``async_destroy`` method:
47
+
48
+ ```ruby
49
+ class CoursesController < BaseController
50
+ def destroy
51
+ @course = Course.find(params[:id])
52
+ @course.async_destroy
53
+
54
+ respond_with(@course)
55
+ end
56
+ end
57
+ ```
58
+
59
+ ## Configuration
60
+
61
+ You can use DelayedJob's named queues setting the queue name as follows:
62
+
63
+ ```ruby
64
+ # config/initializers/destroy_soon.rb
65
+ DestroySoon::Queue.default_queue = "destruction"
66
+ ```
67
+
68
+ <img src="https://github.com/downloads/redu/redupy/redutech-marca.png" alt="Redu Educational Technologies" width="300">
69
+
70
+ This project is maintained and funded by [Redu Educational Techologies](http://tech.redu.com.br).
71
+
72
+ # Copyright
73
+
74
+ Copyright (c) 2012 Redu Educational Technologies
75
+
76
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
77
+
78
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
79
+
80
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,10 @@
1
+ require 'bundler/setup'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ desc 'Run the specs'
6
+ RSpec::Core::RakeTask.new do |r|
7
+ r.verbose = false
8
+ end
9
+
10
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ * Create migration generator
2
+ * initializer generator
3
+ * write the docs
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "destroy_soon/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "destroy_soon"
7
+ s.version = DestroySoon::VERSION
8
+ s.authors = ["Guilherme Cavalcanti"]
9
+ s.email = ["guiocavalcanti@gmail.com"]
10
+ s.homepage = "http://github.com/redu/destroy-soon"
11
+ s.summary = "Delayed destroy ActiveRecord model using DelayedJob as queue system"
12
+ s.description = "Delayed destroy ActiveRecord model"
13
+ s.rubyforge_project = "destroy_soon"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.test_files = Dir.glob('spec/**/*')
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_development_dependency "rspec"
22
+ s.add_development_dependency "sqlite3"
23
+
24
+ s.add_runtime_dependency "activerecord", "~> 3.0.10"
25
+ s.add_runtime_dependency "activesupport", "~> 3.0.10"
26
+ s.add_runtime_dependency "delayed_job_active_record", "~> 0.3.2"
27
+ s.add_runtime_dependency "rake"
28
+ end
@@ -0,0 +1,9 @@
1
+ require "destroy_soon/version"
2
+
3
+ module DestroySoon
4
+ # Your code goes here...
5
+ end
6
+
7
+ require "destroy_soon/job"
8
+ require "destroy_soon/queue"
9
+ require "destroy_soon/model_additions"
@@ -0,0 +1,17 @@
1
+ module DestroySoon
2
+ class Job
3
+ attr_accessor :entity_klass, :entity_id
4
+ def initialize(opts)
5
+ @entity_id = opts[:entity].id
6
+ @entity_klass = opts[:entity].class.to_s
7
+ end
8
+
9
+ def perform
10
+ entity.try(:destroy)
11
+ end
12
+
13
+ def entity
14
+ entity_klass.constantize.find_by_id(entity_id)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require "active_record"
2
+ require "delayed_job_active_record"
3
+
4
+ module DestroySoon::ModelAdditions
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ scope :will_not_be_destroyed, where(:destroy_soon => false)
8
+ end
9
+
10
+ def async_destroy
11
+ unless self.destroy_soon
12
+ self.update_attribute(:destroy_soon, true)
13
+
14
+ DestroySoon::Queue.new.enqueue DestroySoon::Job.new(:entity => self)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module DestroySoon
4
+ class Queue
5
+ DEFAULT_QUEUE = nil
6
+ cattr_accessor :default_queue
7
+
8
+ def initializer
9
+ @default_queue = default_queue || DEFAULT_QUEUE
10
+ end
11
+
12
+ def enqueue(job)
13
+ args = [job]
14
+ args << { :queue => default_queue } if default_queue
15
+
16
+ Delayed::Job.enqueue(*args)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module DestroySoon
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ module DestroySoon
4
+ describe ModelAdditions do
5
+ before(:all) do
6
+ class User < ActiveRecord::Base
7
+ include DestroySoon::ModelAdditions
8
+ end
9
+ end
10
+ after do
11
+ Delayed::Job.destroy_all
12
+ end
13
+ let(:subject) do
14
+ User.create(:name => "Call me susy")
15
+ end
16
+
17
+ it "should have a marked_for_destruction attr" do
18
+ User.new.should respond_to :destroy_soon?
19
+ end
20
+ it "should respond to delayed destroy" do
21
+ subject.should respond_to :async_destroy
22
+ end
23
+ it "should set destroy_soon to true when trying to destroy" do
24
+ expect {
25
+ subject.async_destroy
26
+ }.to change(subject, :destroy_soon?)
27
+ end
28
+ it "should delay the destruction" do
29
+ Queue.any_instance.should_receive(:enqueue)
30
+ subject.async_destroy
31
+ end
32
+ it "should not be enqueued again if it's going to be destroyed" do
33
+ Queue.any_instance.should_receive(:enqueue).once
34
+ 2.times { subject.async_destroy }
35
+ end
36
+ it "should scope by visibility" do
37
+ subject.async_destroy
38
+ User.will_not_be_destroyed.should_not include subject
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ module DestroySoon
4
+ describe Queue do
5
+ after do
6
+ Delayed::Job.destroy_all
7
+ end
8
+ before(:all) do
9
+ class User < ActiveRecord::Base
10
+ include DestroySoon::ModelAdditions
11
+ end
12
+ end
13
+ let(:user) do
14
+ User.create(:name => "call me susy")
15
+ end
16
+ let(:job) do
17
+ Job.new(:entity => user)
18
+ end
19
+ let(:subject) do
20
+ Queue.new
21
+ end
22
+
23
+ it "should enqueue the job" do
24
+ Delayed::Job.should_receive(:enqueue).with(job)
25
+ subject.enqueue(job)
26
+ end
27
+
28
+ it "should enqueue the job on the configured queue" do
29
+ Queue.default_queue = "general"
30
+ Delayed::Job.should_receive(:enqueue).with(job, :queue => "general")
31
+ subject.enqueue(job)
32
+ Queue.default_queue = nil
33
+ end
34
+
35
+ it "should call destroy after all" do
36
+ User.any_instance.should_receive(:destroy).once
37
+ subject.enqueue(job)
38
+ end
39
+
40
+ it "should return the job" do
41
+ subject.enqueue(job).should be_a Delayed::Job
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,26 @@
1
+ ActiveRecord::Schema.define do
2
+ begin
3
+ drop_table :users
4
+ drop_table :delayed_jobs
5
+ rescue
6
+ end
7
+
8
+ create_table "delayed_jobs" do |t|
9
+ t.integer "priority", :default => 0
10
+ t.integer "attempts", :default => 0
11
+ t.text "handler"
12
+ t.text "last_error"
13
+ t.datetime "run_at"
14
+ t.datetime "locked_at"
15
+ t.datetime "failed_at"
16
+ t.string "locked_by"
17
+ t.string "queue"
18
+ t.datetime "created_at"
19
+ t.datetime "updated_at"
20
+ end
21
+
22
+ create_table "users" do |t|
23
+ t.string :name
24
+ t.boolean :destroy_soon, :default => false
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
9
+
10
+ require "rubygems"
11
+ require "bundler/setup"
12
+ require "destroy_soon"
13
+
14
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
15
+ load("schema.rb")
16
+
17
+ RSpec.configure do |config|
18
+ config.treat_symbols_as_metadata_keys_with_true_values = true
19
+ config.run_all_when_everything_filtered = true
20
+ config.filter_run :focus
21
+ Delayed::Worker.delay_jobs = false
22
+
23
+ # Run specs in random order to surface order dependencies. If you find an
24
+ # order dependency and want to debug it, you can fix the order by providing
25
+ # the seed, which is printed after each run.
26
+ # --seed 1234
27
+ config.order = 'random'
28
+ end
metadata ADDED
@@ -0,0 +1,175 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: destroy_soon
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Guilherme Cavalcanti
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-10-22 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ none: false
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ hash: 3
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ prerelease: false
31
+ type: :development
32
+ name: rspec
33
+ requirement: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ version_requirements: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ hash: 3
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ prerelease: false
45
+ type: :development
46
+ name: sqlite3
47
+ requirement: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ version_requirements: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ hash: 19
55
+ segments:
56
+ - 3
57
+ - 0
58
+ - 10
59
+ version: 3.0.10
60
+ prerelease: false
61
+ type: :runtime
62
+ name: activerecord
63
+ requirement: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ version_requirements: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ hash: 19
71
+ segments:
72
+ - 3
73
+ - 0
74
+ - 10
75
+ version: 3.0.10
76
+ prerelease: false
77
+ type: :runtime
78
+ name: activesupport
79
+ requirement: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ version_requirements: &id005 !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ~>
85
+ - !ruby/object:Gem::Version
86
+ hash: 23
87
+ segments:
88
+ - 0
89
+ - 3
90
+ - 2
91
+ version: 0.3.2
92
+ prerelease: false
93
+ type: :runtime
94
+ name: delayed_job_active_record
95
+ requirement: *id005
96
+ - !ruby/object:Gem::Dependency
97
+ version_requirements: &id006 !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ hash: 3
103
+ segments:
104
+ - 0
105
+ version: "0"
106
+ prerelease: false
107
+ type: :runtime
108
+ name: rake
109
+ requirement: *id006
110
+ description: Delayed destroy ActiveRecord model
111
+ email:
112
+ - guiocavalcanti@gmail.com
113
+ executables: []
114
+
115
+ extensions: []
116
+
117
+ extra_rdoc_files: []
118
+
119
+ files:
120
+ - .gitignore
121
+ - .rspec
122
+ - .travis.yml
123
+ - CHANGELOG.mkd
124
+ - Gemfile
125
+ - README.mkd
126
+ - Rakefile
127
+ - TODO.mkd
128
+ - destroy_soon.gemspec
129
+ - lib/destroy_soon.rb
130
+ - lib/destroy_soon/job.rb
131
+ - lib/destroy_soon/model_additions.rb
132
+ - lib/destroy_soon/queue.rb
133
+ - lib/destroy_soon/version.rb
134
+ - spec/model_additions_spec.rb
135
+ - spec/queue_spec.rb
136
+ - spec/schema.rb
137
+ - spec/spec_helper.rb
138
+ homepage: http://github.com/redu/destroy-soon
139
+ licenses: []
140
+
141
+ post_install_message:
142
+ rdoc_options: []
143
+
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ hash: 3
152
+ segments:
153
+ - 0
154
+ version: "0"
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ hash: 3
161
+ segments:
162
+ - 0
163
+ version: "0"
164
+ requirements: []
165
+
166
+ rubyforge_project: destroy_soon
167
+ rubygems_version: 1.8.24
168
+ signing_key:
169
+ specification_version: 3
170
+ summary: Delayed destroy ActiveRecord model using DelayedJob as queue system
171
+ test_files:
172
+ - spec/model_additions_spec.rb
173
+ - spec/queue_spec.rb
174
+ - spec/schema.rb
175
+ - spec/spec_helper.rb