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 CHANGED
@@ -1 +1 @@
1
- 0.2.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
+
@@ -1,10 +1,13 @@
1
1
  module ExpirableLocking
2
2
 
3
3
  def self.extended(base)
4
- base.named_scope :unlocked, lambda {
5
- { :conditions => [ "locked_at IS NULL OR locked_at < ?", base.lock_duration.ago ] }
6
- }
7
- base.send(:include, InstanceMethods)
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
- 1 == update_all({ :locked_at => nil }, { :id => record, :locked_at => record.locked_at })
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
- locked_at = default_timezone == :utc ? Time.now.utc : Time.now
39
- result = update_all({ :locked_at => locked_at }, { :id => record })
50
+ new_attributes = lock_attributes
51
+ result = update_all(new_attributes, { :id => record })
40
52
 
41
53
  if result == 1
42
- record.write_attribute_without_dirty(:locked_at, locked_at)
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
-
@@ -24,6 +24,7 @@ ActiveRecord::Schema.define do
24
24
  table.timestamps
25
25
 
26
26
  table.datetime :locked_at
27
+ table.string :locked_by
27
28
  end
28
29
 
29
30
  end
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: 23
5
- prerelease: false
4
+ hash: 19
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 0.2.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: 2010-08-24 00:00:00 -07:00
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.3.7
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.