when_committed 0.9.0

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.
@@ -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