mongoid_optimistic_locking 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .idea
6
+ *.iml
7
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mongoid_optimistic_locking.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2012 Boxee
2
+
3
+ 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:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ 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,57 @@
1
+ # mongoid\_optimistic\_locking
2
+
3
+ This gem helps to abstract the ["Update if Current"](http://www.mongodb.org/display/DOCS/Atomic+Operations#AtomicOperations-%22UpdateifCurrent%22) method which may be used as a replacement for [transactions in Mongo](http://docs.mongodb.org/manual/faq/developers/#how-do-i-do-transactions-and-locking-in-mongodb).
4
+
5
+ The gem is an addon over [Mongoid ODM](http://mongoid.org/) and is based on [ActiveRecord's Optimistic Locking](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html).
6
+
7
+ ## Compatibility
8
+
9
+ So far it works with the Rails 3 and Mongoid 2.4.
10
+
11
+ Created branch for edge *Mongoid 3*.
12
+
13
+ ## Rails 3 Installation
14
+
15
+ Add the gem to your `Gemfile`:
16
+
17
+ gem 'mongoid_optimistic_locking'
18
+
19
+ ## Usage
20
+
21
+ To use it, all you have to do is add include `Mongoid::OptimisticLocking`:
22
+
23
+ class Post
24
+ include Mongoid::Document
25
+ include Mongoid::OptimisticLocking
26
+
27
+ field :text
28
+ end
29
+
30
+ This will add a `_lock_version` field in the document which will be incremented every time a save is called.
31
+ Be sure to rescue `Mongoid::Errors::StaleDocument` to handle applicative logic in case the object was changed.
32
+
33
+ For example:
34
+
35
+ class PostController < ApplicationController
36
+ ## Adds an "UPDATE: ...some text..." to an existing document
37
+ def add_update
38
+ begin
39
+ post = Post.find(params[:id])
40
+ post.text += "---UPDATE--- " + params[:more_text]
41
+ post.save
42
+ rescue Mongoid::Errors::StaleDocument
43
+ retry
44
+ end
45
+ end
46
+ end
47
+
48
+ That's it!
49
+
50
+ ## Open sourced by
51
+
52
+ [Boxee](http://www.boxee.tv)
53
+
54
+ ## References
55
+ [Mongo Developer FAQ - How do I do transactions/locking?](http://docs.mongodb.org/manual/faq/developers/#how-do-i-do-transactions-and-locking-in-mongodb)
56
+
57
+ [Mongo Atomic Operations - "Update if Current"](http://www.mongodb.org/display/DOCS/Atomic+Operations#AtomicOperations-%22UpdateifCurrent%22)
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,9 @@
1
+ en:
2
+ mongoid:
3
+ errors:
4
+ messages:
5
+ stale_document:
6
+ update:
7
+ "Attempted to update a stale document: %{klass}"
8
+ destroy:
9
+ "Attempted to destroy a stale document: %{klass}"
@@ -0,0 +1,28 @@
1
+ require 'mongoid/errors/mongoid_error'
2
+
3
+ module Mongoid
4
+ module Errors
5
+
6
+ # Raised when trying to update a document that has been updated by
7
+ # another process.
8
+ #
9
+ # @example Create the error.
10
+ # StaleDocument.new('update', document)
11
+ class StaleDocument < MongoidError
12
+
13
+ attr_reader :action, :document
14
+
15
+ def initialize(action, document)
16
+ @action = action
17
+ @document = document
18
+
19
+ super(
20
+ translate(
21
+ "stale_document.#{action}",
22
+ { :klass => document.class.name }
23
+ )
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ module Mongoid
2
+
3
+ module Lockable
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ ActiveSupport::Deprecation.warn 'Mongoid::Lockable is deprecated and will be removed. Use Mongoid::OptimisticLocking instead.', caller
9
+ include Mongoid::OptimisticLocking
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ require 'mongoid'
2
+ require 'mongoid/errors/stale_document'
3
+ require 'mongoid/lockable'
4
+ require 'mongoid/optimistic_locking/deprecated'
5
+ require 'mongoid/optimistic_locking/lock_version'
6
+ require 'mongoid/optimistic_locking/operations'
7
+ require 'mongoid/optimistic_locking/threaded_with_unlocked'
8
+ require 'mongoid/optimistic_locking/unlocked'
9
+ require 'mongoid/optimistic_locking/version'
10
+
11
+ # monkey patch Threaded
12
+ Mongoid::Threaded.send :include, Mongoid::OptimisticLocking::ThreadedWithUnlocked
13
+
14
+ # add english load path to translations
15
+ I18n.load_path << File.expand_path('../../config/locales/en.yml', __FILE__)
16
+
17
+ module Mongoid
18
+ # == What is Optimistic Locking
19
+ #
20
+ # See <http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html>.
21
+ #
22
+ # == Usage
23
+ #
24
+ # TODO ...
25
+ module OptimisticLocking
26
+
27
+ extend ActiveSupport::Concern
28
+
29
+ include Deprecated
30
+ include LockVersion
31
+ include Operations
32
+ include Unlocked
33
+
34
+ included do
35
+ field LOCKING_FIELD, :type => Integer, :default => 0
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ module Mongoid
2
+ module OptimisticLocking
3
+ module Deprecated
4
+
5
+ def save_optimistic!(*args)
6
+ ActiveSupport::Deprecation.warn 'save_optimistic! is deprecated and will be removed. Use save or save! instead', caller
7
+ save! *args
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ module Mongoid
2
+ module OptimisticLocking
3
+ module LockVersion
4
+
5
+ LOCKING_FIELD = :_lock_version
6
+
7
+ private
8
+
9
+ attr_reader :lock_version_for_selector
10
+
11
+ def set_lock_version_for_selector
12
+ @lock_version_for_selector = self[LOCKING_FIELD]
13
+ yield
14
+ rescue Exception
15
+ @lock_version_for_selector = nil
16
+ raise
17
+ end
18
+
19
+ def increment_lock_version
20
+ self[LOCKING_FIELD] = self[LOCKING_FIELD] ? self[LOCKING_FIELD] + 1 : 1
21
+ yield
22
+ rescue Exception
23
+ self[LOCKING_FIELD] = self[LOCKING_FIELD] ? self[LOCKING_FIELD] - 1 : 0
24
+ raise
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ module Mongoid
2
+ module OptimisticLocking
3
+ module Operations
4
+
5
+ def insert(*args)
6
+ return super unless optimistic_locking?
7
+ increment_lock_version do
8
+ super
9
+ end
10
+ end
11
+
12
+ def update(*args)
13
+ return super unless optimistic_locking?
14
+ set_lock_version_for_selector do
15
+ increment_lock_version do
16
+ result = super
17
+ unless Mongoid.database.command({:getlasterror => 1})['updatedExisting']
18
+ raise Mongoid::Errors::StaleDocument.new('update', self)
19
+ end
20
+ result
21
+ end
22
+ end
23
+ end
24
+
25
+ def remove(*args)
26
+ return super unless optimistic_locking?
27
+ set_lock_version_for_selector do
28
+ result = super
29
+ unless Mongoid.database.command({:getlasterror => 1})['updatedExisting']
30
+ raise Mongoid::Errors::StaleDocument.new('destroy', self)
31
+ end
32
+ result
33
+ end
34
+ end
35
+
36
+ def atomic_selector
37
+ result = super
38
+ if optimistic_locking? && lock_version_for_selector
39
+ key =
40
+ if metadata && metadata.embedded?
41
+ path = metadata.path(self)
42
+ "#{path.path}._lock_version"
43
+ else
44
+ '_lock_version'
45
+ end
46
+ result[key] = lock_version_for_selector
47
+ end
48
+ result
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,30 @@
1
+ module Mongoid
2
+ module OptimisticLocking
3
+ module ThreadedWithUnlocked
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+
9
+ def optimistic_locking?
10
+ !unlocked
11
+ end
12
+
13
+ def unlocked
14
+ !!Thread.current["[mongoid]:unlocked"]
15
+ end
16
+
17
+ def unlocked=(value)
18
+ Thread.current["[mongoid]:unlocked"] = value
19
+ end
20
+
21
+ def clear_options!
22
+ self.unlocked = false
23
+ super
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ module Mongoid
2
+ module OptimisticLocking
3
+ module Unlocked
4
+
5
+ extend ActiveSupport::Concern
6
+
7
+ def unlocked
8
+ Threaded.unlocked = true
9
+ self
10
+ end
11
+
12
+ def optimistic_locking?
13
+ Threaded.optimistic_locking?
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ def unlocked
19
+ Threaded.unlocked = true
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,5 @@
1
+ module Mongoid
2
+ module OptimisticLocking
3
+ VERSION = '0.0.2'
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ require 'mongoid/optimistic_locking'
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mongoid/optimistic_locking/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "mongoid_optimistic_locking"
7
+ s.version = Mongoid::OptimisticLocking::VERSION
8
+ s.authors = ["Alon Burg", "John Nishinaga"]
9
+ s.email = ["burgalon@gmail.com", "jingoro@casa-z.org"]
10
+ s.homepage = "https://github.com/burgalon/mongoid_optimistic_locking"
11
+ s.summary = %q{Allows optimisitic locking for Mongoid models}
12
+ s.description = %q{Allows optimisitic locking for Mongoid models. See https://github.com/burgalon/mongoid_optimistic_locking}
13
+
14
+ s.add_dependency 'mongoid', '~> 2.4'
15
+ s.add_development_dependency 'rake', '~> 0.9.0'
16
+ s.add_development_dependency 'rspec', '~> 2.6'
17
+ s.add_development_dependency 'bson_ext', '~> 1.5'
18
+
19
+ s.rubyforge_project = "mongoid_optimistic_locking"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+
26
+ # specify any dependencies here; for example:
27
+ # s.add_development_dependency "rspec"
28
+ # s.add_runtime_dependency "rest-client"
29
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ class Post
4
+ include Mongoid::Document
5
+ ::ActiveSupport::Deprecation.silence do
6
+ include Mongoid::Lockable
7
+ end
8
+
9
+ field :title
10
+
11
+ embeds_many :comments
12
+ end
13
+
14
+ class Comment
15
+ include Mongoid::Document
16
+ ::ActiveSupport::Deprecation.silence do
17
+ include Mongoid::Lockable
18
+ end
19
+
20
+ field :text
21
+ embedded_in :post
22
+ end
23
+
24
+ describe Mongoid::Lockable do
25
+
26
+ before { ::ActiveSupport::Deprecation.silenced = true }
27
+ after { ::ActiveSupport::Deprecation.silenced = false }
28
+
29
+ before :all do
30
+ @post = Post.create(:text => 'original-text')
31
+ @post._lock_version.should == 1
32
+ end
33
+
34
+ it "simulate a migration situation in which _lock_version did not exist" do
35
+ Post.update_all(:_lock_version => nil)
36
+ @post.reload.save_optimistic!.should == true
37
+ end
38
+
39
+ describe "test root documents" do
40
+ it "saves regularly if there's no other process changing the data in the background" do
41
+ @post.text = 'changed-text'
42
+ @post.save_optimistic!.should == true
43
+ @post._lock_version.should == 2
44
+ @post.reload
45
+ @post.text.should == 'changed-text'
46
+ @post._lock_version.should == 2
47
+ end
48
+
49
+ it "raises Stale exception if another process/background code updates the object" do
50
+ post_clone = Post.find(@post.id)
51
+ # the before_filter should increments the version by one, thus making the object stale
52
+ post_clone.text = 'changed-in-background'
53
+ post_clone.save
54
+
55
+ @post.text = 'changed-text'
56
+ expect { @post.save_optimistic! }.to raise_error(Mongoid::Errors::StaleDocument)
57
+
58
+ # Should fail again if still not refreshed
59
+ # i.e: test that _lock_version is decremented upon failure
60
+ expect { @post.save_optimistic! }.to raise_error(Mongoid::Errors::StaleDocument)
61
+
62
+ # Test StaleDocument error
63
+ begin
64
+ @post.save_optimistic!
65
+ rescue Mongoid::Errors::StaleDocument => e
66
+ e.message().should match('Post')
67
+ end
68
+
69
+ @post.reload
70
+ @post.text.should == 'changed-in-background'
71
+
72
+ post_clone.text = 'changed-in-background'
73
+ post_clone.save
74
+ end
75
+ end
76
+
77
+ describe "test embedded documents" do
78
+ before :all do
79
+ @post = Post.create(:text => 'original-text')
80
+ @comment = @post.comments.create!(:text => 'First comment')
81
+ end
82
+
83
+ it "saves regularly if there's no other process changing the data in the background" do
84
+ @comment.text = 'First comment updated!'
85
+ @comment.save_optimistic!.should == true
86
+ @comment._lock_version.should == 2
87
+ @comment.reload
88
+ @comment.text.should == 'First comment updated!'
89
+ @comment._lock_version.should == 2
90
+ end
91
+
92
+ it "raises Stale exception if another process/background code updates the object" do
93
+ @comment_clone = Post.find(@post.id).comments.find(@comment.id)
94
+ # the before_filter should increments the version by one, thus making the object stale
95
+ @comment_clone.text = 'changed-in-background'
96
+ @comment_clone.save
97
+
98
+ @comment.text = 'changed-text'
99
+ expect { @comment.save_optimistic! }.to raise_error(Mongoid::Errors::StaleDocument)
100
+
101
+ # Should fail again if still not refreshed
102
+ # i.e: test that _lock_version is decremented upon failure
103
+ expect { @comment.save_optimistic! }.to raise_error(Mongoid::Errors::StaleDocument)
104
+
105
+ # Test StaleDocument error
106
+ begin
107
+ @comment.save_optimistic!
108
+ rescue Mongoid::Errors::StaleDocument => e
109
+ e.message().should match('Comment')
110
+ end
111
+
112
+ @comment.reload
113
+ @comment.text.should == 'changed-in-background'
114
+
115
+ @comment_clone.text = 'changed-in-background'
116
+ @comment_clone.save
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::OptimisticLocking do
4
+
5
+ context 'without optimistic locking' do
6
+
7
+ let(:company_class) do
8
+ Class.new do
9
+ include Mongoid::Document
10
+ self.collection_name = 'companies'
11
+ field :name
12
+ end
13
+ end
14
+
15
+ it 'should allow collisions' do
16
+ c1 = company_class.create!(:name => 'Acme')
17
+ c2 = company_class.find(c1.id)
18
+ c1.name = 'Biz'
19
+ c1.save.should == true
20
+ c2.name = 'Baz'
21
+ c2.save.should == true
22
+ end
23
+
24
+ end
25
+
26
+ context 'three instances of the same document' do
27
+
28
+ let(:person_class) do
29
+ Class.new do
30
+ include Mongoid::Document
31
+ include Mongoid::OptimisticLocking
32
+ self.collection_name = 'people'
33
+ field :name
34
+ end
35
+ end
36
+
37
+ before do
38
+ @p1 = person_class.create!(:name => 'Bob')
39
+ @p2 = person_class.find(@p1.id)
40
+ @p3 = person_class.find(@p1.id)
41
+ end
42
+
43
+ context 'after updating the first' do
44
+
45
+ before do
46
+ @p1.name = 'Michael'
47
+ @p1.save.should == true
48
+ end
49
+
50
+ it 'should fail when updating the second' do
51
+ expect {
52
+ @p2.name = 'George'
53
+ @p2.save
54
+ }.to raise_error(Mongoid::Errors::StaleDocument)
55
+ end
56
+
57
+ it 'should succeed when updating the second without locking' do
58
+ @p2.name = 'George'
59
+ @p2.unlocked.save.should == true
60
+ end
61
+
62
+ it 'should succeed when updating the second without locking, ' +
63
+ 'then fail when updating the third' do
64
+ @p2.name = 'George'
65
+ @p2.unlocked.save.should == true
66
+ expect {
67
+ @p3.name = 'Sally'
68
+ @p3.save
69
+ }.to raise_error(Mongoid::Errors::StaleDocument)
70
+ end
71
+
72
+ it 'should fail when destroying the second' do
73
+ expect {
74
+ @p2.destroy
75
+ }.to raise_error(Mongoid::Errors::StaleDocument)
76
+ end
77
+
78
+ it 'should succeed when destroying the second without locking' do
79
+ @p2.unlocked.destroy
80
+ end
81
+
82
+ it 'should succeed when destroying the second without locking, ' +
83
+ 'then fail when destroying the third' do
84
+ @p2.unlocked.destroy
85
+ expect {
86
+ @p3.destroy
87
+ }.to raise_error(Mongoid::Errors::StaleDocument)
88
+ end
89
+
90
+ end
91
+
92
+ it 'should give a deprecation warning for #save_optimistic!' do
93
+ ::ActiveSupport::Deprecation.should_receive(:warn).once
94
+ @p1.save_optimistic!
95
+ end
96
+
97
+ it 'should give a deprecation warning for including Mongoid::Lockable' do
98
+ ::ActiveSupport::Deprecation.should_receive(:warn).once
99
+ Class.new do
100
+ include Mongoid::Document
101
+ include Mongoid::Lockable
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup
4
+
5
+ require 'mongoid'
6
+
7
+ Mongoid.configure do |config|
8
+ config.master = Mongo::Connection.new.db("mongoid_optimistic_locking_test")
9
+ end
10
+
11
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
12
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
13
+
14
+
15
+ require 'mongoid_optimistic_locking'
16
+ require 'rspec'
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid_optimistic_locking
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alon Burg
9
+ - John Nishinaga
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-05-31 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mongoid
17
+ requirement: &2161833600 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '2.4'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2161833600
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: &2161832880 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *2161832880
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec
39
+ requirement: &2161832180 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: '2.6'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *2161832180
48
+ - !ruby/object:Gem::Dependency
49
+ name: bson_ext
50
+ requirement: &2161831560 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: '1.5'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *2161831560
59
+ description: Allows optimisitic locking for Mongoid models. See https://github.com/burgalon/mongoid_optimistic_locking
60
+ email:
61
+ - burgalon@gmail.com
62
+ - jingoro@casa-z.org
63
+ executables: []
64
+ extensions: []
65
+ extra_rdoc_files: []
66
+ files:
67
+ - .gitignore
68
+ - .rspec
69
+ - .travis.yml
70
+ - Gemfile
71
+ - LICENSE
72
+ - README.md
73
+ - Rakefile
74
+ - lib/config/locales/en.yml
75
+ - lib/mongoid/errors/stale_document.rb
76
+ - lib/mongoid/lockable.rb
77
+ - lib/mongoid/optimistic_locking.rb
78
+ - lib/mongoid/optimistic_locking/deprecated.rb
79
+ - lib/mongoid/optimistic_locking/lock_version.rb
80
+ - lib/mongoid/optimistic_locking/operations.rb
81
+ - lib/mongoid/optimistic_locking/threaded_with_unlocked.rb
82
+ - lib/mongoid/optimistic_locking/unlocked.rb
83
+ - lib/mongoid/optimistic_locking/version.rb
84
+ - lib/mongoid_optimistic_locking.rb
85
+ - mongoid_optimistic_locking.gemspec
86
+ - spec/lockable_spec.rb
87
+ - spec/optimistic_locking_spec.rb
88
+ - spec/spec_helper.rb
89
+ homepage: https://github.com/burgalon/mongoid_optimistic_locking
90
+ licenses: []
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project: mongoid_optimistic_locking
109
+ rubygems_version: 1.8.10
110
+ signing_key:
111
+ specification_version: 3
112
+ summary: Allows optimisitic locking for Mongoid models
113
+ test_files:
114
+ - spec/lockable_spec.rb
115
+ - spec/optimistic_locking_spec.rb
116
+ - spec/spec_helper.rb