expirable_locking 0.2.0 → 0.3.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.
- data/VERSION +1 -1
- data/expirable_locking.gemspec +50 -0
- data/lib/expirable_locking.rb +41 -8
- data/test/expirable_locking_test.rb +24 -1
- data/test/helper.rb +1 -0
- metadata +7 -6
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{expirable_locking}
|
8
|
+
s.version = "0.3.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Eric Chapweske"]
|
12
|
+
s.date = %q{2011-03-21}
|
13
|
+
s.description = %q{A tiny ActiveRecord extension for expirable locking.}
|
14
|
+
s.email = %q{eac@zendesk.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"expirable_locking.gemspec",
|
27
|
+
"lib/expirable_locking.rb",
|
28
|
+
"test/expirable_locking_test.rb",
|
29
|
+
"test/helper.rb"
|
30
|
+
]
|
31
|
+
s.homepage = %q{http://github.com/eac/expirable_locking}
|
32
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = %q{1.5.2}
|
35
|
+
s.summary = %q{A tiny ActiveRecord extension for expirable locking.}
|
36
|
+
s.test_files = [
|
37
|
+
"test/expirable_locking_test.rb",
|
38
|
+
"test/helper.rb"
|
39
|
+
]
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
s.specification_version = 3
|
43
|
+
|
44
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
45
|
+
else
|
46
|
+
end
|
47
|
+
else
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
data/lib/expirable_locking.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
module ExpirableLocking
|
2
2
|
|
3
3
|
def self.extended(base)
|
4
|
-
base.
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
base.class_eval do
|
5
|
+
named_scope :unlocked, lambda {
|
6
|
+
{ :conditions => [ "locked_at IS NULL OR locked_at < ?", base.lock_duration.ago ] }
|
7
|
+
}
|
8
|
+
|
9
|
+
include InstanceMethods
|
10
|
+
end
|
8
11
|
end
|
9
12
|
|
10
13
|
module InstanceMethods
|
@@ -30,20 +33,50 @@ module ExpirableLocking
|
|
30
33
|
def unlock(record)
|
31
34
|
return true if record.destroyed?
|
32
35
|
|
33
|
-
|
36
|
+
new_attributes = unlock_attributes
|
37
|
+
if result = (1 == update_all(new_attributes, { :id => record, :locked_at => record.locked_at }))
|
38
|
+
|
39
|
+
new_attributes.each do |key, value|
|
40
|
+
record.write_attribute_without_dirty(key, value)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
result
|
34
46
|
end
|
35
47
|
|
36
48
|
# Updates lock timestamp without triggering validations/callbacks.
|
37
49
|
def touch_lock(record)
|
38
|
-
|
39
|
-
result
|
50
|
+
new_attributes = lock_attributes
|
51
|
+
result = update_all(new_attributes, { :id => record })
|
40
52
|
|
41
53
|
if result == 1
|
42
|
-
|
54
|
+
new_attributes.each do |key, value|
|
55
|
+
record.write_attribute_without_dirty(key, value)
|
56
|
+
end
|
43
57
|
end
|
44
58
|
|
45
59
|
result
|
46
60
|
end
|
47
61
|
|
62
|
+
def unlock_attributes
|
63
|
+
lock_attributes.tap do |attributes|
|
64
|
+
attributes.keys.each { |key| attributes[key] = nil }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def lock_attributes
|
69
|
+
locked_at = default_timezone == :utc ? Time.now.utc : Time.now
|
70
|
+
|
71
|
+
Hash.new.tap do |attributes|
|
72
|
+
attributes[:locked_at] = locked_at
|
73
|
+
attributes[:locked_by] = lock_name if method_defined?(:locked_by)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def lock_name
|
78
|
+
"#{`hostname`.chomp}:#{Process.pid}"
|
79
|
+
end
|
80
|
+
|
48
81
|
end
|
49
82
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'helper'
|
2
|
+
require 'socket'
|
2
3
|
|
3
4
|
class ExpirableLockingTest < ActiveRecord::TestCase
|
4
5
|
|
@@ -51,6 +52,27 @@ class ExpirableLockingTest < ActiveRecord::TestCase
|
|
51
52
|
assert_equal true, @record.lock_with_expiry
|
52
53
|
end
|
53
54
|
|
55
|
+
should "add the name of the locking process" do
|
56
|
+
assert_equal nil, @record.locked_by
|
57
|
+
@model.stubs(:lock_name).returns('host.example:1234')
|
58
|
+
assert @record.lock_with_expiry
|
59
|
+
@record.reload
|
60
|
+
|
61
|
+
assert_equal 'host.example:1234', @record.locked_by
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
context "lock_name" do
|
67
|
+
|
68
|
+
should "include the host name" do
|
69
|
+
assert_match Socket.gethostname, @model.lock_name
|
70
|
+
end
|
71
|
+
|
72
|
+
should "include the pid" do
|
73
|
+
assert_match Process.pid.to_s, @model.lock_name
|
74
|
+
end
|
75
|
+
|
54
76
|
end
|
55
77
|
|
56
78
|
context "unlocking" do
|
@@ -82,6 +104,8 @@ class ExpirableLockingTest < ActiveRecord::TestCase
|
|
82
104
|
@record.unlock
|
83
105
|
|
84
106
|
assert @model.unlocked.include?(@record)
|
107
|
+
assert_equal nil, @record.locked_at
|
108
|
+
assert_equal nil, @record.locked_by
|
85
109
|
end
|
86
110
|
|
87
111
|
end
|
@@ -102,4 +126,3 @@ class ExpirableLockingTest < ActiveRecord::TestCase
|
|
102
126
|
end
|
103
127
|
|
104
128
|
end
|
105
|
-
|
data/test/helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: expirable_locking
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Eric Chapweske
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-03-21 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- README.rdoc
|
36
36
|
- Rakefile
|
37
37
|
- VERSION
|
38
|
+
- expirable_locking.gemspec
|
38
39
|
- lib/expirable_locking.rb
|
39
40
|
- test/expirable_locking_test.rb
|
40
41
|
- test/helper.rb
|
@@ -68,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
68
69
|
requirements: []
|
69
70
|
|
70
71
|
rubyforge_project:
|
71
|
-
rubygems_version: 1.
|
72
|
+
rubygems_version: 1.5.2
|
72
73
|
signing_key:
|
73
74
|
specification_version: 3
|
74
75
|
summary: A tiny ActiveRecord extension for expirable locking.
|