when_committed 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in when_committed.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 PeopleAdmin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,50 @@
1
+ # WhenCommitted
2
+
3
+ Provides `#when_commited` to run instance-specific code in an ActiveRecord
4
+ `#after_commit` callback.
5
+
6
+ This is very useful for things like enqueuing a background job that is triggered
7
+ by a model changing state. Usually, it is not sufficient to enqueue the job in
8
+ an `#after_save` hook, because there is always the chance that the save will be
9
+ rolled back (or that the job gets picked up before the save is committed). You
10
+ could try moving that code to an `after_commit` callback, but then you do not
11
+ have access to the `#changes` to your model (they have already been applied), so
12
+ it may be difficult to make decisions on whether to enqueue the job or not.
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ gem 'when_committed'
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install when_committed
27
+
28
+ ## Usage
29
+
30
+ Include the WhenCommitted::ActiveRecord module in your model:
31
+
32
+ class Post < ActiveRecord::Base
33
+ include WhenCommitted::ActiveRecord
34
+ end
35
+
36
+ Call `#when_committed` with a block of code that should run when the transaction
37
+ is committed:
38
+
39
+ def update_score(new_score)
40
+ self.score = new_score
41
+ when_committed { Resque.enqueue(RecalculateAggregateScores, self.id) }
42
+ end
43
+
44
+ ## Contributing
45
+
46
+ 1. [Fork it](https://github.com/PeopleAdmin/when_committed/fork_select)
47
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
48
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
49
+ 4. Push to the branch (`git push origin my-new-feature`)
50
+ 5. [Create new Pull Request](https://github.com/PeopleAdmin/when_committed/pull/new/master)
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,30 @@
1
+ require 'when_committed/version'
2
+
3
+ module WhenCommitted
4
+ module ActiveRecord
5
+ def self.included(base)
6
+ base.after_commit :run_when_committed_callbacks
7
+ base.after_rollback :clear_when_committed_callbacks
8
+ end
9
+
10
+ def when_committed(&block)
11
+ when_committed_callbacks << block
12
+ end
13
+
14
+ private
15
+
16
+ def when_committed_callbacks
17
+ @when_committed_callbacks ||= []
18
+ end
19
+
20
+ def run_when_committed_callbacks
21
+ when_committed_callbacks.each {|cb| cb.call}
22
+ clear_when_committed_callbacks
23
+ end
24
+
25
+ def clear_when_committed_callbacks
26
+ when_committed_callbacks.clear
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,3 @@
1
+ module WhenCommitted
2
+ VERSION = "0.9.0"
3
+ end
@@ -0,0 +1,105 @@
1
+ require 'active_record'
2
+ require 'when_committed'
3
+
4
+ describe "WhenCommitted" do
5
+ before(:all) do
6
+ ActiveRecord::Base.establish_connection :adapter => :nulldb
7
+ ActiveRecord::Migration.verbose = false
8
+ ActiveRecord::Schema.define do
9
+ create_table(:widgets) do |t|
10
+ t.string :name
11
+ t.integer :size
12
+ end
13
+ end
14
+ end
15
+
16
+ it "provides a #when_committed method" do
17
+ sample_class = Class.new(ActiveRecord::Base)
18
+ model = sample_class.new
19
+ model.should_not respond_to(:when_committed)
20
+ sample_class.send :include, WhenCommitted::ActiveRecord
21
+ model.should respond_to(:when_committed)
22
+ end
23
+
24
+ describe "#when_committed" do
25
+ before do
26
+ Backgrounder.reset
27
+ end
28
+ let(:model) { Widget.new }
29
+
30
+ it "runs the provided block after the transaction is committed" do
31
+ model.action_that_needs_follow_up_after_commit
32
+ model.save
33
+ Backgrounder.jobs.should == [:important_work]
34
+ end
35
+
36
+ it "does not run the provided block until the transaction is committed" do
37
+ Widget.transaction do
38
+ model.action_that_needs_follow_up_after_commit
39
+ Backgrounder.jobs.should be_empty
40
+ model.save
41
+ Backgrounder.jobs.should be_empty
42
+ end
43
+ Backgrounder.jobs.should == [:important_work]
44
+ end
45
+
46
+ it "does not run the provided block if the transaction is rolled back" do
47
+ begin
48
+ Widget.transaction do
49
+ model.action_that_needs_follow_up_after_commit
50
+ model.save
51
+ raise Catastrophe
52
+ end
53
+ rescue Catastrophe
54
+ end
55
+ Backgrounder.jobs.should be_empty
56
+ end
57
+
58
+ it "allows you to register multiple after_commit blocks" do
59
+ Widget.transaction do
60
+ model.action_that_needs_follow_up_after_commit
61
+ model.another_action_with_follow_up
62
+ model.save
63
+ end
64
+ Backgrounder.jobs.should == [:important_work,:more_work]
65
+ end
66
+
67
+ it "does not run a registered block more than once" do
68
+ Widget.transaction do
69
+ model.action_that_needs_follow_up_after_commit
70
+ model.save
71
+ end
72
+ Widget.transaction do
73
+ model.name = "changed"
74
+ model.save
75
+ end
76
+ Backgrounder.should have(1).job
77
+ end
78
+ end
79
+ end
80
+
81
+ class Widget < ActiveRecord::Base
82
+ include WhenCommitted::ActiveRecord
83
+ def action_that_needs_follow_up_after_commit
84
+ when_committed { Backgrounder.enqueue :important_work }
85
+ end
86
+ def another_action_with_follow_up
87
+ when_committed { Backgrounder.enqueue :more_work }
88
+ end
89
+ end
90
+
91
+ class Backgrounder
92
+ def self.enqueue job
93
+ jobs << job
94
+ end
95
+
96
+ def self.jobs
97
+ @jobs ||= []
98
+ end
99
+
100
+ def self.reset
101
+ @jobs = []
102
+ end
103
+ end
104
+
105
+ class Catastrophe < StandardError; end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'when_committed/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "when_committed"
8
+ gem.version = WhenCommitted::VERSION
9
+ gem.authors = ["Joshua Flanagan"]
10
+ gem.email = ["jflanagan@peopleadmin.com"]
11
+ gem.description = %q{Run a piece of code after the current transaction is committed}
12
+ gem.summary = %q{Some actions (like enqueuing a background job) should not run until
13
+ the current ActiveRecord transaction has committed. ActiveRecord defines an `#after_commit` callback,
14
+ but it run for every transaction, for every instance of a class. `#when_committed` allows you to
15
+ dynamically define a block of code that should run when the transaction is committed.}
16
+ gem.homepage = "https://github.com/PeopleAdmin/when_committed"
17
+
18
+ gem.files = `git ls-files`.split($/)
19
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
20
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
21
+ gem.require_paths = ["lib"]
22
+ gem.add_dependency "activerecord", ">=3.1"
23
+ gem.add_development_dependency "activerecord-nulldb-adapter"
24
+ gem.add_development_dependency "rspec"
25
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: when_committed
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Joshua Flanagan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ prerelease: false
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3.1'
22
+ none: false
23
+ type: :runtime
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ! '>='
27
+ - !ruby/object:Gem::Version
28
+ version: '3.1'
29
+ none: false
30
+ - !ruby/object:Gem::Dependency
31
+ name: activerecord-nulldb-adapter
32
+ prerelease: false
33
+ requirement: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ none: false
39
+ type: :development
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ none: false
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ prerelease: false
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ none: false
55
+ type: :development
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ none: false
62
+ description: Run a piece of code after the current transaction is committed
63
+ email:
64
+ - jflanagan@peopleadmin.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - LICENSE.txt
72
+ - README.md
73
+ - Rakefile
74
+ - lib/when_committed.rb
75
+ - lib/when_committed/version.rb
76
+ - spec/when_committed_spec.rb
77
+ - when_committed.gemspec
78
+ homepage: https://github.com/PeopleAdmin/when_committed
79
+ licenses: []
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ none: false
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ none: false
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 1.8.24
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Some actions (like enqueuing a background job) should not run until the current
102
+ ActiveRecord transaction has committed. ActiveRecord defines an `#after_commit`
103
+ callback, but it run for every transaction, for every instance of a class. `#when_committed`
104
+ allows you to dynamically define a block of code that should run when the transaction
105
+ is committed.
106
+ test_files:
107
+ - spec/when_committed_spec.rb