mongoid-locker 0.1.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,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - jruby-18mode # JRuby in 1.8 mode
7
+ - jruby-19mode # JRuby in 1.9 mode
8
+ - rbx-18mode
9
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,20 @@
1
+ source 'http://rubygems.org'
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem 'activesupport', '>= 2.3.5'
5
+
6
+ gem 'mongoid', '~> 2.4'
7
+
8
+ # Add dependencies to develop your gem here.
9
+ # Include everything needed to run rake, tests, features, etc.
10
+ group :development do
11
+ gem 'rspec', '~> 2.8'
12
+ gem 'bundler', '~> 1.1'
13
+ gem 'jeweler', '~> 1.8'
14
+
15
+ gem 'guard-rspec'
16
+ end
17
+
18
+ group :development, :test do
19
+ gem 'bson_ext', :platforms => :ruby
20
+ end
@@ -0,0 +1,10 @@
1
+ # More info at https://github.com/guard/guard#readme
2
+
3
+ guard 'rspec', :version => 2 do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+
6
+ watch('Gemfile') { "spec" }
7
+ watch('Gemfile.lock') { "spec" }
8
+ watch(%r{^lib/(.+)\.rb$}) { "spec" }
9
+ watch('spec/spec_helper.rb') { "spec" }
10
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Aidan Feldman
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,66 @@
1
+ # mongoid-locker [![Build Status](https://secure.travis-ci.org/afeld/mongoid-locker.png)](http://travis-ci.org/afeld/mongoid-locker)
2
+
3
+ Document-level locking for MongoDB via Mongoid. The need arose at [Jux](https://jux.com) from multiple processes on multiple servers trying to act upon the same document and stepping on each other's toes. Mongoid-Locker is an easy way to ensure only one process can perform a certain operation on a document at a time.
4
+
5
+ [Tested](http://travis-ci.org/afeld/mongoid-locker) against MRI 1.8.7, 1.9.2 and 1.9.3, Rubinius 1.8 and 1.9, and JRuby 1.8 and 1.9.
6
+
7
+ ## Usage
8
+
9
+ Add to your `Gemfile`:
10
+
11
+ ```ruby
12
+ gem 'mongoid-locker', '~> 0.1.0'
13
+ ```
14
+
15
+ and run `bundle install`. In the model you wish to lock, include `Mongoid::Locker` after `Mongoid::Document`. For example:
16
+
17
+ ```ruby
18
+ class QueueItem
19
+ include Mongoid::Document
20
+ include Mongoid::Locker
21
+
22
+ field :completed_at, :type => Time
23
+ end
24
+ ```
25
+
26
+ Then, execute any code you like in a block like so:
27
+
28
+ ```ruby
29
+ queue_item.with_lock do
30
+
31
+ # do stuff
32
+
33
+ queue_item.completed_at = Time.now
34
+ queue_item.save!
35
+ end
36
+ ```
37
+
38
+ `#with_lock` takes a couple options as a hash:
39
+
40
+ * `timeout`: The amount of time until a lock expires, in seconds. Defaults to `5`.
41
+ * `wait`: If a lock exists on the document, wait until that lock expires and try again. Defaults to `false`.
42
+
43
+ The default timeout can also be set on a per-class basis:
44
+
45
+ ```ruby
46
+ class QueueItem
47
+ # ...
48
+ timeout_lock_after 10
49
+ end
50
+ ```
51
+
52
+ Note that these locks are only enforced when using `#with_lock`, not at the database level. It is useful for transactional operations, where you can make atomic modification of the document with checks. For exmple, you could deduct a purchase from a user's balance... _unless_ they are broke.
53
+
54
+ More in-depth method documentation can be found at [rdoc.info](http://rdoc.info/github/afeld/mongoid-locker/frames). Enjoy!
55
+
56
+ ## Contributing
57
+
58
+ Pull requests are welcome. To run tests:
59
+
60
+ $ bundle install
61
+ $ rake
62
+
63
+ To auto-run tests as you code:
64
+
65
+ $ bundle install
66
+ $ guard
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "mongoid-locker"
18
+ gem.homepage = "http://github.com/afeld/mongoid-locker"
19
+ gem.license = "MIT"
20
+ gem.summary = "Document-level locking for MongoDB via Mongoid"
21
+ gem.description = %Q{Allows multiple processes to operate on individual documents in MongoDB while ensuring that only one can act at a time.}
22
+ gem.email = "aidan.feldman@gmail.com"
23
+ gem.authors = ["Aidan Feldman"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,2 @@
1
+ require 'mongoid'
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'mongoid', 'locker'))
@@ -0,0 +1,141 @@
1
+ module Mongoid
2
+ module Locker
3
+ module ClassMethods
4
+ # A scope to retrieve all locked documents in the collection.
5
+ #
6
+ # @return [Mongoid::Criteria]
7
+ def locked
8
+ where :locked_until.gt => Time.now
9
+ end
10
+
11
+ # A scope to retrieve all unlocked documents in the collection.
12
+ #
13
+ # @return [Mongoid::Criteria]
14
+ def unlocked
15
+ any_of({:locked_until => nil}, {:locked_until.lte => Time.now})
16
+ end
17
+
18
+ # Set the default lock timeout for this class. Note this only applies to new locks. Defaults to five seconds.
19
+ #
20
+ # @param [Fixnum] new_time the default number of seconds until a lock is considered "expired", in seconds
21
+ # @return [void]
22
+ def timeout_lock_after new_time
23
+ @lock_timeout = new_time
24
+ end
25
+
26
+ # Retrieve the lock timeout default for this class.
27
+ #
28
+ # @return [Fixnum] the default number of seconds until a lock is considered "expired", in seconds
29
+ def lock_timeout
30
+ @lock_timeout
31
+ end
32
+ end
33
+
34
+ # @api private
35
+ def self.included mod
36
+ mod.extend ClassMethods
37
+
38
+ mod.field :locked_at, :type => Time
39
+ mod.field :locked_until, :type => Time
40
+
41
+ # default timeout of five seconds
42
+ mod.instance_variable_set :@lock_timeout, 5
43
+ end
44
+
45
+
46
+ # Returns whether the document is currently locked or not.
47
+ #
48
+ # @return [Boolean] true if locked, false otherwise
49
+ def locked?
50
+ self.locked_until && self.locked_until > Time.now
51
+ end
52
+
53
+ # Primary method of plugin: execute the provided code once the document has been successfully locked.
54
+ #
55
+ # @param [Hash] opts for the locking mechanism
56
+ # @option opts [Fixnum] :timeout The number of seconds until the lock is considered "expired" - defaults to the {ClassMethods#lock_timeout}
57
+ # @option opts [Boolean] :wait If the document is currently locked, wait until the lock expires and try again
58
+ # @return [void]
59
+ def with_lock opts={}, &block
60
+ self.lock opts
61
+ begin
62
+ yield
63
+ ensure
64
+ self.unlock
65
+ end
66
+ end
67
+
68
+
69
+ protected
70
+
71
+ def lock opts={}
72
+ coll = self.class.collection
73
+ time = Time.now
74
+ timeout = opts[:timeout] || self.class.lock_timeout
75
+ expiration = time + timeout
76
+
77
+ # lock the document atomically in the DB without persisting entire doc
78
+ record = coll.find_and_modify(
79
+ :query => {
80
+ :_id => self.id,
81
+ '$or' => [
82
+ # not locked
83
+ {:locked_until => nil},
84
+ # expired
85
+ {:locked_until => {'$lte' => time}}
86
+ ]
87
+ },
88
+ :update => {
89
+ '$set' => {
90
+ :locked_at => time,
91
+ :locked_until => expiration
92
+ }
93
+ }
94
+ )
95
+
96
+ if record
97
+ # lock successful
98
+ self.locked_at = time
99
+ self.locked_until = expiration
100
+ else
101
+ # couldn't grab lock
102
+
103
+ existing_query = {
104
+ :_id => self.id,
105
+ :locked_until => {'$exists' => true}
106
+ }
107
+
108
+ if opts[:wait] && existing = coll.find(existing_query, :limit => 1).first
109
+ # doc is locked - wait until it expires
110
+ wait_time = existing.locked_until - Time.now
111
+ sleep wait_time if wait_time > 0
112
+
113
+ # only wait once
114
+ opts.dup
115
+ opts.delete :wait
116
+
117
+ # retry lock grab
118
+ self.lock opts
119
+ else
120
+ raise LockError.new("could not get lock")
121
+ end
122
+ end
123
+ end
124
+
125
+ def unlock
126
+ # unlock the document in the DB without persisting entire doc
127
+ self.class.collection.update({:_id => self.id}, {
128
+ '$set' => {
129
+ :locked_at => nil,
130
+ :locked_until => nil,
131
+ }
132
+ }, {:safe => true})
133
+
134
+ self.locked_at = nil
135
+ self.locked_until = nil
136
+ end
137
+ end
138
+
139
+ # Error thrown if document could not be successfully locked.
140
+ class LockError < Exception; end
141
+ end
@@ -0,0 +1,69 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "mongoid-locker"
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Aidan Feldman"]
12
+ s.date = "2012-07-03"
13
+ s.description = "Allows multiple processes to operate on individual documents in MongoDB while ensuring that only one can act at a time."
14
+ s.email = "aidan.feldman@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ ".travis.yml",
23
+ "Gemfile",
24
+ "Guardfile",
25
+ "LICENSE.txt",
26
+ "README.md",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "lib/mongoid-locker.rb",
30
+ "lib/mongoid/locker.rb",
31
+ "mongoid-locker.gemspec",
32
+ "spec/database.yml",
33
+ "spec/mongoid-locker_spec.rb",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = "http://github.com/afeld/mongoid-locker"
37
+ s.licenses = ["MIT"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = "1.8.24"
40
+ s.summary = "Document-level locking for MongoDB via Mongoid"
41
+
42
+ if s.respond_to? :specification_version then
43
+ s.specification_version = 3
44
+
45
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
+ s.add_runtime_dependency(%q<mongoid>, ["~> 2.4"])
47
+ s.add_development_dependency(%q<rspec>, ["~> 2.8"])
48
+ s.add_development_dependency(%q<bundler>, ["~> 1.1"])
49
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8"])
50
+ s.add_development_dependency(%q<guard-rspec>, [">= 0"])
51
+ s.add_development_dependency(%q<bson_ext>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<mongoid>, ["~> 2.4"])
54
+ s.add_dependency(%q<rspec>, ["~> 2.8"])
55
+ s.add_dependency(%q<bundler>, ["~> 1.1"])
56
+ s.add_dependency(%q<jeweler>, ["~> 1.8"])
57
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
58
+ s.add_dependency(%q<bson_ext>, [">= 0"])
59
+ end
60
+ else
61
+ s.add_dependency(%q<mongoid>, ["~> 2.4"])
62
+ s.add_dependency(%q<rspec>, ["~> 2.8"])
63
+ s.add_dependency(%q<bundler>, ["~> 1.1"])
64
+ s.add_dependency(%q<jeweler>, ["~> 1.8"])
65
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
66
+ s.add_dependency(%q<bson_ext>, [">= 0"])
67
+ end
68
+ end
69
+
@@ -0,0 +1,3 @@
1
+ test:
2
+ host: localhost
3
+ database: mongoid_locker_test
@@ -0,0 +1,159 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Mongoid::Locker do
4
+ def remove_class klass
5
+ Object.send :remove_const, klass.to_s.to_sym
6
+ end
7
+
8
+ before do
9
+ # recreate the class for each spec
10
+ class User
11
+ include Mongoid::Document
12
+ include Mongoid::Locker
13
+
14
+ field :account_balance, :type => Integer # easier to test than Float
15
+ end
16
+
17
+ @user = User.create!
18
+ end
19
+
20
+ after do
21
+ User.delete_all
22
+ remove_class User
23
+ end
24
+
25
+
26
+ describe "#locked?" do
27
+ it "shouldn't be locked when created" do
28
+ @user.should_not be_locked
29
+ end
30
+
31
+ it "should respect the expiration" do
32
+ User.timeout_lock_after 1
33
+
34
+ @user.with_lock do
35
+ sleep 2
36
+ @user.should_not be_locked
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#with_lock" do
42
+ it "should lock and unlock the user" do
43
+ @user.with_lock do
44
+ @user.should be_locked
45
+ User.first.should be_locked
46
+ end
47
+
48
+ @user.should_not be_locked
49
+ @user.reload.should_not be_locked
50
+ end
51
+
52
+ it "shouldn't save the full document" do
53
+ @user.with_lock do
54
+ @user.account_balance = 10
55
+ end
56
+
57
+ @user.account_balance.should eq(10)
58
+ User.first.account_balance.should be_nil
59
+ end
60
+
61
+ it "should handle errors gracefully" do
62
+ expect {
63
+ @user.with_lock do
64
+ raise "booyah!"
65
+ end
66
+ }.to raise_error
67
+
68
+ @user.reload.should_not be_locked
69
+ end
70
+
71
+ it "should complain if trying to lock locked doc" do
72
+ @user.with_lock do
73
+ user_dup = User.first
74
+
75
+ expect {
76
+ user_dup.with_lock do
77
+ fail "shouldn't get the lock"
78
+ end
79
+ }.to raise_error(Mongoid::LockError)
80
+ end
81
+ end
82
+
83
+ it "should wait until the lock times out, if desired" do
84
+ User.timeout_lock_after 1
85
+
86
+ @user.with_lock do
87
+ user_dup = User.first
88
+
89
+ user_dup.with_lock :wait => true do
90
+ user_dup.account_balance = 10
91
+ user_dup.save!
92
+ end
93
+ end
94
+
95
+ @user.reload.account_balance.should eq(10)
96
+ end
97
+
98
+ it "should override the default timeout" do
99
+ User.timeout_lock_after 1
100
+
101
+ expiration = (Time.now + 3).to_i
102
+ @user.with_lock :timeout => 3 do
103
+ @user.locked_until.to_i.should eq(expiration)
104
+ end
105
+ end
106
+ end
107
+
108
+ describe ".timeout_lock_after" do
109
+ it "should ignore the lock if it has timed out" do
110
+ User.timeout_lock_after 1
111
+
112
+ @user.with_lock do
113
+ user_dup = User.first
114
+ sleep 2
115
+
116
+ user_dup.with_lock do
117
+ user_dup.account_balance = 10
118
+ user_dup.save!
119
+ end
120
+ end
121
+
122
+ @user.reload.account_balance.should eq(10)
123
+ end
124
+
125
+ it "should be independent for different classes" do
126
+ class Account
127
+ include Mongoid::Document
128
+ include Mongoid::Locker
129
+ end
130
+
131
+ User.timeout_lock_after 1
132
+ Account.timeout_lock_after 2
133
+
134
+ User.lock_timeout.should eq(1)
135
+
136
+ remove_class Account
137
+ end
138
+ end
139
+
140
+ describe ".locked" do
141
+ it "should return the locked documents" do
142
+ user2 = User.create!
143
+
144
+ @user.with_lock do
145
+ User.locked.to_a.should eq([@user])
146
+ end
147
+ end
148
+ end
149
+
150
+ describe ".unlocked" do
151
+ it "should return the unlocked documents" do
152
+ user2 = User.create!
153
+
154
+ @user.with_lock do
155
+ User.unlocked.to_a.should eq([user2])
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'mongoid-locker'
5
+
6
+ ENV['RACK_ENV'] = 'test'
7
+
8
+ # Requires supporting files with custom matchers and macros, etc,
9
+ # in ./support/ and its subdirectories.
10
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
+
12
+ RSpec.configure do |config|
13
+ Mongoid.load! File.join(File.dirname(__FILE__), 'database.yml')
14
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid-locker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Aidan Feldman
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mongoid
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.4'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.4'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2.8'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2.8'
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '1.1'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ - !ruby/object:Gem::Dependency
63
+ name: jeweler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.8'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '1.8'
78
+ - !ruby/object:Gem::Dependency
79
+ name: guard-rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: bson_ext
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Allows multiple processes to operate on individual documents in MongoDB
111
+ while ensuring that only one can act at a time.
112
+ email: aidan.feldman@gmail.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files:
116
+ - LICENSE.txt
117
+ - README.md
118
+ files:
119
+ - .document
120
+ - .rspec
121
+ - .travis.yml
122
+ - Gemfile
123
+ - Guardfile
124
+ - LICENSE.txt
125
+ - README.md
126
+ - Rakefile
127
+ - VERSION
128
+ - lib/mongoid-locker.rb
129
+ - lib/mongoid/locker.rb
130
+ - mongoid-locker.gemspec
131
+ - spec/database.yml
132
+ - spec/mongoid-locker_spec.rb
133
+ - spec/spec_helper.rb
134
+ homepage: http://github.com/afeld/mongoid-locker
135
+ licenses:
136
+ - MIT
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ segments:
148
+ - 0
149
+ hash: 2896270749272846608
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ none: false
152
+ requirements:
153
+ - - ! '>='
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubyforge_project:
158
+ rubygems_version: 1.8.24
159
+ signing_key:
160
+ specification_version: 3
161
+ summary: Document-level locking for MongoDB via Mongoid
162
+ test_files: []